计算OpenStreetMap的边界框。

问题描述 投票:2回答:2

是否可以通过坐标(经纬度)、缩放级别和大小(屏幕)来获取边界框?我只找到了 根据瓦片计算边框. 我需要它,因为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米的中心。

openstreetmap
2个回答
3
投票

是的,是这样的。我也遇到过类似的问题,所以我把它写出来了。像这样。

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,这样以后会更容易找到......


0
投票

我试着实现了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];
  }

}

它(有点)能用,不过由于某些原因,地图定位并不完全正确。

© www.soinside.com 2019 - 2024. All rights reserved.