2015年3月5日 星期四

認識座標系統

經緯度是我們習以為常的一種座標系統,它可以用來標示地球表面上任何一個點的位置。 然而經緯度是一種球面的座標系統,除了地球儀外,若要將這個座標系統運用在平面的地圖上時,所有的地圖都必須產生某些程度的變形,因此其他的座標系統也就應運而生。

座標系統

大地座標系統

大地座標系是由經度和緯度構成的球面坐標系統。

  • 以子午面起算,向東為正,叫東經(0度~180度),向西為負,叫西經(0度~180度)。
  • 以赤道面起算,向北為正,叫北緯(0度~90度),向南為負,叫南緯(0度~90度)。

經緯度表示法

經緯度以度數表示,一般可直接以帶小數點的度數表示,但亦可把度數的小數點部份再細分成「角分」和「秒」。 1度=60角分,1角分=60秒。例如以下三個都表示同一個經緯座標:

  1. 度數表示 :N25.17077 E121.55344(北緯25.17077度,東經121.55344度)
  2. 度分表示 :N25 10.246 E121 33.207(北緯25度10.246分,東經121度33.207分)
  3. 度分秒表示:N25 10 14.8 E121 33 12.4(北緯25度10分14.8秒,東經121度33分12.4秒)

分帶座標系統

分帶座標系統是為了減少平面地圖繪製時的變形情況,而橫梅投影法(Transverse Mercator Projection),則是一種國際間普遍使用的一種投影方式,我們可以想像成將一個圓柱體橫躺,套在地球外面,再將地表投影到這個圓柱上,然後將圓柱體展開成平面。 它是正形投影的一種,在小範圍內可以保持形狀不變。 為了保持投影精度在可接受範圍內,每次只能取中央經線兩側附近地區來用,因此必須切割為許多投影帶。 就像將地球沿南北子午線方向,如切西瓜一般,切割為若干帶狀,再展成平面。 目前世界各國軍用地圖所採用之 UTM 座標系統 (Universal Transverse Mercator Projection System),即為橫梅投影的一種。

要描述地表上任何一個點的地理位置,都必須使用一個大地基準 (Datum)和一組座標來標示才有意義。 在台灣常聽到的 TWD67、TWD97、WGS84 等,都是一種大地基準,也就是它們各有各的基準點。 而 UTM、TM2、經緯度等,都是一種座標格式。

六度分帶

「UTM 座標系統」是目前世界各國軍用地圖所採用的座標系統,它就是所謂的「六度分帶」,係將地球沿子午線方向,每隔 6 度切割為一帶,全球共切割為 60 個投影帶。 六度分帶是較早期的設計,其精準度要求較低,隨著時代演變,各種高精準度的需求日益增加,所以又有「三度分帶」座標系統的產生,但是其比例誤差仍嫌過大,因此這個系統十分短命。於是在 1974 年時,政府為繪製五千分之一基本圖及地籍測量之需求,決定採用更精準的「二度分帶」座標。

二度分帶

「二度分帶」係將地表每隔二度切為一個投影帶,因為切割更細,所以其投影誤差也更小(約 1/10000 左右),且台灣本島剛好都在同一投影帶內,不會造成使用上不便,因此一直沿用至今,成為國內製作各種圖籍的標準。也因為切割較細,使得台灣、澎湖、彭佳嶼、釣魚台分別屬於不同投影帶。

「二度分帶」是以東經121 度為中央經線,所以在台灣本島西側座標將出現負數,為確保整幅地圖座標值都是正數,於是將 X 軸座標原點,向西平移 250000 公尺(250公里)。

TWD67、TWD97 與 WGS84

TWD67

TWD67 是台灣內政部公告的一種二度分帶座標基準,係參考1967年國際地球原子參數(Geodetic Reference System 1967),以埔里的虎山為坐標基準,使用傳統的天文觀測、三角定位量測方式,所建立的座標系統。 這個系統所測得的經緯度只適用於台灣附近的區域。它的 X 軸座標原點,原本應該位在中央經線 121°E,如此台灣本島的西側座標將出現負數,為確保整幅地圖座標值都是正數,於是將 X 軸座標原點,向西平移 250000 公尺(250公里)。 Y 軸座標原點位在赤道,其座標值即為相對於赤道的距離。

