Leaflet - Как сохранить эффективность исходной системы координат при использовании тайлового слоя?

В моем приложении Leaflet я использовал для отображения фонового слоя с помощью ImageOverlay. Но поскольку изображение слишком велико и замедляет обработку Leaflet, я перехожу на мозаичный подход. Я использовал gdal2tiles-leaflet для создания своих плиток. Все работало нормально.

Но теперь моя декартова система координат, в которой проецируется мой фоновый слой (я использую Leaflet CRS Simple), не более эффективна.

Вот мои характеристики изображения:

  • ширина: 21002 пикс.
  • высота: 14694 пикс.
  • разрешение: 0,02 (1 метр = 50 пикселей)

Вот границы моего изображения при использовании ImageOverlay:  введите описание изображения здесь

Вот границы моего изображения при использовании TileLayer:  введите описание изображения здесь

И вот как это выглядит, когда я показываю их вместе:  введите описание изображения здесь

Кто-нибудь знает, что происходит?


person Martin Tovmassian    schedule 19.03.2019    source источник
comment
Как вы использовали gdal2tiles именно? Какие параметры вы использовали?   -  person IvanSanchez    schedule 19.03.2019
comment
Я назвал это так gdal2tiles.py -l -p raster -z 0-5 -w none image.png   -  person Martin Tovmassian    schedule 19.03.2019
comment
Похоже на проблему TMS vs XYZ, но, не видя кода, сложно сказать. В конструкторе TileLayer есть опция tms, по умолчанию она равна false.   -  person LuisTavares    schedule 19.03.2019
comment
Вот как я инициализирую свой TileLayer: const tileLayer = new L.TileLayer('./assets/mapping-assets/image/{z}/{x}/{y}.png').addTo(map); Я попытался переключить опцию tms, но результат остался прежним.   -  person Martin Tovmassian    schedule 19.03.2019
comment
И должны ли мы предполагать, что единицы для желаемых координат (те, которые указаны в случае ImageOverlay) выражены в метрах?   -  person IvanSanchez    schedule 19.03.2019
comment
Да, это правильно   -  person Martin Tovmassian    schedule 19.03.2019
comment
Возможно, вас заинтересует stackoverflow.com/questions/44054833/   -  person ghybs    schedule 20.03.2019


Ответы (1)


Как было предложено @TomazicM, я исследовал плагин leaflet-rastercoords, который является дополнением к gdal2tiles-leaflet. На его основе я реализовал API, который позволяет преобразовывать координаты в растровый или декартовый способ.

Для этого я сначала делаю код leaflet-rastercoords доступным в едином методе:

export let loadLeafletRastercoordsPlugin = (L: any) => {
    // rastercoords.js source code
}

Затем я написал класс для преобразования координат:

import * as L from 'leaflet';
import { loadLeafletRastercoordsPlugin } from './leaflet-rastercoords';

export class RasterCoords {

    public rc: any;
    public map: L.Map;
    public rasterWidth: number;
    public rasterHeight: number;
    public resolution: number;

    constructor(map: L.Map, rasterWidth: number, rasterHeight: number, resolution: number) {
        loadLeafletRastercoordsPlugin(L);
        this.rc = new L['RasterCoords'](map, [rasterWidth, rasterHeight]);
        this.map = map;
        this.rasterWidth = rasterWidth;
        this.rasterHeight = rasterHeight;
        this.resolution = resolution;
    }

}

С помощью одного метода проецирования растровых координат в исходную ортонормированную плоскость моего изображения на основе его ширины, высоты и разрешения и путем размещения оси Y снизу вверх:

public project(coordinates: L.LatLngTuple): L.LatLngTuple {
    coordinates = this.applyResolution(coordinates);
    const projectedCoordinates = this.rc.project(
        coordinates
    );

    return this.applyCartesianProjection([projectedCoordinates.y, projectedCoordinates.x] as L.LatLngTuple);
}

private applyResolution(coordinates: L.LatLngTuple): L.LatLngTuple {
    return coordinates.map((v: number) => v * this.resolution) as L.LatLngTuple;
}

private applyCartesianProjection(coordinates: L.LatLngTuple): L.LatLngTuple {
    return [(this.rasterHeight * this.resolution) - coordinates[0], coordinates[1]];
}

И с помощью одного метода "unproject" декартовых координат (т. Е. Повторная обработка точка за точкой, что делает метод project):

public unproject(coordinates: L.LatLngTuple): L.LatLngTuple {
    coordinates = this.unapplyResolution(this.unapplyCartesianProjection(coordinates));

    return this.rc.unproject([coordinates[1], coordinates[0]]);
}

private unapplyResolution(coordinates: L.LatLngTuple): L.LatLngTuple {
    return coordinates.map((v: number) => v / this.resolution) as L.LatLngTuple;
}

private unapplyCartesianProjection(coordinates: L.LatLngTuple): L.LatLngTuple {
    return [Math.abs(coordinates[0] - (this.rasterHeight * this.resolution)), coordinates[1]];
}

Затем API помогает мне эффективно добавлять объекты на мою карту на основе их декартовых координат:

const imageWidth = 21002;
const imageHeight = 14694;
const imageResolution = 0.02;
const map = L.map('map');
const rc = new RasterCoords(map, imageWidth, imageHeight, imageResolution);
map.setView(rc.unproject([imageWidth, imageHeight]), 2);
L.tileLayer('./image/{z}/{x}/{y}.png', {
    noWrap: true
}).addTo(map);
new L.CircleMarker(this.rc.unproject([293, 420])).addTo(map);
person Martin Tovmassian    schedule 21.03.2019