我想一個類,可以在一個系統轉換爲另一種。地理座標變換
我發現Python中的源代碼,並試圖將它移植到C#。
這是Python源。 From here
import math
class GlobalMercator(object):
def __init__(self, tileSize=256):
"Initialize the TMS Global Mercator pyramid"
self.tileSize = tileSize
self.initialResolution = 2 * math.pi * 6378137/self.tileSize
# 156543.03392804062 for tileSize 256 pixels
self.originShift = 2 * math.pi * 6378137/2.0
# 20037508.342789244
def LatLonToMeters(self, lat, lon):
"Converts given lat/lon in WGS84 Datum to XY in Spherical Mercator EPSG:900913"
mx = lon * self.originShift/180.0
my = math.log(math.tan((90 + lat) * math.pi/360.0))/(math.pi/180.0)
my = my * self.originShift/180.0
return mx, my
def MetersToLatLon(self, mx, my):
"Converts XY point from Spherical Mercator EPSG:900913 to lat/lon in WGS84 Datum"
lon = (mx/self.originShift) * 180.0
lat = (my/self.originShift) * 180.0
lat = 180/math.pi * (2 * math.atan(math.exp(lat * math.pi/180.0)) - math.pi/2.0)
return lat, lon
def PixelsToMeters(self, px, py, zoom):
"Converts pixel coordinates in given zoom level of pyramid to EPSG:900913"
res = self.Resolution(zoom)
mx = px * res - self.originShift
my = py * res - self.originShift
return mx, my
def MetersToPixels(self, mx, my, zoom):
"Converts EPSG:900913 to pyramid pixel coordinates in given zoom level"
res = self.Resolution(zoom)
px = (mx + self.originShift)/res
py = (my + self.originShift)/res
return px, py
def PixelsToTile(self, px, py):
"Returns a tile covering region in given pixel coordinates"
tx = int(math.ceil(px/float(self.tileSize)) - 1)
ty = int(math.ceil(py/float(self.tileSize)) - 1)
return tx, ty
def PixelsToRaster(self, px, py, zoom):
"Move the origin of pixel coordinates to top-left corner"
mapSize = self.tileSize << zoom
return px, mapSize - py
def MetersToTile(self, mx, my, zoom):
"Returns tile for given mercator coordinates"
px, py = self.MetersToPixels(mx, my, zoom)
return self.PixelsToTile(px, py)
def TileBounds(self, tx, ty, zoom):
"Returns bounds of the given tile in EPSG:900913 coordinates"
minx, miny = self.PixelsToMeters(tx*self.tileSize, ty*self.tileSize, zoom)
maxx, maxy = self.PixelsToMeters((tx+1)*self.tileSize, (ty+1)*self.tileSize, zoom)
return (minx, miny, maxx, maxy)
def TileLatLonBounds(self, tx, ty, zoom):
"Returns bounds of the given tile in latutude/longitude using WGS84 datum"
bounds = self.TileBounds(tx, ty, zoom)
minLat, minLon = self.MetersToLatLon(bounds[0], bounds[1])
maxLat, maxLon = self.MetersToLatLon(bounds[2], bounds[3])
return (minLat, minLon, maxLat, maxLon)
def Resolution(self, zoom):
"Resolution (meters/pixel) for given zoom level (measured at Equator)"
# return (2 * math.pi * 6378137)/(self.tileSize * 2**zoom)
return self.initialResolution/(2**zoom)
def ZoomForPixelSize(self, pixelSize):
"Maximal scaledown zoom of the pyramid closest to the pixelSize."
for i in range(30):
if pixelSize > self.Resolution(i):
return i-1 if i!=0 else 0 # We don't want to scale up
def GoogleTile(self, tx, ty, zoom):
"Converts TMS tile coordinates to Google Tile coordinates"
# coordinate origin is moved from bottom-left to top-left corner of the extent
return tx, (2**zoom - 1) - ty
def QuadTree(self, tx, ty, zoom):
"Converts TMS tile coordinates to Microsoft QuadTree"
quadKey = ""
ty = (2**zoom - 1) - ty
for i in range(zoom, 0, -1):
digit = 0
mask = 1 << (i-1)
if (tx & mask) != 0:
digit += 1
if (ty & mask) != 0:
digit += 2
quadKey += str(digit)
return quadKey
這是我的C#端口。
public class GlobalMercator {
private Int32 TileSize;
private Double InitialResolution;
private Double OriginShift;
private const Int32 EarthRadius = 6378137;
public GlobalMercator() {
TileSize = 256;
InitialResolution = 2 * Math.PI * EarthRadius/TileSize;
OriginShift = 2 * Math.PI * EarthRadius/2;
}
public DPoint LatLonToMeters(Double lat, Double lon) {
var p = new DPoint();
p.X = lon * OriginShift/180;
p.Y = Math.Log(Math.Tan((90 + lat) * Math.PI/360))/(Math.PI/180);
p.Y = p.Y * OriginShift/180;
return p;
}
public GeoPoint MetersToLatLon(DPoint m) {
var ll = new GeoPoint();
ll.Longitude = (m.X/OriginShift) * 180;
ll.Latitude = (m.Y/OriginShift) * 180;
ll.Latitude = 180/Math.PI * (2 * Math.Atan(Math.Exp(ll.Latitude * Math.PI/180)) - Math.PI/2);
return ll;
}
public DPoint PixelsToMeters(DPoint p, Int32 zoom) {
var res = Resolution(zoom);
var met = new DPoint();
met.X = p.X * res - OriginShift;
met.Y = p.Y * res - OriginShift;
return met;
}
public DPoint MetersToPixels(DPoint m, Int32 zoom) {
var res = Resolution(zoom);
var pix = new DPoint();
pix.X = (m.X + OriginShift)/res;
pix.Y = (m.Y + OriginShift)/res;
return pix;
}
public Point PixelsToTile(DPoint p) {
var t = new Point();
t.X = (Int32)Math.Ceiling(p.X/(Double)TileSize) - 1;
t.Y = (Int32)Math.Ceiling(p.Y/(Double)TileSize) - 1;
return t;
}
public Point PixelsToRaster(Point p, Int32 zoom) {
var mapSize = TileSize << zoom;
return new Point(p.X, mapSize - p.Y);
}
public Point MetersToTile(Point m, Int32 zoom) {
var p = MetersToPixels(m, zoom);
return PixelsToTile(p);
}
public Pair<DPoint> TileBounds(Point t, Int32 zoom) {
var min = PixelsToMeters(new DPoint(t.X * TileSize, t.Y * TileSize), zoom);
var max = PixelsToMeters(new DPoint((t.X + 1) * TileSize, (t.Y + 1) * TileSize), zoom);
return new Pair<DPoint>(min, max);
}
public Pair<GeoPoint> TileLatLonBounds(Point t, Int32 zoom) {
var bound = TileBounds(t, zoom);
var min = MetersToLatLon(bound.Min);
var max = MetersToLatLon(bound.Max);
return new Pair<GeoPoint>(min, max);
}
public Double Resolution(Int32 zoom) {
return InitialResolution/(2^zoom);
}
public Double ZoomForPixelSize(Double pixelSize) {
for (var i = 0; i < 30; i++)
if (pixelSize > Resolution(i))
return i != 0 ? i - 1 : 0;
throw new InvalidOperationException();
}
public Point ToGoogleTile(Point t, Int32 zoom) {
return new Point(t.X, ((Int32)Math.Pow(2, zoom) - 1) - t.Y);
}
public Point ToTmsTile(Point t, Int32 zoom) {
return new Point(t.X, ((Int32)Math.Pow(2, zoom) - 1) - t.Y);
}
}
public struct Point {
public Point(Int32 x, Int32 y)
: this() {
X = x;
Y = y;
}
public Int32 X { get; set; }
public Int32 Y { get; set; }
}
public struct DPoint {
public DPoint(Double x, Double y)
: this() {
this.X = x;
this.Y = y;
}
public Double X { get; set; }
public Double Y { get; set; }
public static implicit operator DPoint(Point p) {
return new DPoint(p.X, p.Y);
}
}
public class GeoPoint {
public Double Latitude { get; set; }
public Double Longitude { get; set; }
}
public class Pair<T> {
public Pair() {}
public Pair(T min, T max) {
Min = min;
Max = max;
}
public T Min { get; set; }
public T Max { get; set; }
}
我有兩個問題。
難道我口正確的代碼? (我故意省略了,因爲我不使用它的一種方法,並添加一個我自己)
這裏我有座標
WGS84 datum (longitude/latitude): -123.75 36.59788913307022 -118.125 40.97989806962013 Spherical Mercator (meters): -13775786.985667605 4383204.9499851465 -13149614.849955441 5009377.085697312 Pixels 2560 6144 2816 6400 Google x:10, y:24, z:6 TMS x:10, y:39, z:6 QuadTree 023010
我應該如何鏈中的方法,使我從谷歌的獲得瓷磚座標(10,24,6)球形梅卡托米?
更新
找到適合我的第二個問題的答案是對我來說更重要。
,只要運行它,並對其進行測試。如果你得到了期望的輸出,那麼你可能會搖擺。 –
我不完全精通GIS。所以我正在尋找專家的樣子。 – Oybek