香港 HK1980 方格網坐標 ⇄ WGS84 GPS 經緯度 (2017 新方法)

香港政府 DataOne 提供很多有用的資料庫,有些位置資料庫(例如”香港政府WiFi通”)裡面的座標並不是我們見慣的GPS座標 而是”香港 1980 方格網坐標”

問題是 Google Maps 和手機的系統只有GPS座標系統可用。
必須找個公式把座標轉換才行。

2017-03-22 更新:
Java Applet 版本的已經下架了, 現在新的 Script 是 Server side 的, 所以這方法已經無效了
三年過去了, 人總要進步, 是時候脫離偏門左道了

Google 研究了一番, 找來了正統的新方法 (proj.4)
這次的大部分 Program Language 都適用喔


舊方法 (海事處 Java Applet)

公式當然是政府公開的,這裡有兩個連結,點進去就有了。
但是這一大堆數學公式不太像是我看得懂的東西,還是別找出路吧。

Google找到政府有兩個網上工具:

1. 地政署 “Web-based Datum Transformation Tool” –
http://www.geodetic.gov.hk/smo/gsi/programs/en/GSS/grid/transformation.htm

2. 海事處 “Datum Transformation” –
http://www.hydro.gov.hk/datum/JDatum.html

前者是 Server side script,而後者是Java
正打算用 Java Decompiler 之際,打開 Source Code 看到 applet 的 source address 居然是 .java file (!?)

    <script type="text/javascript">
		function java() {
			document.write ("<applet code=\"Jdgui_awt2.java\" style=\"height:465px; width:750px\"></applet>");
		}
	</script>

下載回來果然是明文的,Decompiler 都省了。
但是這原來只是介面,有一些最重要的關鍵 Class (Transform等)不見了。
.java 裡又沒有指定 Dependency,真奇怪。

反正是 http 明文,將 Cache 清空,再用WireShark Capture Traffic 看看,果然找到還有 Jdatum.java
有了這個 Class,打開Eclipse寫個簡單的 Script,讀取 CSV 直接呼叫 Transform.HKGEO() 進行 Batch Convert。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Converter {
	public static void main(String args[]) {

		if (args.length == 0) {
			System.out.println("Usage: java Converter input.txt");
			return;
		}

		Converter c = new Converter();
		Double N;
		Double E;

		try {
			BufferedReader reader = new BufferedReader(new FileReader(args[0]));
			try {
				String line = null;
				while ((line = reader.readLine()) != null) {

					String[] NE = line.split(",");

					N = Double.parseDouble(NE[0]);
					E = Double.parseDouble(NE[1]);

					c.output(N, E);
				}
			} finally {
				reader.close();
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		}		
	}

	public void output(Double N, Double E) {
		Transform transformer = new Transform();
		GeoData GeoResult = transformer.HKGEO(2, N, E);
		System.out.println(GeoResult.getPhi() + "," + GeoResult.getFlam());
	}
}

input.txt 格式一行一組,用 “,” 分隔。

java -cp .;bin Converter input.txt > output.txt

任務完成!
(版權問題不能提供成品,請自行取檔 Compile)

新方法

經 Google 查找到 HK1980 又名 EPSG 2326, 而 WGS84 (通用 GPS 坐標) 又名 EPSG 4326

epsg.io 的頁面下面有一堆 Definition 提供, 用來幹嘛? 當然是轉換了!

當中最 Programmer Friendly 的應該是 proj.4

proj.4 is a standard UNIX filter function which converts geographic longitude and latitude coordinates into cartesian coordinates (and vice versa), and it is a C API for software developers to include coordinate transformation in their own software.

它是 C Library, 但各大 Program Language 都有 Implementation

PHP (https://github.com/proj4php/proj4php):

<?php
// Use a PSR-4 autoloader for the `proj4php` root namespace.
include("vendor/autoload.php");

use proj4php\Proj4php;
use proj4php\Proj;
use proj4php\Point;

// Initialise Proj4
$proj4 = new Proj4php();

$proj4->addDef("EPSG:2326" ,'+proj=tmerc +lat_0=22.31213333333334 +lon_0=114.1785555555556 +k=1 +x_0=836694.05 +y_0=819069.8 +ellps=intl +towgs84=-162.619,-276.959,-161.764,0.067753,-2.24365,-1.15883,-1.09425 +units=m +no_defs ');

// Create two different projections.
$projHK1980    = new Proj('EPSG:2326', $proj4);
$projWGS84  = new Proj('EPSG:4326', $proj4);

// Create a point.
$pointSrc = new Point(832699, 836055, $projHK1980);
echo "Source: " . $pointSrc->toShortString() . " in HK1980 <br>";

// Transform the point between datums.
$pointDest = $proj4->transform($projWGS84, $pointSrc);
echo "Conversion: " . $pointDest->toShortString() . " in WGS84<br><br>";

// Source: 832699, 836055 in HK1980
// Conversion: 114.14219796719 22.463983921629 in WGS84

JS (http://proj4js.org/)

var proj4 = require('proj4');

proj4.defs("EPSG:2326","+proj=tmerc +lat_0=22.31213333333334 +lon_0=114.1785555555556 +k=1 +x_0=836694.05 +y_0=819069.8 +ellps=intl +towgs84=-162.619,-276.959,-161.764,0.067753,-2.24365,-1.15883,-1.09425 +units=m +no_defs");
proj4.defs("EPSG:4326","+proj=longlat +datum=WGS84 +no_defs");

var result = proj4('EPSG:2326', 'EPSG:4326', [832699, 836055]);

Java (https://trac.osgeo.org/proj4j/)

Python (https://pypi.python.org/pypi/pyproj)


4 Replies to “香港 HK1980 方格網坐標 ⇄ WGS84 GPS 經緯度 (2017 新方法)”

  1. 多謝提供意見。我有些問題未知版主可否給些解決方法。我的工作需要用到手提GPS,裏面有user datum可讓我們將WGS84轉成HK Grid,不過有一堆constant要輸入,請問可以在那裡找到呢?constant 如下:
    Longitude Origin, Scale, False Easting, False Northing, DX, DY,DZ, DA, DF.
    另一個問題是當我download waypoint gpx所顯示只會是WGS84,請問有沒有可能在excel 轉換呢?

  2. Could you also kindly advise how can I convert E-N coordinates from HK Gird 1977 to HK Grid 1980?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.