(英国の)トリミングされた地図上のXおよびYへのメルカトルの経度と緯度計算
-
21-09-2019 - |
質問
私はこのイメージを持っています: http://imgur.com/99tsz.png. 。英国の地図(アイルランド南部を含む)。
私は緯度と経度を取得することに成功し、英国の左上経度と右端の経度をとり、それらを使用して地図の上に置く場所を解決することでこのマップにそれをプロットすることに成功しました。
これはコードです(process.jsで使用しますが、JSなどとして使用できます):
// Size of the map
int width = 538;
int height = 811;
// X and Y boundaries
float westLong = -8.166667;
float eastLong = 1.762833;
float northLat = 58.666667;
float southLat = 49.95;
void drawPoint(float latitude, float longitude){
fill(#000000);
x = width * ((westLong-longitude)/(westLong-eastLong));
y = (height * ((northLat-latitude)/(northLat-southLat)));
console.log(x + ", " + y);
ellipseMode(RADIUS);
ellipse(x, y, 2, 2);
}
ただし、これらの値にメルカトル投影を実装することはできませんでした。プロットはかなり正確ですが、十分ではなく、この投影はそれを解決します。
私はそれをする方法を理解できません。私が見つけたすべての例は、全世界のためにそれを行う方法を説明することです。 これ 予測を実装する方法を説明する例の良いリソースですが、私はそれを機能させることができませんでした。
別のリソースはです 英国の極端なポイント 英国周辺の境界ボックスの緯度と経度の値が得られました。彼らもここにいます:
northLat = 58.666667;
northLong = -3.366667;
eastLat = 52.481167;
eastLong = 1.762833;
southLat = 49.95;
southLong = -5.2;
westLat = 54.45;
westLong = -8.166667;
誰かがこれで私を助けることができれば、私はそれを大いに感謝します!
ありがとう
解決
すべてのフラットマップがメルカトルの投影ではないことを心に留めておくのは価値があると思います。特にそのマップについてもっと知ることなく、確信するのは難しいです。世界の小さな地域のほとんどの地図は、 円錐形 マップ上の関心のある領域がグローバルなメルカトル投影よりも「平坦」であるプロジェクションを入力します。これは、赤道から遠ざかるほど特に重要です(そして、英国はそれが重要であるために十分に離れています)。
試している計算を使用して「十分に近づく」ことができるかもしれませんが、最良の精度では、明確に定義された投影を備えたマップを使用するか、独自のマップを作成することをお勧めします。
他のヒント
私はあなたが探していたものを正確に行う関数を書きました。少し遅れていることは知っていますが、興味のある人が他にもいるかもしれません。
メルカトルの投影であるマップが必要であり、マップのLat / LON位置を知る必要があります。あなたは、完全に一致するLAT / LONポジションを備えた優れたカスタマイズされたメルカトルマップを取得します ティレミル これはからのフリーソフトウェアです マップボックス!
私はこのスクリプトを使用しており、Google Earthのポジションでテストしました。ピクセルレベルで完璧に機能しました。実際、私はこれを異なるマップまたは大規模なマップでテストしませんでした。それがあなたに役立つことを願っています!
ラファエル ;)
<?php
$mapWidth = 1500;
$mapHeight = 1577;
$mapLonLeft = 9.8;
$mapLonRight = 10.2;
$mapLonDelta = $mapLonRight - $mapLonLeft;
$mapLatBottom = 53.45;
$mapLatBottomDegree = $mapLatBottom * M_PI / 180;
function convertGeoToPixel($lat, $lon)
{
global $mapWidth, $mapHeight, $mapLonLeft, $mapLonDelta, $mapLatBottom, $mapLatBottomDegree;
$x = ($lon - $mapLonLeft) * ($mapWidth / $mapLonDelta);
$lat = $lat * M_PI / 180;
$worldMapWidth = (($mapWidth / $mapLonDelta) * 360) / (2 * M_PI);
$mapOffsetY = ($worldMapWidth / 2 * log((1 + sin($mapLatBottomDegree)) / (1 - sin($mapLatBottomDegree))));
$y = $mapHeight - (($worldMapWidth / 2 * log((1 + sin($lat)) / (1 - sin($lat)))) - $mapOffsetY);
return array($x, $y);
}
$position = convertGeoToPixel(53.7, 9.95);
echo "x: ".$position[0]." / ".$position[1];
?>
これがTilemillで作成した画像で、この例で使用した画像です。
Raphael Wichmannが投稿したものに加えて(ちなみに、ありがとう!)、ActionScriptの逆関数があります。
function convertPixelToGeo(tx:Number, ty:Number):Point
{
/* called worldMapWidth in Raphael's Code, but I think that's the radius since it's the map width or circumference divided by 2*PI */
var worldMapRadius:Number = mapWidth / mapLonDelta * 360/(2 * Math.PI);
var mapOffsetY:Number = ( worldMapRadius / 2 * Math.log( (1 + Math.sin(mapLatBottomRadian) ) / (1 - Math.sin(mapLatBottomRadian)) ));
var equatorY:Number = mapHeight + mapOffsetY;
var a:Number = (equatorY-ty)/worldMapRadius;
var lat:Number = 180/Math.PI * (2 * Math.atan(Math.exp(a)) - Math.PI/2);
var long:Number = mapLonLeft+tx/mapWidth*mapLonDelta;
return new Point(lat,long);
}
Raphaelが提供したPHPコードをJavaScriptに変換しましたが、それが機能したことを確認でき、このコードは自分で機能します。ラファエルへのすべての功績。
/*
var mapWidth = 1500;
var mapHeight = 1577;
var mapLonLeft = 9.8;
var mapLonRight = 10.2;
var mapLonDelta = mapLonRight - mapLonLeft;
var mapLatBottom = 53.45;
var mapLatBottomDegree = mapLatBottom * Math.PI / 180;
*/
function convertGeoToPixel(latitude, longitude ,
mapWidth , // in pixels
mapHeight , // in pixels
mapLonLeft , // in degrees
mapLonDelta , // in degrees (mapLonRight - mapLonLeft);
mapLatBottom , // in degrees
mapLatBottomDegree) // in Radians
{
var x = (longitude - mapLonLeft) * (mapWidth / mapLonDelta);
latitude = latitude * Math.PI / 180;
var worldMapWidth = ((mapWidth / mapLonDelta) * 360) / (2 * Math.PI);
var mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(mapLatBottomDegree)) / (1 - Math.sin(mapLatBottomDegree))));
var y = mapHeight - ((worldMapWidth / 2 * Math.log((1 + Math.sin(latitude)) / (1 - Math.sin(latitude)))) - mapOffsetY);
return { "x": x , "y": y};
}
これが別のJavaScriptの実装です。これは、上記の@rob Willetのソリューションの単純化です。コンピューターされた値を関数のパラメーターとして要求する代わりに、必須の値のみを必要とし、それらからすべてを計算します。
function convertGeoToPixel(latitude, longitude,
mapWidth, // in pixels
mapHeight, // in pixels
mapLngLeft, // in degrees. the longitude of the left side of the map (i.e. the longitude of whatever is depicted on the left-most part of the map image)
mapLngRight, // in degrees. the longitude of the right side of the map
mapLatBottom) // in degrees. the latitude of the bottom of the map
{
const mapLatBottomRad = mapLatBottom * Math.PI / 180
const latitudeRad = latitude * Math.PI / 180
const mapLngDelta = (mapLngRight - mapLngLeft)
const worldMapWidth = ((mapWidth / mapLngDelta) * 360) / (2 * Math.PI)
const mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(mapLatBottomRad)) / (1 - Math.sin(mapLatBottomRad))))
const x = (longitude - mapLngLeft) * (mapWidth / mapLngDelta)
const y = mapHeight - ((worldMapWidth / 2 * Math.log((1 + Math.sin(latitudeRad)) / (1 - Math.sin(latitudeRad)))) - mapOffsetY)
return {x, y} // the pixel x,y value of this point on the map image
}
私はこの質問がしばらく前に尋ねられたことを知っていますが、proj4jsライブラリはJavaScriptのさまざまなマップ投影間を変換するのに理想的です。
英国のマップは、横方向のメルカトル投影に基づいたOSGBの国立グリッドを使用する傾向があります。すなわち。 「赤道」が子午線になるように、従来のメルカトルのように90度に変わりました。
@xarinko actionscript snippet in javascript(いくつかのテスト値を含む)
var mapWidth = 1500;
var mapHeight = 1577;
var mapLonLeft = 9.8;
var mapLonRight = 10.2;
var mapLonDelta = mapLonRight - mapLonLeft;
var mapLatBottom = 53.45;
var mapLatBottomRadian = mapLatBottom * Math.PI / 180;
function convertPixelToGeo(tx, ty)
{
/* called worldMapWidth in Raphael's Code, but I think that's the radius since it's the map width or circumference divided by 2*PI */
var worldMapRadius = mapWidth / mapLonDelta * 360/(2 * Math.PI);
var mapOffsetY = ( worldMapRadius / 2 * Math.log( (1 + Math.sin(mapLatBottomRadian) ) / (1 - Math.sin(mapLatBottomRadian)) ));
var equatorY = mapHeight + mapOffsetY;
var a = (equatorY-ty)/worldMapRadius;
var lat = 180/Math.PI * (2 * Math.atan(Math.exp(a)) - Math.PI/2);
var long = mapLonLeft+tx/mapWidth*mapLonDelta;
return [lat,long];
}
convertPixelToGeo(241,444)
proj4jsに固有のLAT/LNG投影の厄介な側面のいくつかを避けたい場合は、D3を使用できます。これは、多くの焼き投影を提供し、美しくレンダリングすることができます。これが次のとおりです インタラクティブな例 方位角突起のいくつかのフレーバーの。私はアメリカのマップにはアルバースが好きです。
D3がエンドユーザーオプションではない場合 - たとえば、IE 7/8をサポートする必要があります - D3でレンダリングしてから、D3が生成する結果のSVGファイルからXY座標を引っ掛けることができます。その後、ラファエルでこれらのXY座標をレンダリングできます。
プロットしたいマップに基づいてmapheightを定義したいので、この関数は私にとって最適です。 PDFマップを生成しています。私がしなければならないのは、マップの最大LAT、MIN LONで渡され、マップのピクセルサイズを[高さ、幅]として返します。
convertgeotopixel(maxlatitude、maxlongitude)
$ yが設定されている最後のステップでは、座標系 'xy'が下/左から起動する場合、pdfsのように左から始まる場合、mapheightの計算を差し引かないでください。これによりマップが反転します。
$y = (($worldMapWidth / 2 * log((1 + sin($lat)) / (1 - sin($lat)))) - $mapOffsetY);
C#実装:
private Point ConvertGeoToPixel(
double latitude, double longitude, // The coordinate to translate
int imageWidth, int imageHeight, // The dimensions of the target space (in pixels)
double mapLonLeft, double mapLonRight, double mapLatBottom // The bounds of the target space (in geo coordinates)
) {
double mapLatBottomRad = mapLatBottom * Math.PI / 180;
double latitudeRad = latitude * Math.PI / 180;
double mapLonDelta = mapLonRight - mapLonLeft;
double worldMapWidth = (imageWidth / mapLonDelta * 360) / (2 * Math.PI);
double mapOffsetY = worldMapWidth / 2 * Math.Log((1 + Math.Sin(mapLatBottomRad)) / (1 - Math.Sin(mapLatBottomRad)));
double x = (longitude - mapLonLeft) * (imageWidth / mapLonDelta);
double y = imageHeight - ((worldMapWidth / 2 * Math.Log((1 + Math.Sin(latitudeRad)) / (1 - Math.Sin(latitudeRad)))) - mapOffsetY);
return new Point()
{
X = Convert.ToInt32(x),
Y = Convert.ToInt32(y)
};
}