17

たとえば、次のリクエストで返されたGoogle静的マップの度数で境界を取得する方法

http://maps.googleapis.com/maps/api/staticmap?center=0.0,0.0&zoom=10&size=640x640&sensor=false

私が知っているように、完全な地球地図は 256x256 の画像です。これは、n 垂直ピクセルには x 度が含まれますが、n 水平ピクセルには 2x 度が含まれることを意味します。右?

グーグルが言うよう に、中心は地図の中心を定義し、地図のすべての端から等距離です。私が理解したように、等距離はピクセル単位(または度単位?)です。また、ズーム レベルが上がるごとに、水平方向と垂直方向の両方の寸法の精度が 2 倍になります。したがって、ズーム値ごとにマップの経度のデルタ値を次のように見つけることができます。

dLongitude = (HorizontalMapSizeInPixels / 256 ) * ( 360 / pow(2, zoom) );

緯度の同じ計算:

dLatitude = (VerticalMapSizeInPixels / 256 ) * ( 180 / pow(2, zoom) );

VerticalMapSizeInPixels と Horizo​​ntalMapSizeInPixels は、URL のマップ サイズのパラメーターです。

経度のデルタ値を計算するのは良いのですが、緯度の場合は間違っています。Latitude のデルタ値が見つかりません。デルタエラーがあります。

4

6 に答える 6

33

私が知っているように、完全な地球地図は 256x256 の画像です。

はい。

これは、n 垂直ピクセルには x 度が含まれますが、n 水平ピクセルには 2x 度が含まれることを意味します。右?

いいえ。1 つのピクセルは、緯度に応じてさまざまな量の緯度を表します。赤道の 1 ピクセルは、極近くの 1 ピクセルよりも緯度が低いことを表します。

マップのコーナーは中心、ズーム レベル、マップ サイズによって異なり、メルカトル図法を使用して計算する必要があります。完全な API をロードしたくない場合は、MercatorProjection オブジェクトを次に示します。

var MERCATOR_RANGE = 256;

function bound(value, opt_min, opt_max) {
  if (opt_min != null) value = Math.max(value, opt_min);
  if (opt_max != null) value = Math.min(value, opt_max);
  return value;
}

function degreesToRadians(deg) {
  return deg * (Math.PI / 180);
}

function radiansToDegrees(rad) {
  return rad / (Math.PI / 180);
}

function MercatorProjection() {
  this.pixelOrigin_ = new google.maps.Point( MERCATOR_RANGE / 2, MERCATOR_RANGE / 2);
  this.pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
  this.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * Math.PI);
};

MercatorProjection.prototype.fromLatLngToPoint = function(latLng, opt_point) {
  var me = this;

  var point = opt_point || new google.maps.Point(0, 0);

  var origin = me.pixelOrigin_;
  point.x = origin.x + latLng.lng() * me.pixelsPerLonDegree_;
  // NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
  // 89.189.  This is about a third of a tile past the edge of the world tile.
  var siny = bound(Math.sin(degreesToRadians(latLng.lat())), -0.9999, 0.9999);
  point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) * -me.pixelsPerLonRadian_;
  return point;
};

MercatorProjection.prototype.fromPointToLatLng = function(point) {
  var me = this;

  var origin = me.pixelOrigin_;
  var lng = (point.x - origin.x) / me.pixelsPerLonDegree_;
  var latRadians = (point.y - origin.y) / -me.pixelsPerLonRadian_;
  var lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2);
  return new google.maps.LatLng(lat, lng);
};

//pixelCoordinate = worldCoordinate * Math.pow(2,zoomLevel)

これを「MercatorProjection.js」などの別のファイルに保存して、アプリケーションに含めることができます。

<script src="MercatorProjection.js"></script>

上記のファイルをロードすると、次の関数は、指定されたサイズとズームでマップの SW と NE のコーナーを計算します。

