基于带有 openlayers 的 WMS `GetTile` 请求的 TileWMS -> TileLayer -> Map -> View 仅复制地图上的相同图块
An TileWMS -> TileLayer -> Map -> View based on a WMS `GetTile` request with openlayers only duplicates the same tile on the map
直到 2020 年,我一直在使用 Openlayers 显示 IGN 地图,代码如下:
import { Component, OnInit, Input } from '@angular/core';
import Map from 'ol/Map';
import View from 'ol/View';
import TileWMS from 'ol/source/TileWMS';
import * as olProj from 'ol/proj';
import TileLayer from 'ol/layer/Tile';
@Component({
selector: 'carte',
templateUrl: './carte.component.html',
styleUrls: ['./carte.component.css']
})
export class CarteComponent implements OnInit {
/** Carte Openlayers. */
map: Map;
/* Longitude. */
@Input() longitude: number;
/* Latitude. */
@Input() latitude: number;
/** Niveau de zoom initial. */
@Input() zoom: number;
constructor() {
}
ngOnInit(): void {
var ign_source = new TileWMS({
url: 'http://wxs.ign.fr/cdw20cou9clqe59fvn39rmcu/geoportail/r/wms',
params: {'LAYERS': 'GEOGRAPHICALGRIDSYSTEMS.PLANIGN', 'TILED': false}
});
var ign = new TileLayer({
source: ign_source
});
this.map = new Map({
target: "carte_principale",
view: new View({
center: olProj.fromLonLat([this.longitude, this.latitude]),
zoom: this.zoom
})
});
this.map.addLayer(ign);
}
}
然后 IGN geoportail 做了几个月的大改动,当它返回时,我不得不调整我的代码才能再次使用它。
它的文档看起来使用 GetTile
请求来显示地图,而不是之前建议使用的 GetMap
。
根据它,我以这种方式更改了我的代码:
ngOnInit(): void {
const planIGN = new TileWMS( {
url: 'https://wxs.ign.fr/decouverte/geoportail/wmts',
params: {
REQUEST: 'GetTile',
VERSION: '1.0.0',
LAYER: 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2',
STYLE: 'normal',
FORMAT: 'image/png',
SERVICE: 'WMTS',
TILEMATRIX: 14,
TILEMATRIXSET: 'PM',
TILECOL: 8180,
TILEROW: 5905
}});
const ign = new TileLayer({
source: planIGN
});
this.map = new Map({
target: 'carte_principale',
view: new View({
center: olProj.fromLonLat([this.longitude, this.latitude]),
zoom: this.zoom
})
});
this.map.addLayer(ign);
}
有效...但显示效果与预期不符:
- 同一图块在地图上重复。
- latitude/longitude 未解决
- 缩放无效
最后两点,因为我不知道如何正确地参数化请求。
当我尝试使用其网络工具显示 QGis(地图显示正常)时,它看到交换了那种请求,所以我还没有到现在:
https://wxs.ign.fr/decouverte/geoportail/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2&STYLE=normal&FORMAT=image/png&TILEMATRIXSET=PM&TILEMATRIX=13&TILEROW=2946&TILECOL=4093
Openlayers 很强大,但对我来说常常很棘手:
我应该改变什么以获得更好的行为?
结语:在@Solomon 和其他人回答了我的问题后,这里是我最终生成并有效的代码:
import { Component, OnInit, Input } from '@angular/core';
import Map from 'ol/Map';
import View from 'ol/View';
import Tile from 'ol/layer/Tile';
import TileLayer from 'ol/layer/Tile';
import WMTS from 'ol/source/WMTS';
import WMTSTileGrid from 'ol/tilegrid/WMTS';
import {fromLonLat, get as getProjection} from 'ol/proj';
import {getWidth, getTopLeft} from 'ol/extent';
@Component({
selector: 'carte',
templateUrl: './carte.component.html',
styleUrls: ['./carte.component.css']
})
export class CarteComponent implements OnInit {
/** Carte Openlayers. */
map: Map;
/* Longitude. */
@Input() longitude: number;
/* Latitude. */
@Input() latitude: number;
/** Niveau de zoom initial. */
@Input() zoom: number;
/** Couche Plan IGN V2 */
planIGNV2: TileLayer<WMTS> = this.couche('https://wxs.ign.fr/decouverte/geoportail/wmts', 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2',
'EPSG:3857', 'image/png');
/* Couche : Orthophotos
orthoPhotos: TileLayer<WMTS> = this.couche('https://wxs.ign.fr/decouverte/geoportail/wmts', 'ORTHOIMAGERY.ORTHOPHOTOS',
'EPSG:3857', 'image/jpeg')
*/
ngOnInit() {
const map = new Map({
layers: [ this.planIGNV2 ],
target: 'carte_principale', // id de l'élément HTML
view: new View({
center: fromLonLat([this.longitude, this.latitude]),
zoom: this.zoom
})
});
}
/**
* Crée une couche tuilée WMTS
* @param url URL
* @param layer Nom de la couche
* @param projection Projection à utiliser pour calculer la grille de tuiles (exemple : EPSG:3857)
* @param format Format d'image à utiliser.
*/
couche(url: string, layer: string, projection: string, format: string): TileLayer<WMTS> {
return new Tile({
source : new WMTS({
url,
layer,
matrixSet: 'PM',
format,
style: 'normal',
tileGrid: this.grilleTuiles(projection)
})
});
}
/**
* Renvoie une grille de tuiles
* @param projection Projection (exemple : EPSG:3857)
*/
grilleTuiles(projection: string): WMTSTileGrid {
const proj = getProjection(projection);
const maxResolution = getWidth(proj.getExtent()) / 256;
const projectionExtent = proj.getExtent();
const resolutions = [];
const matrixIds = [];
for (let i = 0; i < 20; i++) {
matrixIds[i] = i.toString();
resolutions[i] = maxResolution / Math.pow(2, i);
}
return new WMTSTileGrid( {
origin: getTopLeft(projectionExtent), // coin supérieur gauche
resolutions,
matrixIds
});
}
}
我相信你根本没有做对。
您只需要一块地砖,位于 TILECOL:8180,TILEROW:5905
的地砖
使用此代码:
const projection = ol.proj.get('EPSG:4326');
const projectionExtent = projection.getExtent();
// The matrixes start at 2 tiles wide, 1 tile high (OR WHATEVER YOU HAVE IN THE API DOCUMENTATION)
const size = ol.extent.getWidth(projectionExtent) / 256 / 2; // or ol.extent.getHeight(projectionExtent) / 256
const resolutions = new Array(12);
const matrixIds = new Array(12);
for (let z = 0; z < 12; ++z) {
// generate resolutions and matrixIds arrays for this WMTS
resolutions[z] = size / Math.pow(2, z);
matrixIds[z] = "EPSG:4326:" + z;
}
map.addLayer(new ol.layer.Tile({
source: new ol.source.WMTS({
url: <your_url_tile_provider>
projection: projection,
layer: <your layer name>,
matrixSet: 'EPSG:4326',
format: <your format>,
style: <your style>,
tileGrid : new ol.tilegrid.WMTS({
origin: ol.extent.getTopLeft(projectionExtent), // topLeftCorner
resolutions: resolutions,
matrixIds: matrixIds
}),
}),
opacity: 0.7, <whatever you want>
}));
直到 2020 年,我一直在使用 Openlayers 显示 IGN 地图,代码如下:
import { Component, OnInit, Input } from '@angular/core';
import Map from 'ol/Map';
import View from 'ol/View';
import TileWMS from 'ol/source/TileWMS';
import * as olProj from 'ol/proj';
import TileLayer from 'ol/layer/Tile';
@Component({
selector: 'carte',
templateUrl: './carte.component.html',
styleUrls: ['./carte.component.css']
})
export class CarteComponent implements OnInit {
/** Carte Openlayers. */
map: Map;
/* Longitude. */
@Input() longitude: number;
/* Latitude. */
@Input() latitude: number;
/** Niveau de zoom initial. */
@Input() zoom: number;
constructor() {
}
ngOnInit(): void {
var ign_source = new TileWMS({
url: 'http://wxs.ign.fr/cdw20cou9clqe59fvn39rmcu/geoportail/r/wms',
params: {'LAYERS': 'GEOGRAPHICALGRIDSYSTEMS.PLANIGN', 'TILED': false}
});
var ign = new TileLayer({
source: ign_source
});
this.map = new Map({
target: "carte_principale",
view: new View({
center: olProj.fromLonLat([this.longitude, this.latitude]),
zoom: this.zoom
})
});
this.map.addLayer(ign);
}
}
然后 IGN geoportail 做了几个月的大改动,当它返回时,我不得不调整我的代码才能再次使用它。
它的文档看起来使用 GetTile
请求来显示地图,而不是之前建议使用的 GetMap
。
根据它,我以这种方式更改了我的代码:
ngOnInit(): void {
const planIGN = new TileWMS( {
url: 'https://wxs.ign.fr/decouverte/geoportail/wmts',
params: {
REQUEST: 'GetTile',
VERSION: '1.0.0',
LAYER: 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2',
STYLE: 'normal',
FORMAT: 'image/png',
SERVICE: 'WMTS',
TILEMATRIX: 14,
TILEMATRIXSET: 'PM',
TILECOL: 8180,
TILEROW: 5905
}});
const ign = new TileLayer({
source: planIGN
});
this.map = new Map({
target: 'carte_principale',
view: new View({
center: olProj.fromLonLat([this.longitude, this.latitude]),
zoom: this.zoom
})
});
this.map.addLayer(ign);
}
有效...但显示效果与预期不符:
- 同一图块在地图上重复。
- latitude/longitude 未解决
- 缩放无效
最后两点,因为我不知道如何正确地参数化请求。
当我尝试使用其网络工具显示 QGis(地图显示正常)时,它看到交换了那种请求,所以我还没有到现在:
https://wxs.ign.fr/decouverte/geoportail/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2&STYLE=normal&FORMAT=image/png&TILEMATRIXSET=PM&TILEMATRIX=13&TILEROW=2946&TILECOL=4093
Openlayers 很强大,但对我来说常常很棘手:
我应该改变什么以获得更好的行为?
结语:在@Solomon 和其他人回答了我的问题后,这里是我最终生成并有效的代码:
import { Component, OnInit, Input } from '@angular/core';
import Map from 'ol/Map';
import View from 'ol/View';
import Tile from 'ol/layer/Tile';
import TileLayer from 'ol/layer/Tile';
import WMTS from 'ol/source/WMTS';
import WMTSTileGrid from 'ol/tilegrid/WMTS';
import {fromLonLat, get as getProjection} from 'ol/proj';
import {getWidth, getTopLeft} from 'ol/extent';
@Component({
selector: 'carte',
templateUrl: './carte.component.html',
styleUrls: ['./carte.component.css']
})
export class CarteComponent implements OnInit {
/** Carte Openlayers. */
map: Map;
/* Longitude. */
@Input() longitude: number;
/* Latitude. */
@Input() latitude: number;
/** Niveau de zoom initial. */
@Input() zoom: number;
/** Couche Plan IGN V2 */
planIGNV2: TileLayer<WMTS> = this.couche('https://wxs.ign.fr/decouverte/geoportail/wmts', 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2',
'EPSG:3857', 'image/png');
/* Couche : Orthophotos
orthoPhotos: TileLayer<WMTS> = this.couche('https://wxs.ign.fr/decouverte/geoportail/wmts', 'ORTHOIMAGERY.ORTHOPHOTOS',
'EPSG:3857', 'image/jpeg')
*/
ngOnInit() {
const map = new Map({
layers: [ this.planIGNV2 ],
target: 'carte_principale', // id de l'élément HTML
view: new View({
center: fromLonLat([this.longitude, this.latitude]),
zoom: this.zoom
})
});
}
/**
* Crée une couche tuilée WMTS
* @param url URL
* @param layer Nom de la couche
* @param projection Projection à utiliser pour calculer la grille de tuiles (exemple : EPSG:3857)
* @param format Format d'image à utiliser.
*/
couche(url: string, layer: string, projection: string, format: string): TileLayer<WMTS> {
return new Tile({
source : new WMTS({
url,
layer,
matrixSet: 'PM',
format,
style: 'normal',
tileGrid: this.grilleTuiles(projection)
})
});
}
/**
* Renvoie une grille de tuiles
* @param projection Projection (exemple : EPSG:3857)
*/
grilleTuiles(projection: string): WMTSTileGrid {
const proj = getProjection(projection);
const maxResolution = getWidth(proj.getExtent()) / 256;
const projectionExtent = proj.getExtent();
const resolutions = [];
const matrixIds = [];
for (let i = 0; i < 20; i++) {
matrixIds[i] = i.toString();
resolutions[i] = maxResolution / Math.pow(2, i);
}
return new WMTSTileGrid( {
origin: getTopLeft(projectionExtent), // coin supérieur gauche
resolutions,
matrixIds
});
}
}
我相信你根本没有做对。 您只需要一块地砖,位于 TILECOL:8180,TILEROW:5905
的地砖使用此代码:
const projection = ol.proj.get('EPSG:4326');
const projectionExtent = projection.getExtent();
// The matrixes start at 2 tiles wide, 1 tile high (OR WHATEVER YOU HAVE IN THE API DOCUMENTATION)
const size = ol.extent.getWidth(projectionExtent) / 256 / 2; // or ol.extent.getHeight(projectionExtent) / 256
const resolutions = new Array(12);
const matrixIds = new Array(12);
for (let z = 0; z < 12; ++z) {
// generate resolutions and matrixIds arrays for this WMTS
resolutions[z] = size / Math.pow(2, z);
matrixIds[z] = "EPSG:4326:" + z;
}
map.addLayer(new ol.layer.Tile({
source: new ol.source.WMTS({
url: <your_url_tile_provider>
projection: projection,
layer: <your layer name>,
matrixSet: 'EPSG:4326',
format: <your format>,
style: <your style>,
tileGrid : new ol.tilegrid.WMTS({
origin: ol.extent.getTopLeft(projectionExtent), // topLeftCorner
resolutions: resolutions,
matrixIds: matrixIds
}),
}),
opacity: 0.7, <whatever you want>
}));