Closed moovida closed 4 years ago
On a sidenote: when removing the crs option it works.
That's because WMSTileLayerOptions
using Epsg3857
by default see: this.crs = const Epsg3857(),
and that just works fine.
The main problem is the provided resolutions
in your code.
You can create a little helper function which will resolve the resolutions
like this:
List<double> getResolutions(double maxX, double minX, int zoom,
[double tileSize = 256.0]) {
var size = (maxX - minX) / tileSize;
return List.generate(zoom, (z) => size / math.pow(2, z));
}
Usually you can get the maxx
/ minx
from the Capabilities http://geoservices.retecivica.bz.it/geoserver/gwc/service/wmts?request=GetCapabilities
Then you should find something like this:
<Layer queryable="1">
<Name>iier:EK_FA_BOKORCS</Name>
<Title>EK_FA_BOKORCS</Title>
<Abstract/>
<SRS>EPSG:23700</SRS>
<BoundingBox SRS="EPSG:23700" minx="420000.0" miny="40000.0" maxx="944288.0" maxy="564288.0"/>
</Layer>
However I couldn't find it. You can get extent from https://epsg.io/ also see https://epsg.io/3857.
Projected bounds:
-20026376.39 -20048966.10
20026376.39 20048966.10
Warning above bounds misleading see the first comment:
The Projected bounds should be wrong.
X domain must be (6378137 * Pi) = 20037508.34
So the right bounds would be:
Projected bounds:
-20037508.342789244 -20037508.342789244
20037508.342789244 20037508.342789244
Here is the final code (I rewrote wms_tile_layer.dart
in flutter_map):
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map/plugin_api.dart';
import 'package:latlong/latlong.dart';
import 'package:proj4dart/proj4dart.dart' as proj4;
import '../widgets/drawer.dart';
List<double> getResolutions(double maxX, double minX, int zoom,
[double tileSize = 256.0]) {
var size = (maxX - minX) / tileSize;
return List.generate(zoom, (z) => size / math.pow(2, z));
}
int r = 6378137;
double _boundsD = r * math.pi;
final Bounds<double> _bounds = Bounds<double>(
CustomPoint<double>(-_boundsD, -_boundsD),
CustomPoint<double>(_boundsD, _boundsD),
);
final resolutions = getResolutions(_boundsD, -_boundsD, 19);
final maxZoom = (resolutions.length - 1).toDouble();
final epsg3857CRS = Proj4Crs.fromFactory(
code: 'EPSG:3857',
proj4Projection: proj4.Projection('EPSG:3857'),
resolutions: resolutions,
bounds: _bounds,
);
class WMSLayerPage extends StatelessWidget {
static const String route = 'WMS layer';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('WMS Layer')),
drawer: buildDrawer(context, route),
body: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child:
Text('This is a map that is showing (46.762784, 11.450838)'),
),
Flexible(
child: FlutterMap(
options: MapOptions(
center: LatLng(46.762784, 11.450838),
zoom: 17,
maxZoom: maxZoom,
crs: epsg3857CRS,
onTap: print,
),
layers: [
TileLayerOptions(
wmsOptions: WMSTileLayerOptions(
crs: epsg3857CRS,
baseUrl:
'http://geoservices.retecivica.bz.it/geoserver/ows?',
layers: ['P_BZ_BASEMAP_HYBRID_EPSG3857'],
),
)
],
),
),
],
),
),
);
}
}
Maybe in Flutter Map
documentation should mention this, however neither Proj4Leaflet nor OpenLayers mention it.
@moovida please let me know if above code works if so I am going to close this issue.
Hi @maRci002 , now I see the point, thanks for the description.
So in fact the getCapabilites needs to be parsed by the enduser library, right? I will have a look at it. I would love to add custom map view to SMASH ( https://www.geopaparazzi.org/smash/index.html ) but I can't ask a user to define bounds. So this has to be extracted from the getCapabilities, but as you are writing, there might be errors in that.
I will have to do some test. I will then report back here to let you know if this works well for other CRS as well.
If you really need to parse getCapabilites
then you could use something like this (I know it's wmts but here they calculate bounds which will have maxX, minX):
http://www.atlefren.net/post/2014/05/how-to-calculate-maxresolution-for-wmts-given-info-in-getcapabilities/
Search a little bit on Google how to calculate resolutions in general.
Thanks @maRci002 , I am trying to wrap my head around this and I am not sure I understand one thing. What you write is ok to define resolutions for a given WMS and its projection. And one could go over to epsg.io or spatialreference.org to get the CRS bounds, even if in the past those have proved to be not always the right ones.
But what I want to achieve is to have a map view with a CRS for which I can:
For this I can't use a resolution schema based on the data I am loading, but it needs to be on the projection, right? Is there a way for me to get to this? I mean, I can live with the fact that it doesn't load raster data of a different CRS, but the rest should load.
Maybe @fegyi001 could help because I'm not a GIS expert.
I think the getResolutions
helper method works only for EPSG:3857
.
This could help also.
Thanks @maRci002 , thank you. Indeed, mine would be a requirement similar to that of a GIS map view. Looking forward to see if that is even feasible.
Just on a sidenote, even if that does not work, please know that I highly appreciate this project. Being able to reproject vector data is already a dream come true. :-)
BTW, do you know of an online service that also would supply the bounds of a CRS. I tested downloading the proj4 definitions from epsg.io and it works great, so reprojecting for example geopackage vector data works nice. But I found no way to get the bounds, so that I could calculate the right settings for a generic CRS map view.
On a sidenote: when removing the crs option it works.
That's because
WMSTileLayerOptions
usingEpsg3857
by default see:this.crs = const Epsg3857(),
and that just works fine.The main problem is the provided
resolutions
in your code. You can create a little helper function which will resolve theresolutions
like this:List<double> getResolutions(double maxX, double minX, int zoom, [double tileSize = 256.0]) { var size = (maxX - minX) / tileSize; return List.generate(zoom, (z) => size / math.pow(2, z)); }
Usually you can get the
maxx
/minx
from the Capabilities http://geoservices.retecivica.bz.it/geoserver/gwc/service/wmts?request=GetCapabilities Then you should find something like this:<Layer queryable="1"> <Name>iier:EK_FA_BOKORCS</Name> <Title>EK_FA_BOKORCS</Title> <Abstract/> <SRS>EPSG:23700</SRS> <BoundingBox SRS="EPSG:23700" minx="420000.0" miny="40000.0" maxx="944288.0" maxy="564288.0"/> </Layer>
However I couldn't find it. You can get extent from https://epsg.io/ also see https://epsg.io/3857.
Projected bounds: -20026376.39 -20048966.10 20026376.39 20048966.10
Warning above bounds misleading see the first comment:
The Projected bounds should be wrong. X domain must be (6378137 * Pi) = 20037508.34
So the right bounds would be:
Projected bounds: -20037508.342789244 -20037508.342789244 20037508.342789244 20037508.342789244
Here is the final code (I rewrote
wms_tile_layer.dart
in flutter_map):import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/plugin_api.dart'; import 'package:latlong/latlong.dart'; import 'package:proj4dart/proj4dart.dart' as proj4; import '../widgets/drawer.dart'; List<double> getResolutions(double maxX, double minX, int zoom, [double tileSize = 256.0]) { var size = (maxX - minX) / tileSize; return List.generate(zoom, (z) => size / math.pow(2, z)); } int r = 6378137; double _boundsD = r * math.pi; final Bounds<double> _bounds = Bounds<double>( CustomPoint<double>(-_boundsD, -_boundsD), CustomPoint<double>(_boundsD, _boundsD), ); final resolutions = getResolutions(_boundsD, -_boundsD, 19); final maxZoom = (resolutions.length - 1).toDouble(); final epsg3857CRS = Proj4Crs.fromFactory( code: 'EPSG:3857', proj4Projection: proj4.Projection('EPSG:3857'), resolutions: resolutions, bounds: _bounds, ); class WMSLayerPage extends StatelessWidget { static const String route = 'WMS layer'; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('WMS Layer')), drawer: buildDrawer(context, route), body: Padding( padding: EdgeInsets.all(8.0), child: Column( children: [ Padding( padding: EdgeInsets.only(top: 8.0, bottom: 8.0), child: Text('This is a map that is showing (46.762784, 11.450838)'), ), Flexible( child: FlutterMap( options: MapOptions( center: LatLng(46.762784, 11.450838), zoom: 17, maxZoom: maxZoom, crs: epsg3857CRS, onTap: print, ), layers: [ TileLayerOptions( wmsOptions: WMSTileLayerOptions( crs: epsg3857CRS, baseUrl: 'http://geoservices.retecivica.bz.it/geoserver/ows?', layers: ['P_BZ_BASEMAP_HYBRID_EPSG3857'], ), ) ], ), ), ], ), ), ); } }
For example, which are EPSG:5253's minx and maxx? epsg.io 5253 I tried some possibilities, but I took 'Couldn't download or retrieve file.' error.
@berkayoruc that is what I was asking in the comment. You can get the definition as https://epsg.io/5253.proj4, but not the bounds. I am not sure a service is out there that gives that. This makes it almost impossible to do this automatically and therefore make a switchable base for a custom crs flutter_map for example.
@moovida so creating gis data collection app with flutter_map is not good. BTW I need compile input or qfield😄
@moovida so creating gis data collection app with flutter_map is not good.
Let's say I didn't find a smooth way to do that. Maybe it is just that I do not know how.
BTW I need compile input or qfield😄
How do you mix those with flutter? Not really an issue for this repo, but I am curious :-D
@moovida No, I mean I didn't integrate qfield or input in flutter. Maybe C++ files about qgis will can add to flutter project. But this way, I think, will be so diffucult.
I'm going to close this issue because main problem has been solved and there isn't any generic solution for determine resolutions
/ scales
even for Leaflet / OpenLayers.
Even if this is happening in a flutter_map project, I feel that it makes sense to post the issue here.
I am trying to load a WMS layer with a defined CRS. What I am doing is more or less:
But on creation of the layer, I am getting:
with the following stacktrace:
Am I missing something in the creation?
Just as info, if it helps:
On a sidenote: when removing the crs option it works.