【问题标题】:How to use Openstreetmap(osm) offline tiles file in .net core?如何在 .net core 中使用 Openstreetmap(osm) 离线切片文件?
【发布时间】:2019-08-26 12:25:39
【问题描述】:

我有一个使用Leaflet 来显示一个小区域的地图的网络应用程序。问题是应用程序必须离线工作(在 LAN 上)并且地图图块是从 Openstreetmap 加载的。我下载了我需要的图块,但我没有找到关于如何使用下载文件的好的文档(这是一个 500MB 的文件,扩展名为 .mbtiles)。这是 Leaflet 建议的默认方法:

    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map); 

如何使用dotnet core 设置服务器以使用我的离线磁贴和给定参数并获取磁贴图像?(如下所示):

L.tileLayer('https://example.com/DotnetCore/WepApi/GetTiles?{s}/{z}/{x}/{y}').addTo(map);

【问题讨论】:

  • 我不知道OSM文件格式tiles,但我想,它一定是某种容器。您是否尝试使用 7-Zip 之类的文件打开 tiles 文件?如果是:它是否包含不同 LOD 的缓存切片?或者有什么文件吗?
  • 我发现.MBTiles其实是Sqlite数据库文件。

标签: c# .net-core leaflet openstreetmap asp.net-core-webapi


【解决方案1】:

这里是读取切片文件并在您的 WebApi 中提供它们的基本实现。

您需要安装 NuGet System.Data.SQLite.Core(或类似软件)才能访问数据库。

助手类:

public class MbTilesReader
{
    private string _mbTilesFilename;

    public MbTilesReader(string mbTilesFilename)
    {
        _mbTilesFilename = mbTilesFilename;
    }

    public byte[] GetImageData(int x, int y, int zoom)
    {
        byte[] imageData = null;
        using (SQLiteConnection conn = new SQLiteConnection(string.Format("Data Source={0};Version=3;", _mbTilesFilename)))
        {
            conn.Open();
            using (SQLiteCommand cmd = new SQLiteCommand(conn))
            {
                cmd.CommandText = "SELECT * FROM tiles WHERE tile_column = @x and tile_row = @y and zoom_level = @z";
                cmd.CommandType = System.Data.CommandType.Text;
                cmd.Parameters.Add(new SQLiteParameter("@x", x));
                cmd.Parameters.Add(new SQLiteParameter("@y", y));
                cmd.Parameters.Add(new SQLiteParameter("@z", zoom));
                SQLiteDataReader reader = cmd.ExecuteReader();
                if (reader.Read())
                {
                    imageData = reader["tile_data"] as byte[];
                }
            }
        }
        return imageData;
    }
}

然后在您的 ConfigureServices 方法中将该类注册为单例并将路径传递给文件:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(new MbTilesReader("c:/temp/map.mbtiles"));
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

最后,您可以在 WebApi 操作中返回图像,如下所示:

[Route("api/[controller]")]
[ApiController]
public class MapController : ControllerBase
{
    private MbTilesReader _tileReader;

    public MapController(MbTilesReader tileReader)
    {
        _tileReader = tileReader;

    }

    [HttpGet]
    public IActionResult Get(int x, int y, int z)
    {
        byte[] imageData = _tileReader.GetImageData(x, y, z);
        return File(imageData, "image/png");
    }
}

可能的改进

  • 使用缓存避免始终查询相同的图像。
  • 使实现异步(请参阅this 问题)。

编辑 - 格式

此答案假设您的数据以 PNG 格式存储,.mbtiles 文件可以以以下格式存储数据 pbf(用于矢量)、jpg、png 和 webapp。要了解您的数据库使用的是哪种格式,请检查 .mbtiles SQLite 数据库的表元数据中的数据。

查看以下链接了解更多信息:https://github.com/mapbox/mbtiles-spec/blob/master/1.3/spec.md

【讨论】:

  • 我现在测试了这个,似乎字节数组不是图像格式,即使它不能被 Image 类保存。
  • 你是怎么保存的?
  • 首先我尝试了不同的文件保存方式,例如使用 MemoryStream 和 Image.FromMemoryStream。然后当我确定正确保存时,我使用在线工具检查文件格式,发现它是 .gz是一个压缩文件。然后我重命名并提取了文件,这次结果是 ApplicationOctedStream。我在互联网上找到的每段代码都使用 tile_data 作为图像。
  • 还有其他意见吗?
  • 实际上,您提到您的mbtiles是pbf格式的,我认为这是用于矢量数据的,您确定您下载的是png格式的图像吗?你能把你生成文件的网址发给我吗?我对答案做了一点更新。
猜你喜欢
  • 2023-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多