我想在 openlayers 的地图上显示全球 UTM 网格。整个系统没有项目定义,只有各个区域。对于我的地图的投影,我想使用 EPSG:3857.Im 使用 Ol-Ext 刻度对地图和网格使用不同的投影,因为这是我的项目中需要的。有没有办法用 ol-ext 刻度线做到这一点,还是我必须开发自定义解决方案?
问问题
238 次
1 回答
0
您可以定义一个将所有 UTM 投影合并为一个的投影(例如,通过在每次增加区域时将 x 坐标添加 1000000),同时仍对该区域使用适当的 UTM 变换。
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.6.1/css/ol.css" type="text/css">
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.6.1/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.7.5/proj4.js"></script>
<link rel="stylesheet" href="https://viglino.github.io/ol-ext/dist/ol-ext.css" type="text/css">
<script src="https://viglino.github.io/ol-ext/dist/ol-ext.js"></script>
</head>
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
const utmProjs = [];
for (let zone = 1; zone <= 60; zone++) {
const code = "EPSG:" + (32600 + zone);
proj4.defs(code, "+proj=utm +zone=" + zone + " +ellps=WGS84 +datum=WGS84 +units=m +no_defs");
ol.proj.proj4.register(proj4);
utmProjs[zone] = ol.proj.get(code);
}
const llProj = ol.proj.get("EPSG:4326");
const midpointX = 500000;
const width = midpointX * 2;
function ll2utm(ll) {
const lon = (((ll[0] % 360) + 540) % 360) - 180; // normalise any wrapx
const lat = ll[1];
const zone = Math.floor((180 + lon) / 6) + 1;
const zoneCoord = ol.proj.transform([lon, lat], llProj, utmProjs[zone]);
return [zoneCoord[0] + (zone - 1) * width, zoneCoord[1]];
}
function utm2ll(coord) {
const zone = Math.floor(coord[0] / width) % 60 + 1;
const c0 = coord[0] % width;
const c1 = coord[1];
const ll = ol.proj.transform([c0, c1], utmProjs[zone], llProj);
if (Math.floor((180 + ll[0]) / 6) + 1 != zone) {
ll[0] = (zone - (c0 < midpointX ? 1 : 0)) * 6 - 180;
}
return ll;
}
const UTM = new ol.proj.Projection({
code: 'GlobalUTM',
units: 'm',
extent: [0, -10000000, 60 * width, 10000000]
});
ol.proj.addProjection(UTM);
ol.proj.addCoordinateTransforms(
llProj,
UTM,
ll2utm,
utm2ll
);
const map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
const viewProj = map.getView().getProjection();
ol.proj.addCoordinateTransforms(
viewProj,
UTM,
function(coord) {
return ll2utm(ol.proj.toLonLat(coord, viewProj));
},
function(coord) {
return ol.proj.fromLonLat(utm2ll(coord), viewProj);
},
);
map.addControl(
new ol.control.Graticule({
projection: UTM,
step: 1000,
stepCoord: 1
})
);
</script>
</body>
</html>
如果 ol-ext 刻度具有intervals
类似于 OpenLayers 刻度中的选项,而不是step
使用设置的随机倍数绘制线条
intervals: [1000, 5000, 10000, 50000, 100000, 500000]
将使区域边界清晰,同时在放大时仍显示细节。在没有该选项的情况下,您可能会使用一个step
设置为 1000 公里且笔划较宽的标线来突出显示和标记区域,而另一个标有step
区域内的详细信息为 1 公里。不幸的是,ol-ext 刻度只是在交叉点之间绘制直线,而不是计算正确的曲线,因此也会产生的 1000 公里 y 值线相对于更准确的 1 公里细节会错位。然而,它可以用于显示标签,但由于它缺少用于 x 和 y 坐标的单独标签格式化程序,因此需要额外的 x 偏移量才能区分 x 和 y 坐标。在 EPSG:3857 投影中,区域边界线可以很容易地添加到单独的矢量图层中。
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.6.1/css/ol.css" type="text/css">
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.6.1/build/ol.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.7.5/proj4.js"></script>
<link rel="stylesheet" href="https://viglino.github.io/ol-ext/dist/ol-ext.css" type="text/css">
<script src="https://viglino.github.io/ol-ext/dist/ol-ext.js"></script>
</head>
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
const utmProjs = [];
for (let zone = 1; zone <= 60; zone++) {
const code = "EPSG:" + (32600 + zone);
proj4.defs(code, "+proj=utm +zone=" + zone + " +ellps=WGS84 +datum=WGS84 +units=m +no_defs");
ol.proj.proj4.register(proj4);
utmProjs[zone] = ol.proj.get(code);
}
const llProj = ol.proj.get("EPSG:4326");
const midpointX = 500000;
const width = midpointX * 2;
const xOffset = 100 * 60 * width;
function ll2utm(ll) {
//const world = Math.floor((ll[0] + 180) / 360);
const lon = (((ll[0] % 360) + 540) % 360) - 180; // normalise any wrapx
const lat = ll[1];
const zone = Math.floor((180 + lon) / 6) + 1;
const zoneCoord = ol.proj.transform([lon, lat], llProj, utmProjs[zone]);
const coord = [xOffset + zoneCoord[0] + (zone - 1) * width, zoneCoord[1]];
//coord[0] += world * 60 * width;
return coord;
}
function utm2ll(coord) {
//const world = Math.floor((coord[0] - xOffset) / (60 * width));
const zone = Math.floor(coord[0] / width) % 60 + 1;
const c0 = coord[0] % width;
const c1 = coord[1];
const ll = ol.proj.transform([c0, c1], utmProjs[zone], llProj);
if (Math.floor((180 + ll[0]) / 6) + 1 != zone) {
ll[0] = (zone - (c0 < midpointX ? 1 : 0)) * 6 - 180;
}
//ll[0] += world * 360;
return ll;
}
const UTM = new ol.proj.Projection({
code: 'GlobalUTM',
units: 'm',
extent: [xOffset, -10000000, xOffset + 60 * width, 10000000],
//global: true
});
ol.proj.addProjection(UTM);
ol.proj.addCoordinateTransforms(
llProj,
UTM,
ll2utm,
utm2ll
);
const map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
const viewProj = map.getView().getProjection();
ol.proj.addCoordinateTransforms(
viewProj,
UTM,
function(coord) {
return ll2utm(ol.proj.toLonLat(coord, viewProj));
},
function(coord) {
return ol.proj.fromLonLat(utm2ll(coord), viewProj);
},
);
const features = [
new ol.Feature(
new ol.geom.LineString([[-180, 0], [180, 0]]).transform(llProj, viewProj)
)
];
for (let i = -180; i <= 180; i += 6) {
features.push(
new ol.Feature(
new ol.geom.LineString([[i, -85], [i, 85]]).transform(llProj, viewProj)
)
);
};
map.addLayer(
new ol.layer.Vector({
source: new ol.source.Vector({
features: features
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'black',
width: 3
}),
})
})
);
map.addControl(
new ol.control.Graticule({
projection: UTM,
step: 1000,
stepCoord: 1,
formatCoord: function(coord) {
if (coord % width == 0) {
return '';
} else {
return (20000 + (coord % width) / 1000).toString().slice(2);
}
},
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'black',
width: 1
}),
fill: new ol.style.Fill({
color: 'white'
}),
text: new ol.style.Text({
stroke: new ol.style.Stroke({
color: 'white',
width: 3
}),
fill: new ol.style.Fill({
color: 'black'
}),
font: 'bold 12px Arial, Helvetica, Helvetica, sans-serif',
})
})
})
);
map.addControl(
new ol.control.Graticule({
projection: UTM,
step: width,
stepCoord: 1,
formatCoord: function(coord) {
if (coord < 0) {
return 'S' + (20 + coord / width).toString().slice(1);
} else if (coord < xOffset) {
return 'N' + (20 + coord / width).toString().slice(1);
} else {
return 'Z' + (100 + Math.floor(coord / width) % 60 + 1).toString().slice(1);
}
},
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'transparent',
width: 1
}),
fill: new ol.style.Fill({
color: 'transparent'
}),
text: new ol.style.Text({
stroke: new ol.style.Stroke({
color: 'white',
width: 3
}),
fill: new ol.style.Fill({
color: 'black'
}),
font: 'bold 15px Arial, Helvetica, Helvetica, sans-serif',
})
})
})
);
</script>
</body>
</html>
于 2021-08-16T15:44:52.337 回答