function getCorners(center,zoom,mapWidth,mapHeight){
    var scale = Math.pow(2,zoom);
    var centerPx = proj.fromLatLngToPoint(center);
    var SWPoint = {x: (centerPx.x -(mapWidth/2)/ scale) , y: (centerPx.y + (mapHeight/2)/ scale)};
    var SWLatLon = proj.fromPointToLatLng(SWPoint);
    alert('SW: ' + SWLatLon);
    var NEPoint = {x: (centerPx.x +(mapWidth/2)/ scale) , y: (centerPx.y - (mapHeight/2)/ scale)};
    var NELatLon = proj.fromPointToLatLng(NEPoint);
    alert(' NE: '+ NELatLon);
}

次のように呼び出します。

var proj = new MercatorProjection();
var G = google.maps;
var centerPoint = new G.LatLng(49.141404, -121.960988);
var zoom = 10;
getCorners(centerPoint,zoom,640,640);
于 2012-09-20T11:38:44.477 に答える
2

これは PHP での Marcelo のコードの行ごとの翻訳です。これはおそらく少しきれいにすることができます。よく働く!大変なことをしてくれた Marcelo に感謝します。

define("MERCATOR_RANGE", 256);

function degreesToRadians($deg) {
  return $deg * (M_PI / 180);
}

function radiansToDegrees($rad) {
  return $rad / (M_PI / 180);
}

function bound($value, $opt_min, $opt_max) {
  if ($opt_min != null) $value = max($value, $opt_min);
  if ($opt_max != null) $value = min($value, $opt_max);
  return $value;
}

class G_Point {
    public $x,$y;
    function G_Point($x=0, $y=0){
        $this->x = $x;
        $this->y = $y;
    }
}

class G_LatLng {
    public $lat,$lng;
    function G_LatLng($lt, $ln){
        $this->lat = $lt;
        $this->lng = $ln;
    }
}

class MercatorProjection {

    private $pixelOrigin_, $pixelsPerLonDegree_, $pixelsPerLonRadian_;

    function MercatorProjection() {
      $this->pixelOrigin_ = new G_Point( MERCATOR_RANGE / 2, MERCATOR_RANGE / 2);
      $this->pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
      $this->pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * M_PI);
    }

    public function fromLatLngToPoint($latLng, $opt_point=null) {
      $me = $this;

      $point = $opt_point ? $opt_point : new G_Point(0,0);

      $origin = $me->pixelOrigin_;
      $point->x = $origin->x + $latLng->lng * $me->pixelsPerLonDegree_;
      // NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
      // 89.189.  This is about a third of a tile past the edge of the world tile.
      $siny = bound(sin(degreesToRadians($latLng->lat)), -0.9999, 0.9999);
      $point->y = $origin->y + 0.5 * log((1 + $siny) / (1 - $siny)) * -$me->pixelsPerLonRadian_;
      return $point;
    }

    public function fromPointToLatLng($point) {
      $me = $this;

      $origin = $me->pixelOrigin_;
      $lng = ($point->x - $origin->x) / $me->pixelsPerLonDegree_;
      $latRadians = ($point->y - $origin->y) / -$me->pixelsPerLonRadian_;
      $lat = radiansToDegrees(2 * atan(exp($latRadians)) - M_PI / 2);
      return new G_LatLng($lat, $lng);
    }

    //pixelCoordinate = worldCoordinate * pow(2,zoomLevel)
}

function getCorners($center, $zoom, $mapWidth, $mapHeight){
    $scale = pow(2, $zoom);
    $proj = new MercatorProjection();
    $centerPx = $proj->fromLatLngToPoint($center);
    $SWPoint = new G_Point($centerPx->x-($mapWidth/2)/$scale, $centerPx->y+($mapHeight/2)/$scale);
    $SWLatLon = $proj->fromPointToLatLng($SWPoint);
    $NEPoint = new G_Point($centerPx->x+($mapWidth/2)/$scale, $centerPx->y-($mapHeight/2)/$scale);
    $NELatLon = $proj->fromPointToLatLng($NEPoint);
    return array(
        'N' => $NELatLon->lat,
        'E' => $NELatLon->lng,
        'S' => $SWLatLon->lat,
        'W' => $SWLatLon->lng,
    );
}