TWD97

TWD97 也一種二度分帶座標基準,它是直接使用衛星定位技術量測產生,適用於全球的一套座標系統。 TWD67 與 TWD97 之間的差異量不小,若全面採用 TWD97,勢必導致大量舊有之圖籍全面改製,茲事體大,因此國內尚未全面採用。

WGS84

WGS84,全名是 World Geodetic System 1984,由遍布世界的衛星站所觀測建立,為 GPS 全球定位系統而建立的坐標系統。 TWD97 與 WGS84 兩者相差不大, 大約幾公分至數十公分, 一般在登山及導航的應用時,可以視為一致。

台灣二度分帶

二度分帶以二度劃分一區,而台灣本島剛好都在同一區裡,澎湖,金門與馬祖屬於另一個分帶。 「台灣二度分帶」指的就是 TWD67、TWD97 二種系統,或稱「舊虎子山系統」和「虎子山系統」,都是以東經 121 度為中央子午線,橫跨東經120~122二度的範圍。 雖然目前國際通用之經緯度座標系統為WGS84,且 Google Earth 也是使用 WGS84 ,但是因為上河出版的百岳地圖,還有舊的經建版地圖都是使用 TWD67 ,所以 TWD67 座標系統在登山的相關領域中還是很常見到的系統。

認識地圖與讀取座標

如果下圖是一份 TWD67 地圖,你應該如何正確報出虎子山的座標?

首先觀查圖中的資訊,因為虎子山距離中央子午線約 2658 公尺,距離赤道約 2652336 公尺,因為 X 軸座標原點向西平移 250000 公尺,所以虎子山的座標應該為(-2658+250000, 2652336)= (247342, 2652336)。 而 XY 值的讀法為:東距247342公尺、北距2652336公尺。同時為了避免混淆,也要註明使用的大地基準。

座標轉換

以下程式碼,取自ola的家程式設計 遇上 小提琴二位大大的文章。

(TWD67)與(TWD97)轉換

const double A = 0.00001549;
const double B = 0.000006521;

public static Coordinate TWD97_To_TWD67(Coordinate Coord97)
{
double X67 = Coord97.X - 807.8 - A * Coord97.X - B * Coord97.Y;
double Y67 = Coord97.Y + 248.6 - A * Coord97.Y - B * Coord97.X;

return new Coordinate(X67, Y67);
}

public static Coordinate TWD67_To_TWD97(Coordinate Coord67)
{
double X97 = Coord67.X + 807.8 + A * Coord67.X + B * Coord67.Y;
double Y97 = Coord67.Y - 248.6 + A * Coord67.Y + B * Coord67.X;

return new Coordinate(X97, Y97);
}

(TWD97)與(經緯度)轉換

const double a = 6378137.0;
const double b = 6356752.314245;
const double lon0 = 121 * Math.PI / 180;
const double k0 = 0.9999;
const int dx = 250000;
const int dy = 0;

