From 9f1f77a6e3516f374beca8c6dc4ef9bc60eaec1d Mon Sep 17 00:00:00 2001 From: Josef Nilsen Date: Thu, 30 Jun 2022 10:11:48 +0200 Subject: [PATCH 1/8] Fixes for polar projection --- lib/src/layer/circle_layer.dart | 14 +++++--------- lib/src/layer/overlay_image_layer.dart | 24 +++++++++++------------- lib/src/layer/polygon_layer.dart | 8 +++----- lib/src/layer/polyline_layer.dart | 8 +++----- lib/src/map/map.dart | 5 +++++ 5 files changed, 27 insertions(+), 32 deletions(-) diff --git a/lib/src/layer/circle_layer.dart b/lib/src/layer/circle_layer.dart index 9ab7b11c5..f3b3b3303 100644 --- a/lib/src/layer/circle_layer.dart +++ b/lib/src/layer/circle_layer.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/widgets.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/src/map/map.dart'; @@ -66,18 +68,12 @@ class CircleLayer extends StatelessWidget { builder: (BuildContext context, _) { final circleWidgets = []; for (final circle in circleOpts.circles) { - var pos = map.project(circle.point); - pos = pos.multiplyBy(map.getZoomScale(map.zoom, map.zoom)) - - map.getPixelOrigin(); - circle.offset = Offset(pos.x.toDouble(), pos.y.toDouble()); + circle.offset = map.getOffset(circle.point); if (circle.useRadiusInMeter) { final r = const Distance().offset(circle.point, circle.radius, 180); - var rpos = map.project(r); - rpos = rpos.multiplyBy(map.getZoomScale(map.zoom, map.zoom)) - - map.getPixelOrigin(); - - circle.realRadius = rpos.y - pos.y; + final delta = circle.offset - map.getOffset(r); + circle.realRadius = delta.distance; } circleWidgets.add( diff --git a/lib/src/layer/overlay_image_layer.dart b/lib/src/layer/overlay_image_layer.dart index 8df75667c..5bfd53b17 100644 --- a/lib/src/layer/overlay_image_layer.dart +++ b/lib/src/layer/overlay_image_layer.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/src/map/map.dart'; +import 'package:flutter_map/src/core/bounds.dart'; class OverlayImageLayerOptions extends LayerOptions { final List overlayImages; @@ -67,20 +68,17 @@ class OverlayImageLayer extends StatelessWidget { } Positioned _positionedForOverlay(OverlayImage overlayImage) { - final zoomScale = - map.getZoomScale(map.zoom, map.zoom); // TODO replace with 1? - final pixelOrigin = map.getPixelOrigin(); - final upperLeftPixel = - map.project(overlayImage.bounds.northWest).multiplyBy(zoomScale) - - pixelOrigin; - final bottomRightPixel = - map.project(overlayImage.bounds.southEast).multiplyBy(zoomScale) - - pixelOrigin; + // northWest is not necessarily upperLeft depending on projection + final bounds = Bounds( + map.project(overlayImage.bounds.northWest) - map.getPixelOrigin(), + map.project(overlayImage.bounds.southEast) - map.getPixelOrigin(), + ); + return Positioned( - left: upperLeftPixel.x.toDouble(), - top: upperLeftPixel.y.toDouble(), - width: (bottomRightPixel.x - upperLeftPixel.x).toDouble(), - height: (bottomRightPixel.y - upperLeftPixel.y).toDouble(), + left: bounds.topLeft.x.toDouble(), + top: bounds.topLeft.y.toDouble(), + width: bounds.size.x.toDouble(), + height: bounds.size.y.toDouble(), child: Image( image: overlayImage.imageProvider, fit: BoxFit.fill, diff --git a/lib/src/layer/polygon_layer.dart b/lib/src/layer/polygon_layer.dart index 4a70a0085..4c556d89e 100644 --- a/lib/src/layer/polygon_layer.dart +++ b/lib/src/layer/polygon_layer.dart @@ -144,12 +144,10 @@ class PolygonLayer extends StatelessWidget { for (var i = 0; i < len; ++i) { final point = points[i]; - var pos = map.project(point); - pos = pos.multiplyBy(map.getZoomScale(map.zoom, map.zoom)) - - map.getPixelOrigin(); - offsets.add(Offset(pos.x.toDouble(), pos.y.toDouble())); + final offset = map.getOffset(point); + offsets.add(offset); if (i > 0) { - offsets.add(Offset(pos.x.toDouble(), pos.y.toDouble())); + offsets.add(offset); } } } diff --git a/lib/src/layer/polyline_layer.dart b/lib/src/layer/polyline_layer.dart index 27631f7f6..4ea4f011f 100644 --- a/lib/src/layer/polyline_layer.dart +++ b/lib/src/layer/polyline_layer.dart @@ -131,12 +131,10 @@ class PolylineLayer extends StatelessWidget { for (var i = 0; i < len; ++i) { final point = points[i]; - var pos = map.project(point); - pos = pos.multiplyBy(map.getZoomScale(map.zoom, map.zoom)) - - map.getPixelOrigin(); - offsets.add(Offset(pos.x.toDouble(), pos.y.toDouble())); + final offset = map.getOffset(point); + offsets.add(offset); if (i > 0) { - offsets.add(Offset(pos.x.toDouble(), pos.y.toDouble())); + offsets.add(offset); } } } diff --git a/lib/src/map/map.dart b/lib/src/map/map.dart index d57d4314e..3be454c66 100644 --- a/lib/src/map/map.dart +++ b/lib/src/map/map.dart @@ -567,6 +567,11 @@ class MapState { return _pixelOrigin; } + Offset getOffset(LatLng pos) { + final delta = project(pos) - getPixelOrigin(); + return Offset(delta.x.toDouble(), delta.y.toDouble()); + } + CustomPoint getNewPixelOrigin(LatLng center, [double? zoom]) { final viewHalf = size / 2.0; return (project(center, zoom) - viewHalf).round(); From a7fc581aa09f9628d86a4cf42b419ada2ee17957 Mon Sep 17 00:00:00 2001 From: Josef Nilsen Date: Thu, 30 Jun 2022 13:04:27 +0200 Subject: [PATCH 2/8] Rename getOffset to getOffsetFromOrigin --- lib/src/layer/circle_layer.dart | 4 ++-- lib/src/layer/polygon_layer.dart | 2 +- lib/src/layer/polyline_layer.dart | 2 +- lib/src/map/map.dart | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/src/layer/circle_layer.dart b/lib/src/layer/circle_layer.dart index f3b3b3303..76cde91ec 100644 --- a/lib/src/layer/circle_layer.dart +++ b/lib/src/layer/circle_layer.dart @@ -68,11 +68,11 @@ class CircleLayer extends StatelessWidget { builder: (BuildContext context, _) { final circleWidgets = []; for (final circle in circleOpts.circles) { - circle.offset = map.getOffset(circle.point); + circle.offset = map.getOffsetFromOrigin(circle.point); if (circle.useRadiusInMeter) { final r = const Distance().offset(circle.point, circle.radius, 180); - final delta = circle.offset - map.getOffset(r); + final delta = circle.offset - map.getOffsetFromOrigin(r); circle.realRadius = delta.distance; } diff --git a/lib/src/layer/polygon_layer.dart b/lib/src/layer/polygon_layer.dart index 4c556d89e..581805d9c 100644 --- a/lib/src/layer/polygon_layer.dart +++ b/lib/src/layer/polygon_layer.dart @@ -144,7 +144,7 @@ class PolygonLayer extends StatelessWidget { for (var i = 0; i < len; ++i) { final point = points[i]; - final offset = map.getOffset(point); + final offset = map.getOffsetFromOrigin(point); offsets.add(offset); if (i > 0) { offsets.add(offset); diff --git a/lib/src/layer/polyline_layer.dart b/lib/src/layer/polyline_layer.dart index 4ea4f011f..18bc1b65c 100644 --- a/lib/src/layer/polyline_layer.dart +++ b/lib/src/layer/polyline_layer.dart @@ -131,7 +131,7 @@ class PolylineLayer extends StatelessWidget { for (var i = 0; i < len; ++i) { final point = points[i]; - final offset = map.getOffset(point); + final offset = map.getOffsetFromOrigin(point); offsets.add(offset); if (i > 0) { offsets.add(offset); diff --git a/lib/src/map/map.dart b/lib/src/map/map.dart index 3be454c66..ea5b9b390 100644 --- a/lib/src/map/map.dart +++ b/lib/src/map/map.dart @@ -567,7 +567,7 @@ class MapState { return _pixelOrigin; } - Offset getOffset(LatLng pos) { + Offset getOffsetFromOrigin(LatLng pos) { final delta = project(pos) - getPixelOrigin(); return Offset(delta.x.toDouble(), delta.y.toDouble()); } From 382b922b3d54f612963e2d14af743cbcf84965dd Mon Sep 17 00:00:00 2001 From: Josef Nilsen Date: Thu, 30 Jun 2022 14:56:21 +0200 Subject: [PATCH 3/8] Remove redundant offsets in _fillOffsets() --- lib/src/layer/polygon_layer.dart | 4 ---- lib/src/layer/polyline_layer.dart | 4 ---- 2 files changed, 8 deletions(-) diff --git a/lib/src/layer/polygon_layer.dart b/lib/src/layer/polygon_layer.dart index 581805d9c..022efde19 100644 --- a/lib/src/layer/polygon_layer.dart +++ b/lib/src/layer/polygon_layer.dart @@ -143,12 +143,8 @@ class PolygonLayer extends StatelessWidget { final len = points.length; for (var i = 0; i < len; ++i) { final point = points[i]; - final offset = map.getOffsetFromOrigin(point); offsets.add(offset); - if (i > 0) { - offsets.add(offset); - } } } } diff --git a/lib/src/layer/polyline_layer.dart b/lib/src/layer/polyline_layer.dart index 18bc1b65c..57571f381 100644 --- a/lib/src/layer/polyline_layer.dart +++ b/lib/src/layer/polyline_layer.dart @@ -130,12 +130,8 @@ class PolylineLayer extends StatelessWidget { final len = points.length; for (var i = 0; i < len; ++i) { final point = points[i]; - final offset = map.getOffsetFromOrigin(point); offsets.add(offset); - if (i > 0) { - offsets.add(offset); - } } } } From e98cf8bed46c09421e484f97557886daa820a34e Mon Sep 17 00:00:00 2001 From: Josef Nilsen Date: Sat, 2 Jul 2022 00:51:44 +0200 Subject: [PATCH 4/8] Remove unused import --- lib/src/layer/circle_layer.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/src/layer/circle_layer.dart b/lib/src/layer/circle_layer.dart index 76cde91ec..bf790980f 100644 --- a/lib/src/layer/circle_layer.dart +++ b/lib/src/layer/circle_layer.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:flutter/widgets.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/src/map/map.dart'; From 0312b909945da6b08ba2b33d293631a191c3664b Mon Sep 17 00:00:00 2001 From: Josef Nilsen Date: Mon, 11 Jul 2022 20:20:27 +0200 Subject: [PATCH 5/8] Add EPSG:3413 CRS example page --- example/lib/main.dart | 2 + example/lib/pages/epsg3413_crs.dart | 136 ++++++++++++++++++++++++++++ example/lib/widgets/drawer.dart | 10 +- 3 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 example/lib/pages/epsg3413_crs.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 961652307..5e874f338 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -33,6 +33,7 @@ import './pages/tile_builder_example.dart'; import './pages/tile_loading_error_handle.dart'; import './pages/widgets.dart'; import './pages/wms_tile_layer.dart'; +import './pages/epsg3413_crs.dart'; void main() => runApp(const MyApp()); @@ -82,6 +83,7 @@ class MyApp extends StatelessWidget { MapInsideListViewPage.route: (context) => const MapInsideListViewPage(), ResetTileLayerPage.route: (context) => const ResetTileLayerPage(), EPSG4326Page.route: (context) => const EPSG4326Page(), + EPSG3413Page.route: (context) => const EPSG3413Page(), MaxBoundsPage.route: (context) => const MaxBoundsPage(), PointToLatLngPage.route: (context) => const PointToLatLngPage(), }, diff --git a/example/lib/pages/epsg3413_crs.dart b/example/lib/pages/epsg3413_crs.dart new file mode 100644 index 000000000..916f397a2 --- /dev/null +++ b/example/lib/pages/epsg3413_crs.dart @@ -0,0 +1,136 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_map/plugin_api.dart'; +import 'package:latlong2/latlong.dart'; +import 'package:proj4dart/proj4dart.dart' as proj4; + +import '../../widgets/drawer.dart'; + +class EPSG3413Page extends StatefulWidget { + static const String route = 'EPSG3413 Page'; + + const EPSG3413Page({Key? key}) : super(key: key); + + @override + _EPSG3413PageState createState() => _EPSG3413PageState(); +} + +class _EPSG3413PageState extends State { + late final Proj4Crs epsg3413CRS; + + double? maxZoom; + + // Define start center + proj4.Point point = proj4.Point(x: 90, y: 0); + + String initText = 'Map centered to'; + + late final proj4.Projection epsg4326; + + late final proj4.Projection epsg3413; + + @override + void initState() { + super.initState(); + + epsg4326 = proj4.Projection.get('EPSG:4326')!; + + // EPSG:3413 is a user-defined projection from a valid Proj4 definition string + // From: http://epsg.io/3413, proj definition: http://epsg.io/3413.proj4 + // Find Projection by name or define it if not exists + epsg3413 = proj4.Projection.get('EPSG:3413') ?? + proj4.Projection.add('EPSG:3413', + '+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs'); + + // 9 example zoom level resolutions + final resolutions = [ + 32768, + 16384, + 8192, + 4096, + 2048, + 1024, + 512, + 256, + 128, + ]; + + final epsg3413Bounds = Bounds( + const CustomPoint(-4511619.0, -4511336.0), + const CustomPoint(4510883.0, 4510996.0), + ); + + maxZoom = (resolutions.length - 1).toDouble(); + + epsg3413CRS = Proj4Crs.fromFactory( + code: 'EPSG:3413', + proj4Projection: epsg3413, + resolutions: resolutions, + bounds: epsg3413Bounds, + origins: [const CustomPoint(0, 0)], + scales: null, + transformation: null, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('EPSG:4326 CRS')), + drawer: buildDrawer(context, EPSG3413Page.route), + body: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: [ + const Padding( + padding: EdgeInsets.only(top: 8.0, bottom: 2.0), + child: Text( + 'This map is in EPSG:3413', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.blue, + fontSize: 16.0, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0, bottom: 2.0), + child: Text( + '$initText (${point.x.toStringAsFixed(5)}, ${point.y.toStringAsFixed(5)}) in EPSG:4326.', + ), + ), + Padding( + padding: const EdgeInsets.only(top: 2.0, bottom: 2.0), + child: Text( + 'Which is (${epsg4326.transform(epsg3413, point).x.toStringAsFixed(2)}, ${epsg4326.transform(epsg3413, point).y.toStringAsFixed(2)}) in EPSG:3413.', + ), + ), + Flexible( + child: FlutterMap( + options: MapOptions( + crs: epsg3413CRS, + center: LatLng(point.x, point.y), + zoom: 3.0, + maxZoom: maxZoom, + ), + layers: [ + TileLayerOptions( + opacity: 1, + backgroundColor: Colors.transparent, + wmsOptions: WMSTileLayerOptions( + crs: epsg3413CRS, + transparent: true, + format: 'image/jpeg', + baseUrl: + 'https://www.gebco.net/data_and_products/gebco_web_services/north_polar_view_wms/mapserv?', + layers: ['gebco_north_polar_view'], + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/example/lib/widgets/drawer.dart b/example/lib/widgets/drawer.dart index be7c38e74..e2c5925df 100644 --- a/example/lib/widgets/drawer.dart +++ b/example/lib/widgets/drawer.dart @@ -8,6 +8,7 @@ import 'package:flutter_map_example/pages/point_to_latlng.dart'; import '../pages/animated_map_controller.dart'; import '../pages/circle.dart'; import '../pages/custom_crs/custom_crs.dart'; +import '../pages/epsg3413_crs.dart'; import '../pages/esri.dart'; import '../pages/home.dart'; import '../pages/interactive_test_page.dart'; @@ -237,12 +238,19 @@ Drawer buildDrawer(BuildContext context, String currentRoute) { }, ), ListTile( - title: const Text('EPSG4326 Crs'), + title: const Text('EPSG4326 CRS'), selected: currentRoute == EPSG4326Page.route, onTap: () { Navigator.pushReplacementNamed(context, EPSG4326Page.route); }, ), + ListTile( + title: const Text('EPSG3413 CRS'), + selected: currentRoute == EPSG3413Page.route, + onTap: () { + Navigator.pushReplacementNamed(context, EPSG3413Page.route); + }, + ), _buildMenuItem( context, const Text('Stateful markers'), From 2772595d3b25eca0677ee6f04e4f3739bb6f4a1b Mon Sep 17 00:00:00 2001 From: Josef Nilsen Date: Tue, 12 Jul 2022 00:07:46 +0200 Subject: [PATCH 6/8] Add circle & overlay image layers to EPSG:3413 example --- example/assets/map/epsg3413/amsr2.png | Bin 0 -> 53134 bytes example/lib/pages/epsg3413_crs.dart | 75 +++++++++++++++---------- example/pubspec.yaml | 1 + lib/src/layer/overlay_image_layer.dart | 2 +- 4 files changed, 48 insertions(+), 30 deletions(-) create mode 100644 example/assets/map/epsg3413/amsr2.png diff --git a/example/assets/map/epsg3413/amsr2.png b/example/assets/map/epsg3413/amsr2.png new file mode 100644 index 0000000000000000000000000000000000000000..ad24c5e91c9f1b60c7fbd0eec7ab93cb2a9ace0f GIT binary patch literal 53134 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 IC;JlFj7-Ge*#O72#}g8xP&R^M}y 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
    IFPxINSI%pOF~*`_~fU6u~}qmkUtEIv&(=ir=H zn$lq>0W&P>NeUP&qlF2mZ|pQ-zF)w-SxL^tYwR#&c4}))b@$c#74DuyLWMz`6Mmc-8n3hf27y_gB_9RLDj$;RdCuPa`Rl55yzReQbGX%MGpDFHMy0)A zsTF4Cdm!sW-^F$VfH*_UsBgF1GivryJ^^;PBr|#Eg}+r0MQ1m_XAdRL9??aa9g3*i)F?=;a@uSrQ?^9H6B?J+VY-Yg z#TK{P(1{3nA6AYd|0Dh;|8wb3Z2|^G!G8?G*PgNyf5mlKI;vMb0l-Nn}=35wmQUIr(6T; zH36y)-ch$xSSBrrBeC<8NB$eFtI~NTa8te82lm%#?V4kP_PL5j z3MuWR3gG2%%b25sMlHx?+Yc_0EyK{SAhRU}25_o`4%g=y5Bs-U*QKMrj-4$AugcozxuJj{fe;liT^(`iGamDAx}G2%_NDJ4 z=Tue~Ai3FHrP0;e)4H(bC5XE0AdBk777BXmv4KlUD|~5FhU@)~Ib5ive#Qg-t=BW8 zGiOGq%cqhnYU3`{7?dYwsD}nRtKnVEA)xaFxwti!gcf)u<>eMb{>ftg&#q_Kok4Vs z-R-=Q23%rnI~gB?bRF0iHhltrr=mmXwwg$-H#HXh2fpxkEi$N{$$_Fik?t2tS%avCA2iuE56 z@_%|=myYPsO0k$n+^dr>YE0~-htfgK%LCIhXi5Y^&L@2OpM71I&Lmb4sxCgs*a95# zLkWSRK^L1JM-0w@ZF<57|3|DR+?}IArqh#DI8`}+0xfYY*aT~*#JH^gTK?a)o?v%4 zysOMk3%eN}^g8S8-+^pFA}RDAhmk#FU6;=5?6s^0vZHM|hYc!j&mp1V%|987xwf7l z9lIYrGjnNf*tW67ni|CBc>Ue~(d!A)Ar)GsJh6lrP|s8UjbNU!o**5y2gosP%g)lL z>u>q*(t3h)I3E~8&wn<)(x1PcAe~n;Ft;bX&A;or_5VD&bHo9aDA@o2002ovPDHLk FV1gr8(H#H) literal 0 HcmV?d00001 diff --git a/example/lib/pages/epsg3413_crs.dart b/example/lib/pages/epsg3413_crs.dart index 916f397a2..346ae134e 100644 --- a/example/lib/pages/epsg3413_crs.dart +++ b/example/lib/pages/epsg3413_crs.dart @@ -19,28 +19,10 @@ class _EPSG3413PageState extends State { double? maxZoom; - // Define start center - proj4.Point point = proj4.Point(x: 90, y: 0); - - String initText = 'Map centered to'; - - late final proj4.Projection epsg4326; - - late final proj4.Projection epsg3413; - @override void initState() { super.initState(); - epsg4326 = proj4.Projection.get('EPSG:4326')!; - - // EPSG:3413 is a user-defined projection from a valid Proj4 definition string - // From: http://epsg.io/3413, proj definition: http://epsg.io/3413.proj4 - // Find Projection by name or define it if not exists - epsg3413 = proj4.Projection.get('EPSG:3413') ?? - proj4.Projection.add('EPSG:3413', - '+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs'); - // 9 example zoom level resolutions final resolutions = [ 32768, @@ -61,6 +43,13 @@ class _EPSG3413PageState extends State { maxZoom = (resolutions.length - 1).toDouble(); + // EPSG:3413 is a user-defined projection from a valid Proj4 definition string + // From: http://epsg.io/3413, proj definition: http://epsg.io/3413.proj4 + // Find Projection by name or define it if not exists + final proj4.Projection epsg3413 = proj4.Projection.get('EPSG:3413') ?? + proj4.Projection.add('EPSG:3413', + '+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs'); + epsg3413CRS = Proj4Crs.fromFactory( code: 'EPSG:3413', proj4Projection: epsg3413, @@ -74,8 +63,26 @@ class _EPSG3413PageState extends State { @override Widget build(BuildContext context) { + // These circles should have the same pixel radius on the map + final circles = [ + CircleMarker( + point: LatLng(90, 0), + radius: 20000, + useRadiusInMeter: true, + color: Colors.red, + ) + ]; + for (final lon in [-90.0, 0.0, 90.0, 180.0]) { + circles.add(CircleMarker( + point: LatLng(80, lon), + radius: 20000, + useRadiusInMeter: true, + color: Colors.red, + )); + } + return Scaffold( - appBar: AppBar(title: const Text('EPSG:4326 CRS')), + appBar: AppBar(title: const Text('EPSG:3413 CRS')), drawer: buildDrawer(context, EPSG3413Page.route), body: Padding( padding: const EdgeInsets.all(8.0), @@ -92,23 +99,17 @@ class _EPSG3413PageState extends State { ), ), ), - Padding( - padding: const EdgeInsets.only(top: 8.0, bottom: 2.0), - child: Text( - '$initText (${point.x.toStringAsFixed(5)}, ${point.y.toStringAsFixed(5)}) in EPSG:4326.', - ), - ), - Padding( - padding: const EdgeInsets.only(top: 2.0, bottom: 2.0), + const Padding( + padding: EdgeInsets.only(top: 8.0, bottom: 2.0), child: Text( - 'Which is (${epsg4326.transform(epsg3413, point).x.toStringAsFixed(2)}, ${epsg4326.transform(epsg3413, point).y.toStringAsFixed(2)}) in EPSG:3413.', + 'This page demonstrates some tricky edge-cases for maps with a polar projection.', ), ), Flexible( child: FlutterMap( options: MapOptions( crs: epsg3413CRS, - center: LatLng(point.x, point.y), + center: LatLng(90, 0), zoom: 3.0, maxZoom: maxZoom, ), @@ -125,6 +126,22 @@ class _EPSG3413PageState extends State { layers: ['gebco_north_polar_view'], ), ), + CircleLayerOptions( + circles: circles, + ), + OverlayImageLayerOptions( + overlayImages: [ + OverlayImage( + bounds: LatLngBounds( + LatLng(72.7911372, 162.6196478), + LatLng(85.2802493, 79.794166), + ), + imageProvider: Image.asset( + 'map/epsg3413/amsr2.png', + ).image, + ) + ], + ) ], ), ), diff --git a/example/pubspec.yaml b/example/pubspec.yaml index afbcf07a2..5f478c080 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -59,3 +59,4 @@ flutter: - assets/map/anholt_osmbright/14/8725/ - assets/map/anholt_osmbright/14/8726/ - assets/map/anholt_osmbright/14/8727/ + - assets/map/epsg3413/amsr2.png diff --git a/lib/src/layer/overlay_image_layer.dart b/lib/src/layer/overlay_image_layer.dart index 4a7e9657b..5bfd53b17 100644 --- a/lib/src/layer/overlay_image_layer.dart +++ b/lib/src/layer/overlay_image_layer.dart @@ -73,7 +73,7 @@ class OverlayImageLayer extends StatelessWidget { map.project(overlayImage.bounds.northWest) - map.getPixelOrigin(), map.project(overlayImage.bounds.southEast) - map.getPixelOrigin(), ); - + return Positioned( left: bounds.topLeft.x.toDouble(), top: bounds.topLeft.y.toDouble(), From 18e3a22dfd6abaee639251f2aebcca683f873502 Mon Sep 17 00:00:00 2001 From: Josef Nilsen Date: Sat, 16 Jul 2022 12:32:08 +0200 Subject: [PATCH 7/8] Improve polar projection example --- example/lib/pages/epsg3413_crs.dart | 37 ++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/example/lib/pages/epsg3413_crs.dart b/example/lib/pages/epsg3413_crs.dart index 346ae134e..e12d4f534 100644 --- a/example/lib/pages/epsg3413_crs.dart +++ b/example/lib/pages/epsg3413_crs.dart @@ -69,7 +69,7 @@ class _EPSG3413PageState extends State { point: LatLng(90, 0), radius: 20000, useRadiusInMeter: true, - color: Colors.red, + color: Colors.yellow, ) ]; for (final lon in [-90.0, 0.0, 90.0, 180.0]) { @@ -81,6 +81,18 @@ class _EPSG3413PageState extends State { )); } + // Add latitude line at 80 degrees + final distancePoleToLat80 = + const Distance().distance(LatLng(90, 0), LatLng(80, 0)); + circles.add(CircleMarker( + point: LatLng(90, 0), + radius: distancePoleToLat80, + useRadiusInMeter: true, + color: Colors.transparent, + borderColor: Colors.black, + borderStrokeWidth: 1.0, + )); + return Scaffold( appBar: AppBar(title: const Text('EPSG:3413 CRS')), drawer: buildDrawer(context, EPSG3413Page.route), @@ -91,7 +103,7 @@ class _EPSG3413PageState extends State { const Padding( padding: EdgeInsets.only(top: 8.0, bottom: 2.0), child: Text( - 'This map is in EPSG:3413', + 'Tricky edge-cases with polar projections', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.blue, @@ -99,10 +111,19 @@ class _EPSG3413PageState extends State { ), ), ), + const Text( + 'Details: https://github.com/fleaflet/flutter_map/pull/1295'), const Padding( padding: EdgeInsets.only(top: 8.0, bottom: 2.0), - child: Text( - 'This page demonstrates some tricky edge-cases for maps with a polar projection.', + child: SizedBox( + width: 500, + child: Text( + '• Northern and eastern directions are relative to where you are on the map:\n' + ' • A red dot moves north toward the yellow dot (North Pole).\n' + ' • A red dot moves east counter-clockwise along the black latitude line (80°).\n' + '• The lower left and right corners of the overlay image are the northern corners.' + //textAlign: TextAlign.center, + ), ), ), Flexible( @@ -126,9 +147,6 @@ class _EPSG3413PageState extends State { layers: ['gebco_north_polar_view'], ), ), - CircleLayerOptions( - circles: circles, - ), OverlayImageLayerOptions( overlayImages: [ OverlayImage( @@ -141,7 +159,10 @@ class _EPSG3413PageState extends State { ).image, ) ], - ) + ), + CircleLayerOptions( + circles: circles, + ), ], ), ), From dce34f6fe65d71cb3820601389f34eb0fe6be11b Mon Sep 17 00:00:00 2001 From: Josef Nilsen Date: Wed, 20 Jul 2022 17:09:27 +0200 Subject: [PATCH 8/8] Fix issue with polygon rendering --- lib/src/layer/polygon_layer.dart | 28 ++++++++++++++++++---------- lib/src/layer/polyline_layer.dart | 7 ++++--- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/src/layer/polygon_layer.dart b/lib/src/layer/polygon_layer.dart index 022efde19..daaccb812 100644 --- a/lib/src/layer/polygon_layer.dart +++ b/lib/src/layer/polygon_layer.dart @@ -1,5 +1,4 @@ import 'dart:math'; -import 'dart:ui'; import 'package:flutter/widgets.dart'; import 'package:flutter_map/flutter_map.dart'; @@ -42,6 +41,8 @@ class Polygon { final bool disableHolesBorder; final bool isDotted; final bool isFilled; + final StrokeCap strokeCap; + final StrokeJoin strokeJoin; late final LatLngBounds boundingBox; final String? label; final TextStyle labelStyle; @@ -56,6 +57,8 @@ class Polygon { this.disableHolesBorder = false, this.isDotted = false, this.isFilled = false, + this.strokeCap = StrokeCap.round, + this.strokeJoin = StrokeJoin.round, this.label, this.labelStyle = const TextStyle(), this.labelPlacement = PolygonLabelPlacement.centroid, @@ -165,13 +168,13 @@ class PolygonPainter extends CustomPainter { void _paintBorder(Canvas canvas) { if (polygonOpt.borderStrokeWidth > 0.0) { - final borderRadius = (polygonOpt.borderStrokeWidth / 2); - final borderPaint = Paint() ..color = polygonOpt.borderColor ..strokeWidth = polygonOpt.borderStrokeWidth; if (polygonOpt.isDotted) { + final borderRadius = (polygonOpt.borderStrokeWidth / 2); + final spacing = polygonOpt.borderStrokeWidth * 1.5; _paintDottedLine( canvas, polygonOpt.offsets, borderRadius, spacing, borderPaint); @@ -184,12 +187,17 @@ class PolygonPainter extends CustomPainter { } } } else { - _paintLine(canvas, polygonOpt.offsets, borderRadius, borderPaint); + borderPaint + ..style = PaintingStyle.stroke + ..strokeCap = polygonOpt.strokeCap + ..strokeJoin = polygonOpt.strokeJoin; + + _paintLine(canvas, polygonOpt.offsets, borderPaint); if (!polygonOpt.disableHolesBorder && null != polygonOpt.holeOffsetsList) { for (final offsets in polygonOpt.holeOffsetsList!) { - _paintLine(canvas, offsets, borderRadius, borderPaint); + _paintLine(canvas, offsets, borderPaint); } } } @@ -218,12 +226,12 @@ class PolygonPainter extends CustomPainter { canvas.drawCircle(offsets.last, radius, paint); } - void _paintLine( - Canvas canvas, List offsets, double radius, Paint paint) { - canvas.drawPoints(PointMode.lines, [...offsets, offsets[0]], paint); - for (final offset in offsets) { - canvas.drawCircle(offset, radius, paint); + void _paintLine(Canvas canvas, List offsets, Paint paint) { + if (offsets.isEmpty) { + return; } + final path = Path()..addPolygon(offsets, true); + canvas.drawPath(path, paint); } void _paintPolygon(Canvas canvas, Rect rect) { diff --git a/lib/src/layer/polyline_layer.dart b/lib/src/layer/polyline_layer.dart index 57571f381..e925d8762 100644 --- a/lib/src/layer/polyline_layer.dart +++ b/lib/src/layer/polyline_layer.dart @@ -240,10 +240,11 @@ class PolylinePainter extends CustomPainter { } void _paintLine(Canvas canvas, List offsets, Paint paint) { - if (offsets.isNotEmpty) { - final path = ui.Path()..addPolygon(offsets, false); - canvas.drawPath(path, paint); + if (offsets.isEmpty) { + return; } + final path = ui.Path()..addPolygon(offsets, false); + canvas.drawPath(path, paint); } ui.Gradient _paintGradient() => ui.Gradient.linear(polylineOpt.offsets.first,