使用法:

$centerLat = 49.141404;
$centerLon = -121.960988;
$zoom = 10;
$mapWidth = 640;
$mapHeight = 640;
$centerPoint = new G_LatLng($centerLat, $centerLon);
$corners = getCorners($centerPoint, $zoom, $mapWidth, $mapHeight);
$mapURL = "http://maps.googleapis.com/maps/api/staticmap?center={$centerLat},{$centerLon}&zoom={$zoom}&size={$mapWidth}x{$mapHeight}&scale=2&maptype=roadmap&sensor=false";
于 2013-10-31T17:01:50.237 に答える
1

大きなズーム倍率 (>=8) の場合、y 軸上のマップ スケールの不均一性を無視できるため、はるかに簡単な方法があります。ピクセル/(緯度の度数) の 1/cos(緯度) 補正を考慮するだけです。 ) 解像度。zoom=0 の初期解像度は、緯度 0 での x と y の両方で 360 度あたり 256 ピクセルです。

def get_static_map_bounds(lat, lng, zoom, sx, sy):
    # lat, lng - center
    # sx, sy - map size in pixels

    # 256 pixels - initial map size for zoom factor 0
    sz = 256 * 2 ** zoom

    #resolution in degrees per pixel
    res_lat = cos(lat * pi / 180.) * 360. / sz
    res_lng = 360./sz

    d_lat = res_lat * sy / 2
    d_lng = res_lng * sx / 2

    return ((lat-d_lat, lng-d_lng), (lat+d_lat, lng+d_lng))
于 2017-11-30T17:32:15.113 に答える
0

これは、より厳密な Pascal 言語とメモリ管理に対応するためにいくつかの最適化を行った Delphi/Pascal への翻訳です。

unit Mercator.Google.Maps;

interface

uses System.Math;

type TG_Point = class(TObject)
    private
        Fx: integer;
        Fy: integer;
    public
        property x: integer read Fx write Fx;
        property y: integer read Fy write Fy;

        constructor Create(Ax: integer = 0; Ay: integer = 0);
end;

type TG_LatLng = class(TObject)
    private
        FLat: double;
        FLng: double;
    public
        property Lat: double read FLat write FLat;
        property Lng: double read FLng write FLng;

        constructor Create(ALat: double; ALng: double);
end;

type TMercatorProjection = class(TObject)
    private
        pixelOrigin_: TG_Point;
        pixelsPerLonDegree_, pixelsPerLonRadian_: double;

        function degreesToRadians(deg: double): double;
        function radiansToDegrees(rad: double): double;
        function bound(value: double; opt_min: double; opt_max: double): double;
    public
        constructor Create;
        procedure fromLatLngToPoint(latLng: TG_LatLng; var point: TG_Point);
        procedure fromPointToLatLng(point: TG_point; var latLng: TG_LatLng);
        procedure getCorners(center: TG_LatLng; zoom: integer; mapWidth: integer; mapHeight: integer;
                             var NELatLon: TG_LatLng; var SWLatLon: TG_LatLng);
end;

implementation

const MERCATOR_RANGE = 256;

constructor TG_Point.Create(Ax: Integer = 0; Ay: Integer = 0);
begin
     inherited Create;
     Fx := Ax;
     Fy := Ay
end;

// **************

constructor TG_LatLng.Create(ALat: double; ALng: double);
begin
     inherited Create;
     FLat := ALat;
     FLng := ALng
end;

// **************

