前段時間就在考慮如果把我們的IP地址查詢網站進行改進,以前把内網的IP地址頁面進行了大幅整改,無論是内容、界面都有很大提升,效果還是很明顯的,後面還想對外網頁面也進行較大的改造。
一個考慮的重點是把圖片做成我們網站的特色,讓用戶可以看到更直觀、更有用的圖片,準備在圖片中顯示IP地址的歸屬地信息,還要加上地圖顯示,這個地圖的顯示就很有講究了,遇到的一個難題是如何把IP地址的歸屬地經緯度在平面地圖上進行标記,而這就需要解決經緯度轉平面直角坐标系的問題。
在網上查了一下,國内有幫助的文章不多,而用英文在Google搜索就很快發現一些好的信息,例如:
- Convert from latitude, longitude to x, y 轉換經緯度到x, y坐标
- Transverse Mercator projection 橫軸墨卡托投影
又陸陸續續找了不少文章查看,基本看明白了幾點:
- 這種轉換是一個近似轉換,不可能是精确解
- 有專門的近似計算公式,可以拿來參考使用
雖然這些年都搞電腦相關工作,但計算中需要涉及三角函數和自然對數這些的地方還是很少,所以看到一些中學時候學的數學公式還覺得有趣:
而推導原理如下圖所示:
太深究原理了也沒有必要,我就把這公式用好吧,于是在PHP程序中用log, sin等函數來實現了,經緯度在使用sin函數前需要從角度轉為弧度再計算,還有一些參數需要反複調整以便合适地展示在地圖中。
... //準備經緯度數據,角度轉弧度 $longitude_radian = M_PI / 180 * $longitude;//經度,角度轉弧度,乘以兀除以180度 $latitude_radian = M_PI / 180 * $latitude;//緯度,角度轉弧度,乘以兀除以180度 //準備x,y軸比例數據 $x_scale = $width / 2 / M_PI * 0.97;//這個0.97是因為橫行數據核查對比的時候總有一點偏差而乘以的一個估算比例值 $y_scale = $height / 2 / 3;//這個3也是一個經驗值,測試了各種大小,3左右誤差小,這裡是否應該用到 M_PI 未知? //墨卡托投影轉換公式 $x = $x_center + $x_scale * $longitude_radian;//x軸坐标,與經度是線性關系的 $y = $y_center - $y_scale * log((1 + sin($latitude_radian)) / (1 - sin($latitude_radian)));//y軸坐标,與緯度是非線性關系的 ...
本來按照公式,$y_scale應該是等于$x_scale的,但我實際用的時候發現相差很大,就各自單獨計算設置了。
下面就是我們通過計算将一個IP地址的所在位置經緯度轉為平面坐标,再展示在世界地圖中的效果:
我找了10多個很小的國家和地區,将IP所在經緯度計算出來的x, y坐标與原始SVG地圖中繪圖的坐标進行比對,可以實現大約1%左右的精确度,橫坐标相對更準,誤差在1%以内,縱坐标差一些,而且需要用部分自己試算的參數,有的地方誤差有3%左右了。
這個圖片還會集成在我們IP站外網頁面的綜合圖片中,為了一幅圖花費這麼大的力氣,我們自己感覺會對用戶很有幫助,到時候再寫一篇介紹。
评论