是否可以通过坐标(经纬度)、缩放级别和大小(屏幕)来获取边界框?我只找到了 根据瓦片计算边框. 我需要它,因为OpenStreetMap在导出模式下只接受bbox。我没有任何经验,所以我将很高兴得到任何建议。谢谢。
编辑一下。
对不起,我描述错了。我写的是这样的。
(伪代码)`
x = getX(longitude, zoom); //X Tile - return 41870
y = getY(latitude, zoom); //Y Tile - return 22226
north = getXToLongitude(x, zoom); //return 49.998779
south = getXToLongitude(x + 1, zoom); //return 50.004272
west = getYToLatitude(y, zoom); //return 49.997078
east = getYToLatitude(y + 1, zoom); //return 50.000609
`
但这是非常不准确的,并且移动了100米的中心。
是的,是这样的。我也遇到过类似的问题,所以我把它写出来了。像这样。
use Math::Trig;
sub getTileNumber {
my ($lat,$lon,$zoom) = @_;
my $xtile = int( ($lon+180)/360 * 2**$zoom ) ;
my $ytile = int( (1 - log(tan(deg2rad($lat)) + sec(deg2rad($lat)))/pi)/2 * 2**$zoom ) ;
return ($xtile, $ytile);
}
sub getLonLat {
my ($xtile, $ytile, $zoom) = @_;
my $n = 2 ** $zoom;
my $lon_deg = $xtile / $n * 360.0 - 180.0;
my $lat_deg = rad2deg(atan(sinh(pi * (1 - 2 * $ytile / $n))));
return ($lon_deg, $lat_deg);
}
# convert from permalink OSM format like:
# http://www.openstreetmap.org/?lat=43.731049999999996&lon=15.79375&zoom=13&layers=M
# to OSM "Export" iframe embedded bbox format like:
# http://www.openstreetmap.org/export/embed.html?bbox=15.7444,43.708,15.8431,43.7541&layer=mapnik
sub LonLat_to_bbox {
my ($lat, $lon, $zoom) = @_;
my $width = 425; my $height = 350; # note: must modify this to match your embed map width/height in pixels
my $tile_size = 256;
my ($xtile, $ytile) = getTileNumber ($lat, $lon, $zoom);
my $xtile_s = ($xtile * $tile_size - $width/2) / $tile_size;
my $ytile_s = ($ytile * $tile_size - $height/2) / $tile_size;
my $xtile_e = ($xtile * $tile_size + $width/2) / $tile_size;
my $ytile_e = ($ytile * $tile_size + $height/2) / $tile_size;
my ($lon_s, $lat_s) = getLonLat($xtile_s, $ytile_s, $zoom);
my ($lon_e, $lat_e) = getLonLat($xtile_e, $ytile_e, $zoom);
my $bbox = "$lon_s,$lat_s,$lon_e,$lat_e";
return $bbox;
}
我还把这个信息加到了 OSM wiki,这样以后会更容易找到......
我试着实现了Angular组件的OSM嵌入,基于代码样本从 OSM. 结果是相当困难的 :(
这是我目前的代码。
import { Component, Input, OnInit } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'app-osm',
templateUrl: './osm.component.html',
styleUrls: ['./osm.component.scss']
})
export class OsmComponent implements OnInit {
@Input() latitude: number;
@Input() longitude: number;
@Input() zoom: number;
public iframeSrc;
public extMapSrc;
constructor(
private sanitizer: DomSanitizer
) { }
ngOnInit(): void {
const bbox = this.boundaryBox(this.latitude, this.longitude, 1100, 400, 16);
this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(
`https://www.openstreetmap.org/export/embed.html` +
`?bbox=${bbox.join(',')}` +
`&layer=mapnik` +
`&marker=${this.latitude},${this.longitude}`
);
this.extMapSrc = this.sanitizer.bypassSecurityTrustUrl(
`https://www.openstreetmap.org/` +
`?mlat=${this.latitude}&mlon=${this.longitude}` +
`#map=17/${this.latitude}/${this.longitude}`
);
}
lonToTile(lon: number, zoom: number): number {
return (Math.floor((lon + 180) / 360 * Math.pow(2, zoom)));
}
latToTile(lat: number, zoom: number): number {
return Math.floor(
(1 - Math.log(
Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)
) / Math.PI) / 2 * Math.pow(2, zoom)
);
}
tileToLon(x: number, zoom: number): number {
return (x / Math.pow(2, zoom) * 360 - 180);
}
tileToLat(y: number, zoom: number): number {
const n = Math.PI - 2 * Math.PI * y / Math.pow(2, zoom);
return (180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
}
boundaryBox(
lat: number,
lon: number,
width: number = 1110,
height: number = 400,
zoom: number = 17,
) {
const tileSize = 256;
const lonTile = this.lonToTile(lon, zoom);
const latTile = this.latToTile(lat, zoom);
const minLonTile = (lonTile * tileSize - width / 2) / tileSize;
const minLatTile = (latTile * tileSize - height / 2) / tileSize;
const maxLonTile = (lonTile * tileSize + width / 2) / tileSize;
const maxLatTile = (latTile * tileSize + height / 2) / tileSize;
const minLon = this.tileToLon(minLonTile, zoom);
const minLat = this.tileToLat(minLatTile, zoom);
const maxLon = this.tileToLon(maxLonTile, zoom);
const maxLat = this.tileToLat(maxLatTile, zoom);
return [minLon, minLat, maxLon, maxLat];
}
}
它(有点)能用,不过由于某些原因,地图定位并不完全正确。