constructor TMercatorProjection.Create;
begin
    inherited Create;

    pixelOrigin_ := TG_Point.Create( Round(MERCATOR_RANGE / 2), Round(MERCATOR_RANGE / 2));
    pixelsPerLonDegree_ := MERCATOR_RANGE / 360;
    pixelsPerLonRadian_ := MERCATOR_RANGE / (2 * PI);
end;

// Translate degrees to radians
function TMercatorProjection.degreesToRadians(deg: double): double;
begin
  Result := deg * (PI / 180);
end;

// Translate radians to degrees
function TMercatorProjection.radiansToDegrees(rad: double): double;
begin
  Result := rad / (PI / 180);
end;

// keep value insid defined bounds
function TMercatorProjection.bound(value: double; opt_min: double; opt_max: double): double;
begin
  if Value < opt_min then Result := opt_min
  else if Value > opt_max then Result := opt_max
  else Result := Value;
end;

procedure TMercatorProjection.fromLatLngToPoint(latLng: TG_LatLng; var point: TG_Point);
var
    siny: double;
begin
   if Assigned(point) then
   begin
      point.x := Round(pixelOrigin_.x + latLng.lng * pixelsPerLonDegree_);
      // NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
      // 89.189.  This is about a third of a tile past the edge of the world tile.
      siny := bound(sin(degreesToRadians(latLng.lat)), -0.9999, 0.9999);
      point.y := Round(pixelOrigin_.y + 0.5 * ln((1 + siny) / (1 - siny)) * -pixelsPerLonRadian_);
   end;
end;

procedure TMercatorProjection.fromPointToLatLng(point: TG_point; var latLng: TG_LatLng);
var
    latRadians: double;
begin
    if Assigned(latLng) then
    begin
      latLng.lng := (point.x - pixelOrigin_.x) / pixelsPerLonDegree_;
      latRadians := (point.y - pixelOrigin_.y) / -pixelsPerLonRadian_;
      latLng.lat := radiansToDegrees(2 * arctan(exp(latRadians)) - PI / 2);
    end;
end;

//pixelCoordinate = worldCoordinate * pow(2,zoomLevel)

procedure TMercatorProjection.getCorners(center: TG_LatLng; zoom: integer; mapWidth: integer; mapHeight: integer;
                     var NELatLon: TG_LatLng; var SWLatLon: TG_LatLng);
var
    scale: double;
    centerPx, SWPoint, NEPoint: TG_Point;
begin
    scale := power(2, zoom);

    centerPx := TG_Point.Create(0, 0);
    try
        fromLatLngToPoint(center, centerPx);
        SWPoint := TG_Point.Create(Round(centerPx.x-(mapWidth/2)/scale), Round(centerPx.y+(mapHeight/2)/scale));
        NEPoint := TG_Point.Create(Round(centerPx.x+(mapWidth/2)/scale), Round(centerPx.y-(mapHeight/2)/scale));
        try
            fromPointToLatLng(SWPoint, SWLatLon);
            fromPointToLatLng(NEPoint, NELatLon);
        finally
            SWPoint.Free;
            NEPoint.Free;
        end;
    finally
        centerPx.Free;
    end;
end;

end.

使用例:

            with TMercatorProjection.Create do
            try
                CLatLon := TG_LatLng.Create(Latitude, Longitude);
                SWLatLon := TG_LatLng.Create(0,0);
                NELatLon := TG_LatLng.Create(0,0);
                try
                    getCorners(CLatLon, Zoom,
                                MapWidth, MapHeight,
                                SWLatLon, NELatLon);
                finally
                    ShowMessage('SWLat='+FloatToStr(SWLatLon.Lat)+' | SWLon='+FloatToStr(SWLatLon.Lng));
                    ShowMessage('NELat='+FloatToStr(NELatLon.Lat)+' | NELon='+FloatToStr(NELatLon.Lng));

                    SWLatLon.Free;
                    NELatLon.Free;
                    CLatLon.Free;
                end;
            finally
                Free;
            end;
于 2016-05-11T14:17:02.703 に答える