Closed asim27 closed 1 year ago
I've same problem with WMS provider. I've tested on 4.0.0-beta.5. This is the code:
XmlDocument capabilities = new XmlDocument { XmlResolver = null };
capabilities.Load("http://sgi2.isprambiente.it/arcgis/services/raster/igm25k_lazio_wgs/ImageServer/WMSServer?service=wms&request=getCapabilities&version=1.3.0");
WmsProvider provider = new WmsProvider(capabilities)
{
CRS = "EPSG:3857",
ContinueOnError = true,
TimeOut = 20000
};
provider.AddLayer("igm25k_lazio_wgs");
provider.SetImageFormat((provider.OutputFormats)[0]);
ILayer imageLayer = new ImageLayer("mainmap")
{
DataSource = provider,
};
mapView.Map.Layers.Add(imageLayer);
The behavior is that no map is shown and pan and zoom don't work. I've tested on different map server but the behavios is the same. A question. The CRS of the map must be the same of the provider? Thank you.
You should use WfsProvider.CreateAsync ... and WmsProvider.CreateAsync ... because Constructors cannot be asynchronous this methods initialize the wfs and wms provider asynchronous because a http call is involved.
Ok, now i've tried this code:
protected async override void OnAppearing()
{
base.OnAppearing();
mapView.Map = await CreateMapAsync();
Mapsui.Widgets.ScaleBar.ScaleBarWidget scale = new Mapsui.Widgets.ScaleBar.ScaleBarWidget(mapView.Map)
{
TextAlignment = Alignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top
};
mapView.Map.Widgets.Add(scale);
mapView.Map.Layers.Add(await CreateLayerAsync());
}
public static async Task<Mapsui.Map> CreateMapAsync()
{
var map = new Mapsui.Map { CRS = "EPSG:3857" };
map.Layers.Add(await CreateLayerAsync());
return map;
}
public static async Task<ILayer> CreateLayerAsync()
{
return new ImageLayer("mainmap") { DataSource = await CreateWmsProviderAsync() };
}
private static async Task<WmsProvider> CreateWmsProviderAsync()
{
const string wmsUrl = "https://sgi2.isprambiente.it/arcgis/services/raster/igm25k_lazio_wgs/ImageServer/WMSServer?service=wms&request=getCapabilities&version=1.3.0";
var provider = await WmsProvider.CreateAsync(wmsUrl, persistentCache: null);
provider.ContinueOnError = true;
provider.TimeOut = 20000;
provider.CRS = "EPSG:3857";
provider.AddLayer("igm25k_lazio_wgs");
provider.SetImageFormat((provider.OutputFormats)[0]);
return provider;
}
I obtain the following error: System.ApplicationException: 'Could not download capabilities'
I would try https instead of http.
I corrected the above code and tried again but nothing changes. I tried also:
const string wmsUrl = "https://wms.pcn.minambiente.it/ogc?map=/ms_ogc/WMS_v1.3/raster/IGM_25000.map&service=wms&request=getCapabilities&version=1.3.0";
var capabilities = new XmlDocument { XmlResolver = null };
capabilities.Load(wmsUrl);
var provider = new WmsProvider(capabilities)
{
CRS = "EPSG:4326",
};
and I obtain: System.Net.WebException: 'Error: TrustFailure (Authentication failed, see inner exception.)' It should be noted that if I launch the link in the browser the capabilities xml file is loaded correctly. With OpenLayers the link above works fine.
I've tried the code posted on Mar 30 (see above) with Mapsui 4.0.0-rc.1. Now there aren't errors but map isn't shown. Note that, after added the layer to the map, mapView.Map.Navigator.Resolutions.Count = 0. Did I do something wrong in the code? I've tried the code on Windows 10 + Android (Samsung A53). Thank you.
I fixed here a WMSProvider Bug too. https://github.com/Mapsui/Mapsui/pull/2007
The wms Http request was missing service=wms // newer wms service complain about it. older seem to not care.
This should be changed
public static async Task<ILayer> CreateLayerAsync()
{
return new ImageLayer("mainmap") { DataSource = await CreateWmsProviderAsync() };
}
to this
public static async Task<ILayer> CreateLayerAsync()
{
return new ImageLayer("mainmap")
{
DataSource = await CreateWmsProviderAsync(),
Style = new RasterStyle()
};
}
Because without the Style = RasterStyle() mapsui does not know how to render the imagelayer
this line sets the image format to
provider.SetImageFormat((provider.OutputFormats)[0]);
I think this is a missing case that needs to be handled in BitmapHelper.LoadBitmap
image/tiff
Because without the Style = RasterStyle() mapsui does not know how to render the imagelayer
This has caused confusion before. We need to improve it. The behavior needs to be consistent for all styles though.
I would suggest that The ImageLayer has RasterStyle set as default. So it would work out of the box. But still be customizable.
I've tried the code suggested by inforithmics without success:
`
protected async override void OnAppearing()
{
base.OnAppearing();
mapView.Map = await CreateMapAsync();
}
public async Task<Map> CreateMapAsync()
{
var map = new Map {
CRS = "EPSG:3857"
};
Mapsui.Widgets.ScaleBar.ScaleBarWidget scale = new Mapsui.Widgets.ScaleBar.ScaleBarWidget(mapView.Map)
{
TextAlignment = Alignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top
};
map.Widgets.Add(scale);
map.Layers.Add(await CreateLayerAsync());
return map;
}
public static async Task<ILayer> CreateLayerAsync()
{
return new ImageLayer("mainmap")
{
DataSource = await CreateWmsProviderAsync(),
Style = new RasterStyle()
};
}
private static async Task<WmsProvider> CreateWmsProviderAsync()
{
const string wmsUrl = "https://sgi2.isprambiente.it/arcgis/services/raster/igm25k_lazio_wgs/ImageServer/WMSServer?service=wms&request=getCapabilities&version=1.3.0";
var provider = await WmsProvider.CreateAsync(wmsUrl, persistentCache: null);
provider.ContinueOnError = true;
provider.TimeOut = 20000;
provider.CRS = "EPSG:3857";
provider.AddLayer("igm25k_lazio_wgs");
provider.SetImageFormat((provider.OutputFormats)[1]);
return provider;
}
`
Note that EPSG:3857 is not contained in the xml capabilities. There are only: CRS:84, EPSG:4326, EPSG:0 (what does it mean?). May be this the problem? Thank you.
You should use EPSG:4326 and use a projection provider
I've changed
provider.CRS = "EPSG:3857";
with
provider.CRS = "EPSG:4326";
but results are the same.
What do you mean by "projection provider"?
If the map CRS is 3857 can CRS provider is 4326?
It should be considered that I could add layers with different EPSGs.
Is it possible?
Thank you.
Mapsui Projection.
There is something special about this wms service. Because in the sample I created here it still does not get the right data. My guess it fetches the wrong coordinates. But still investigating.
Thank you for info. I've made another test with this server (Spain orthophoto): https://www.ign.es/wms-inspire/pnoa-ma?service=wms&request=getCapabilities the layer is: OI.OrthoimageCoverage
Test 1: map CRS: EPSG:3857, CRS provider: EPSG:3857 => it works fine Test 2: map CRS: EPSG:3857, CRS provider: EPSG:4326 => map is shown but scale is wrong and perhaps coordinates Test 3: map CRS: EPSG:4326, CRS provider: EPSG:4326 => as above
May be test 2 needs implementing Mapsui projection as inforithmics said. Sincerely I don't understand how set a working projection. I've seen the example in https://mapsui.com/documentation/projections.html but it seems incomplete or I don't understand the mechanism. Why test 3 doesn't work? It doens't need a reprojection. Thank you.
The wms server you are using is an Archivs server. Maybe you can use mapsui.Archie's to fetch the data.
Sorry but I'm a bit confused. Where do you know that the server is Archivs (or Archie)? I've never heard of it before. In other environments (eg: OpenLayers) it is a WMS server like any other.
Auto correction error. I meant ArcGis
How do you know it's an ArcGIS server? Is there any documentation or examples on Masui.ArcGIS?
It's only a guess because it has arcgis in it's url.
Sample
Thank you. I'll try it. However it responds with a classic XSD WMS version 1.3.0. In OpenLayers the provider used for both my examples is the same (ol.source.TileWMS).
The ArcGIS WMS is supposed to follow the OGC standard. It can always be a bit different but I would expect the implementation is correct. It probably works correctly in a QGIS client as well.
It seems that mapsui needs to url encode more parameters.
It is the crs: with EPSG:4326 the axis are changed. So it doesn't load the data, I think the problem is that the extent is initially wrong because this needs to be changed too. see: https://github.com/Mapsui/Mapsui/issues/1925#issuecomment-1493411132
The "DPI", "MAP_RESOLUTION" and "FORMAT_OPTIONS" parameters are not actually needed. So both link are identical except the order of the coordinates. I know post #1925, I reported this issue but I thought the release candidate version fixed it. I've tried the following code:
`
protected async override void OnAppearing()
{
base.OnAppearing();
mapView.Map = await CreateMapAsync();
}
public async Task<Map> CreateMapAsync()
{
var map = new Map {
CRS = "EPSG:3857"
};
Mapsui.Widgets.ScaleBar.ScaleBarWidget scale = new Mapsui.Widgets.ScaleBar.ScaleBarWidget(mapView.Map)
{
TextAlignment = Alignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top
};
map.Widgets.Add(scale);
map.Layers.Add(await CreateLayerAsync());
return map;
}
public static async Task<ILayer> CreateLayerAsync()
{
return new ImageLayer("mainmap")
{
DataSource = await CreateWmsProviderAsync(),
Style = new RasterStyle(),
Attribution = new Hyperlink() {
Text = "attributions"
}
};
}
private static async Task<WmsProvider> CreateWmsProviderAsync()
{
const string wmsUrl = "https://sgi2.isprambiente.it/arcgis/services/raster/igm25k_lazio_wgs/ImageServer/WMSServer?service=wms&request=getCapabilities&version=1.3.0";
var provider = await WmsProvider.CreateAsync(wmsUrl, persistentCache: null);
provider.ContinueOnError = true;
provider.TimeOut = 20000;
provider.CRS = "CRS:84";
provider.AddLayer("igm25k_lazio_wgs");
provider.SetImageFormat((provider.OutputFormats)[1]);
return provider;
}
}
` The map is shown but there is an error on scale and coordinates. Zoom flickers.
I've tried this server also but the map isn't shown: https://geoportale.regione.lazio.it/geoserver/ows?service=wms&request=getCapabilities&version=1.3.0 layer: "geonode:ctr_5k_retiled" However, it should be considered that not all services have CRS:84.
After the pull request with the fixes goes on this sample should work now.
using Mapsui.Cache;
using Mapsui.Layers;
using Mapsui.Providers.Wms;
using System.Threading.Tasks;
using Mapsui.Nts.Extensions;
using Mapsui.Providers;
using Mapsui.Styles;
using NetTopologySuite.Geometries;
namespace Mapsui.Samples.Common.Maps.DataFormats;
public class WmsProjectionSample : ISample
{
public string Name => " 6 WMS Projection";
public string Category => "Data Formats";
public static IUrlPersistentCache? DefaultCache { get; set; }
public async Task<Map> CreateMapAsync()
{
var map = new Mapsui.Map
{
CRS = "EPSG:3857",
};
// The WMS request needs a CRS
map.Layers.Add(await CreateLayerAsync());
return map;
}
public static async Task<ILayer> CreateLayerAsync()
{
var dataSource = new ProjectingProvider(await CreateWmsProviderAsync())
{
CRS = "EPSG:3857"
};
return new ImageLayer("mainmap")
{
DataSource = dataSource,
Style = new RasterStyle()
};
}
private static async Task<WmsProvider> CreateWmsProviderAsync()
{
const string wmsUrl = "https://sgi2.isprambiente.it/arcgis/services/raster/igm25k_lazio_wgs/ImageServer/WMSServer?service=wms&request=getCapabilities&version=1.3.0";
var provider = await WmsProvider.CreateAsync(wmsUrl, persistentCache: DefaultCache);
provider.ContinueOnError = true;
provider.TimeOut = 20000;
provider.CRS = "EPSG:4326";
provider.AddLayer("igm25k_lazio_wgs");
provider.SetImageFormat((provider.OutputFormats)[1]);
return provider;
}
}
I've tried this code:
`
using System.Threading.Tasks;
using Xamarin.Forms;
using Mapsui;
using Mapsui.Layers;
using Mapsui.Providers.Wms;
using Mapsui.Extensions;
using Mapsui.Widgets;
using Mapsui.Styles;
using Mapsui.Cache;
using System.ComponentModel;
using Mapsui.Projections;
using System.Collections.Generic;
namespace OkMap.Views
{
public partial class Maps : ContentPage
{
public static IUrlPersistentCache DefaultCache { get; set; }
public Maps()
{
InitializeComponent();
}
protected async override void OnAppearing()
{
base.OnAppearing();
mapView.Map = await CreateMapAsync();
mapView.Map.Navigator.ViewportChanged += mapView_ViewPortChanged;
}
public async Task<Map> CreateMapAsync()
{
var map = new Map {
CRS = "EPSG:3857"
};
Mapsui.Widgets.ScaleBar.ScaleBarWidget scale = new Mapsui.Widgets.ScaleBar.ScaleBarWidget(mapView.Map)
{
TextAlignment = Alignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Top
};
map.Widgets.Add(scale);
map.Layers.Add(await CreateLayerAsync());
return map;
}
public static async Task<ILayer> CreateLayerAsync()
{
return new ImageLayer("mainmap")
{
DataSource = await CreateWmsProviderAsync(),
Style = new RasterStyle(),
Attribution = new Hyperlink() {
Text = "attributions"
}
};
}
private static async Task<WmsProvider> CreateWmsProviderAsync()
{
const string wmsUrl = "https://sgi2.isprambiente.it/arcgis/services/raster/igm25k_lazio_wgs/ImageServer/WMSServer?service=wms&request=getCapabilities&version=1.3.0";
//const string wmsUrl = "https://geoportale.regione.lazio.it/geoserver/ows?service=wms&request=getCapabilities&version=1.3.0";
//const string wmsUrl = "https://www.ign.es/wms-inspire/pnoa-ma?service=wms&request=getCapabilities";
var provider = await WmsProvider.CreateAsync(wmsUrl, persistentCache: DefaultCache);
provider.ContinueOnError = true;
provider.TimeOut = 20000;
provider.CRS = "EPSG:4326";
provider.AddLayer("igm25k_lazio_wgs");
//provider.AddLayer("geonode:ctr_5k_retiled");
//provider.AddLayer("OI.OrthoimageCoverage");
provider.SetImageFormat((provider.OutputFormats)[1]);
return provider;
}
private void mapView_ViewPortChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
(double lon, double lat) mapCenter = SphericalMercator.ToLonLat(mapView.Map.Navigator.Viewport.CenterX, mapView.Map.Navigator.Viewport.CenterY);
Device.BeginInvokeOnMainThread(() => {
lblCoordinates.Text = mapView.Map.Navigator.Viewport.CenterY.ToString() + " " + mapView.Map.Navigator.Viewport.CenterX.ToString() + " " + GetZoom().ToString();
});
}
private int GetZoom()
{
IReadOnlyList<double> resolutions = mapView.Map.Navigator.Resolutions;
for (int i = 0; i <= resolutions.Count - 1; i++)
{
if (mapView.Map.Navigator.Viewport.Resolution >= resolutions[i])
return i + 1;
}
return resolutions.Count;
}
}
}
`
1- Shown scale is wrong 2- Map in streched horizzontally (grid is formed by rectangle and not by square) 3- This statement mapView.Map.Navigator.Resolutions return zero length array I downloaded the latest version 4.0.0-rc.2. What am I doing wrong? Thank you.
I'm not followed the whole discussion, so I might be wrong.
If you read this info, and compare it with your last code, then I fear, that you try to fit EPSG:4326 tiles in a EPSG:3857 map, which, with my understanding, doesn't work.
I know the difference between datum and projection and between EPSG.4326 and EPSG:3857. Based on Mapsui official documentation (see below), I thought Mapsui was able to convert between these two systems. However even if I crete the map with EPSG:4326 CRS the problem remains the same.
Out of the box Mapsui only supports the projection between two coordinate systems.
Yes, Mapsui knows both, but I could not find any conversion from one format to another. What you could do is convert coordinates from one of these projections to Mapsui and vice versa. But there isn't a conversion of raster data.
However even if the CRS of the map = EPSG:4326 and the CRS of the provider = EPSG:4326 there are problems about map streching, map scale and map resolutions (mapView.Map.Navigator.Resolutions return zero length array). If the CRS of the map = EPSG:3857 and the CRS of the provider = EPSG:3857, the map is not streched, map scale is ok but the statement mapView.Map.Navigator.Resolutions always return zero length array.
Test with url: https://www.ign.es/wms-inspire/pnoa-ma?service=wms&request=getCapabilities layer: OI.OrthoimageCoverage
My fixes are not yet in 4.0.0-rc.2. so they should be in the next rc or release. As far as I know only tile layers support resolutions and because it is a wms layer it hasn't one.
sample for tiling a wms server (makes it faster too).
public Task<Map> CreateMapAsync()
{
var map = new Map();
map.Layers.Add(CreateLayer());
return Task.FromResult(map);
}
public static ILayer CreateLayer()
{
return new TileLayer(CreateTileSource()) { Name = "Omgevingswarmte (PDOK)" };
}
public static ITileSource CreateTileSource()
{
const string url = "https://geodata.nationaalgeoregister.nl/omgevingswarmte/wms?SERVICE=WMS&VERSION=1.1.1";
// You need to know the schema. This can be a problem. Usally it is GlobalSphericalMercator
var schema = new WkstNederlandSchema { Format = "image/png", Srs = "EPSG:28992" };
var request = new WmscRequest(new Uri(url), schema, new[] { "koudegeslotenwkobuurt" }.ToList(), Array.Empty<string>().ToList());
var provider = new HttpTileProvider(request, DefaultCache);
return new TileSource(provider, schema) { Name = "Omgevingswarmte (PDOK)" };
}
Actually the list of resolutions is only for me to determine the zoom factor (integer 1-20). Is there another way to determine the zoom factor?
Your solution uses the WkstNederlandSchema class which inherits from TileSchema. I tested it and works fine. Does that mean I have to implement a class for each CRS?
In my software (OkMap Mobile for iOS and Android) the user chooses the TMS/WMS server and the app should work in any case. So far I could only implement TMS (XYZ) because I found a lot of problems with WMS. In the dekstop app (OkMap Desktop) I use Openlayers without problems and the user chooses his server from a list of more than 200 and can define his own. There is no need to supply the CRS in the code because, I suppose, OpenLayers does all the necessary conversions. I would like to do a similar thing with OkMap Mobile and Mapsui. I'll wait for the next rc and I'll do more tests. Thanks so much for the support.
I've made new tests with 4.0.0-rc.3 version. The issue doesn't seem solved (no map was shown). I've tryed these servers with EPSG:3857:
https://www.ign.es/wms-inspire/pnoa-ma?service=wms&request=getCapabilities layer: OI.OrthoimageCoverage
https://wms.geo.admin.ch?service=wms&request=getCapabilities layer: ch.swisstopo.pixelkarte-farbe
I also tried these servers with EPSG:4326:
https://sgi2.isprambiente.it/arcgis/services/raster/igm25k_lazio_wgs/ImageServer/WMSServer?service=wms&request=getCapabilities layer: igm25k_lazio_wgs
https://geoportale.regione.lazio.it/geoserver/ows?service=wms&request=getCapabilities layer: geonode:ctr_5k_retiled
The first seems works but:
Is it possible to manage at least these CRS? (the most important) EPSG:3857, EPSG:4326, CRS:84
public async Task<Map> CreateMapAsync()
{
var map = new Mapsui.Map
{
CRS = "EPSG:3857",
};
// The WMS request needs a CRS
map.Layers.Add(await CreateLayerAsync());
return map;
}
public static async Task<ILayer> CreateLayerAsync()
{
var dataSource = new ProjectingProvider(await CreateWmsProviderAsync())
{
CRS = "EPSG:3857"
};
return new ImageLayer("mainmap")
{
DataSource = dataSource,
Style = new RasterStyle()
};
}
private static async Task<WmsProvider> CreateWmsProviderAsync()
{
const string wmsUrl = "https://sgi2.isprambiente.it/arcgis/services/raster/igm25k_lazio_wgs/ImageServer/WMSServer?service=wms&request=getCapabilities&version=1.3.0";
var provider = await WmsProvider.CreateAsync(wmsUrl, persistentCache: DefaultCache);
provider.ContinueOnError = true;
provider.TimeOut = 20000;
provider.CRS = "EPSG:4326";
provider.AddLayer("igm25k_lazio_wgs");
provider.SetImageFormat((provider.OutputFormats)[1]);
return provider;
}
This Code works (is the sample that the map displays). A Projection Provider needs to be used so that the WmsCalls are projected from EPSG:4326 to EPSG:3857 and the projection needs to be set on the map
Perfect, everything is clear and thank you for the precious answers. I take advantage of the availability to ask you a couple of things that I haven't understood yet. 1) I don't understand why maps that have both EPSG:4326 and EPSG:3857 only work if I use EPSG:4326 as provider.CRS while they don't work with EPSG:3857 (no conversion should be needed in that case). 2) If a map doesn't have CRS:3857 and CRS:4326 (ex: Italy cadastre https://wms.cartografia.agenziaentrate.gov.it/inspire/wms/ows01.php?service=WMS&request=getcapabilities), if I use EPSG:6706 it doesn't work. Perhaps there is a need to write a conversion routine but there is no documentation on this. 3) The command mapView.Map.Navigator.ZoomToLevel(n) has no effect and the property mapView.Map.Navigator.Resolutions.Counts = 0. How is it possible to set a zoom level and know the current zoom level of the map? PS if I use an XYZ layer and an overlapping WMS layer, the zoom works.
I hope these considerations are also valuable for other users. Thank you very much!!!
Thank you very much. Is it possible to speculate when the release 4 will be released?
I think this will take some time but with this link a mapsui version with the fixes can be downloaded and then with a local nuget package folder used.
<configuration>
<config>
<add key="local" value="C:\path\to\custom\folder" />
</config>
</configuration>
C:\path\to\custom\folder
there you put the custom nuget files
https://github.com/Mapsui/Mapsui/suites/13681044682/artifacts/756030684
Many thanks!
Two question.
<configuration>
<config>
<add key="local" value="C:\path\to\custom\folder" />
</config>
</configuration>
Thank you!
you can add a nuget.config file.
with following content.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="local-packages" value="path/to/your/local/package/folder" />
</packageSources>
</configuration>
Ok, thank you!
Answered and fixed with https://github.com/Mapsui/Mapsui/pull/2073
Describe the bug I am not able to create a wfsprovider from latest version 4.0.0-beta.8 WfsProvider method with URI parameter raises System.NullReferenceException: 'Object reference not set to an instance of an object.' on calling InitAsync() method To Reproduce Steps to reproduce the behavior:
Expected behavior System.NullReferenceException: 'Object reference not set to an instance of an object.'
Screenshots
Desktop (please complete the following information):
Smartphone (please complete the following information):