public static Coordinate LonLat_To_TWD97(LonLat lonlat)
{
double e = 1 - Math.Pow(b, 2) / Math.Pow(a, 2);
double e1 = (1 - Math.Pow(b, 2) / Math.Pow(a, 2)) / (Math.Pow(b, 2) / Math.Pow(a, 2));

double lon = (lonlat.Longitude - Math.Floor((lonlat.Longitude + 180) / 360) * 360) * Math.PI / 180;
double lat = (lonlat.Latitude / 180) * Math.PI;

double V = a / Math.Sqrt(1 - e * Math.Pow(Math.Sin(lat), 2));
double T = Math.Pow(Math.Tan(lat), 2);
double C = e1 * Math.Pow(Math.Cos(lat), 2);
double A = Math.Cos(lat) * (lon - lon0);
double M = a * ((1.0 - e / 4.0 - 3.0 * Math.Pow(e, 2) / 64.0 - 5.0 * Math.Pow(e, 3) / 256.0) * lat -
(3.0 * e / 8.0 + 3.0 * Math.Pow(e, 2) / 32.0 + 45.0 * Math.Pow(e, 3) / 1024.0) *
Math.Sin(2.0 * lat) + (15.0 * Math.Pow(e, 2) / 256.0 + 45.0 * Math.Pow(e, 3) / 1024.0) *
Math.Sin(4.0 * lat) - (35.0 * Math.Pow(e, 3) / 3072.0) * Math.Sin(6.0 * lat));

//計算Y值
double y = dy + k0 * (M + V * Math.Tan(lat) * (Math.Pow(A, 2) / 2 + (5 - T + 9 * C + 4 * Math.Pow(C, 2)) * Math.Pow(A, 4) / 24 + (61 - 58 * T + Math.Pow(T, 2) + 600 * C - 330 * e1) * Math.Pow(A, 6) / 720));

//計算X值
double x = dx + k0 * V * (A + (1 - T + C) * Math.Pow(A, 3) / 6 + (5 - 18 * T + Math.Pow(T, 2) + 72 * C - 58 * e1) * Math.Pow(A, 5) / 120);

return new Coordinate(x, y);
}

public static LonLat TWD97_To_LonLat(Coordinate Coord)
{
double e = 1 - Math.Pow(b, 2) / Math.Pow(a, 2);
double e1 = (1.0 - Math.Sqrt(1.0 - e)) / (1.0 + Math.Sqrt(1.0 - e));

double x = Coord.X - dx;
double y = Coord.Y - dy;

// Calculate the Meridional Arc
double M = y / k0;

// Calculate Footprint Latitude
double mu = M / (a * (1.0 - e / 4.0 - 3 * Math.Pow(e, 2) / 64.0 - 5 * Math.Pow(e, 3) / 256.0));
double J1 = (3 * e1 / 2 - 27 * Math.Pow(e1, 3) / 32.0);
double J2 = (21 * Math.Pow(e1, 2) / 16.0 - 55 * Math.Pow(e1, 4) / 32.0);
double J3 = (151 * Math.Pow(e1, 3) / 96.0);
double J4 = (1097 * Math.Pow(e1, 4) / 512.0);
double fp = mu + J1 * Math.Sin(2 * mu) + J2 * Math.Sin(4 * mu) + J3 * Math.Sin(6 * mu) + J4 * Math.Sin(8 * mu);

// Calculate Latitude and Longitude
double e2 = Math.Pow((e1 * a / b), 2);
double C1 = e2 * Math.Pow(Math.Cos(fp), 2);
double T1 = Math.Pow(Math.Tan(fp), 2);
double R1 = a * (1 - e) / Math.Pow((1 - e * Math.Pow(Math.Sin(fp), 2)), (3.0 / 2.0));
double N1 = a / Math.Pow((1 - e * Math.Pow(Math.Sin(fp), 2)), 0.5);
double D = x / (N1 * k0);

// 計算緯度
double Q1 = N1 * Math.Tan(fp) / R1;
double Q2 = (Math.Pow(D, 2) / 2.0);
double Q3 = (5 + 3 * T1 + 10 * C1 - 4 * Math.Pow(C1, 2) - 9 * e2) * Math.Pow(D, 4) / 24.0;
double Q4 = (61 + 90 * T1 + 298 * C1 + 45 * Math.Pow(T1, 2) - 3 * Math.Pow(C1, 2) - 252 * e2) * Math.Pow(D, 6) / 720.0;
double lat = fp - Q1*(Q2 - Q3 + Q4);

// 計算經度
double Q5 = D;
double Q6 = (1 + 2 * T1 + C1) * Math.Pow(D, 3) / 6.0;
double Q7 = (5 - 2 * C1 + 28 * T1 - 3 * Math.Pow(C1, 2) + 8 * e2 + 24 * Math.Pow(T1, 2)) * Math.Pow(D, 5) / 120.0;
double lon = lon0 + (Q5 - Q6 + Q7)/Math.Cos(fp);

lat = (lat * 180) / Math.PI; //緯
lon = (lon * 180) / Math.PI; //經
//string lonlat = lon + "," + lat;
return new LonLat(lon, lat);
}

沒有留言:

張貼留言