目錄html
今天(2019年5月30日)去編譯最新版本的GDAL,發現其對Proj.4的依賴已經要求爲6.x版本了。因而去https://github.com/OSGeo/proj.4看了一下最新的代碼,又去https://proj4.org/看了一下文檔,感受5.x和6.x的更新挺大的,有必要測試一下,看工做中的項目是否是要升級過來。git
我沒有仔細去看5.x版本的代碼,僅看了一下最新的Proj.4
版本6的代碼,與早前使用的4.9.3版本簡單對比了一下,感受區別仍是挺大的,這裏列出幾點我關注的地方的對比。github
一、新版本改用C++編寫,相比4.9版本代碼量增長了很多,功能也多了很多。代碼層次結構清晰了許多,好比各類轉換算法都在src/transformations目錄下能夠找到,各類投影方法相關的算法都在src/projections目錄能夠找到。算法
二、支持了從WKT/WKT2
字符串和EPSG代碼直接建立座標系對象,也支持導出WKT字符串。老版本中記錄EPSG座標系定義的的nad/epsg被棄用,改用SQLite數據庫來記錄(在data/sql目錄下保存着用於生成proj.db
文件的SQL腳本),不過新版本須要依賴SQLite3。sql
三、新版的實現使用了緩存機制,在建立操做座標系對象及搜索查找等都有用到。代碼可見 src/iso19111/factory.cpp、src/iso19111/crs.cpp、src/iso19111/coordinateoperation.cpp、數據庫
src/iso19111/coordinateoperation.cpp 等文件。編程
四、新版添加了proj_math.h、math.cpp,添加了pj_hypot
等函數,這解決了一些編譯問題(由於以前版本projects.h中聲明瞭hypot
函數,但這個函數在非_WIN32環境中也多是存在math.h中的)。api
如下主要翻譯自:PROJ.4 News緩存
此版本的 PROJ 對系統的大地測量功能 (主要是) 引入了一些重要的擴展和改進。架構
引入新功能的主要驅動因素是動態參考框架的出現、高精度全球導航衛星系統的使用日益增長以及對精確座標變換的相關需求的增長。雖然舊版本的 PROJ 包含一些大地測量功能, 但新框架爲將 PROJ 轉變爲通用地理空間座標轉換引擎奠基了基礎。
內部架構也有了許多變化和改進。到目前爲止,這些改進都遵循現有的編程接口。可是這個過程已經顯示出須要簡化和減小代碼庫,以支持持續的主動開發。
新的主要版本號使該項目在名稱上留下了一些難題。在產品的大部分使用壽命中,它被稱爲PROJ.4,但因爲咱們如今已達到版本5,所以名稱再也不與版本號對齊。
所以,咱們決定將名稱與版本號和該版本分離,而後將產品簡稱爲PROJ。爲了表彰軟件的歷史,咱們將PROJ.4做爲組織項目的名稱。同一個項目團隊也會生成datum-grid 包。
綜上所述:
推出新的API在proj.h
proj_
命名空間(名稱前綴)PJ_
命名空間(名稱前綴)引入「轉換管道」(transformation pipelines)的概念,能夠經過 菊花鏈 的方式簡化座標操做,能夠對座標進行復雜的大地轉換。
採用 OGC/ISO-19100 地理空間標準系列術語。關鍵定義是:
新操做
pipeline
)helmert
)horner
)hgridshift
)vgridshift
)molodensky
)deformation
)unitconvert
)axisswap
)ccon
)新的「自由格式」(free format)選項,運行在指定key/value鍵值對時候經過空白字符進行分割標記,例如proj = merc lat_0 = 45
添加到init-files的元數據,能夠經過proj.h
中新的API函數proj_init_info()
讀取它們。
添加了具備ITRF轉換參數的ITRF2000,ITRF2008和ITRF2014初始化文件,包括板塊運動模型參數。
添加橢球參數到GSK2011,PZ90和"danish"。後者相似於已經支持的andrae橢球體,但長半軸略微不一樣。
添加哥本哈根本初子午線.
將EPSG數據庫更新至9.2.0版。
Geodesic庫已更新至1.49.2-c版。
對分析性偏導數的支持已被移除。
改善了Winkel Tripel和Aitoff的表現。
將pj_has_inverse()
函數引入proj_api.h
,使用它檢測一個操做是否可反轉,而不是檢測P->inv
是否存在。
ABI版本號更新爲13:0:0。
刪除了對Windows CE的支持。
刪除了VB6 COM接口。
proj_errno_string()
到 proj.h
--skip-lines
選項。NaN
處返回Nan
值。src/org_proj4_Projections.h
文件。+t_epoch
爲時間輸入。-multiplier
選項到vgridshift。+transpose
選項替換爲+convention
。從如今開始應當顯示指定convertion使用,使用+transpose選項將返回錯誤。PROJ6 進行了普遍的更改, 以增長其功能範圍, 從具備所謂 "早期綁定" 大地測量基準轉換功能的製圖投影引擎, 到更完整的庫, 支持座標變換和座標參考系統。
做爲其餘加強功能的基礎, PROJ 如今包括由 iso-19111:2019 標準/OGC 抽象規範主題 2: "按座標引用" 的模型的 C++ 實現, 用於大地測量參照框 (基準), 座標參考系統和協調操做。這些大地測量對象的構造和查詢可經過新的 C++ API 進行, 而且在很大程度上能夠從 C API 中的綁定中訪問。
這些大地測量對象能夠從 OGC 已知文本格式 (WKT) 以不一樣的變體導入和導出: ESRI WKT、GDAL WKT 一、WKT2:2015 (ISO 191.2: 2015) 和 WKT2:2018 (ISO 19162: 2018)。還支持從 PROJ 字符串導入和導出 crs 對象。此功能之前在 GDAL 軟件庫中可用 (WKT2 支持除外, 這是一項新功能), 如今是 PROJ 不可或缺的一部分。
如今, sqlite3 數據庫文件 proj.db 中提供了一個統一的大地測量對象數據庫、座標參考系統及其元數據以及這些 CRS 之間的座標操做。這包括從 IOMP EPSG 數據集 (v9.6.0 版本)、法國國家測繪機構大地測量登記冊和 ESRI 投影引擎數據庫中導入的定義。PROJ 如今是此 CRS 和座標操做數據庫的 "OSGeo C stack" 中的參考軟件, 而之前此功能分佈在 PROJ、GDAL 和歌詞地理, 並使用 CSV 或其餘基於特定文本的格式。
添加了考慮到元數據 (如使用區域和準確性) 的後期綁定座標操做功能。這能夠在許多狀況下避免過去使用 WGS84 做爲中間系統的要求, 這可能會致使沒必要要的精度損失, 或者在沒法轉換到 WGS84 的狀況下有時是沒法實現的。這些後期綁定功能如今由 proj_create_crs_to_crs() 函數和 cs2cs 實用程序使用。
添加了一個新的命令行實用程序 projinfo 來查詢有關數據庫的大地測量對象的信息, 從 WKT 字符串和 PROJ 字符串導入和導出大地測量對象, 並顯示兩個 CRS(座標參考系統) 之間可用的座標操做。
ACCEPT_USE_OF_DEPRECATED_PROJ_API_H
宏接口才可用。 (#836)proj_def.dat
默認文件的支持。 (#201)proj.h
。(#1175)nad2bin
程序。如今能夠在proj-datumgrid倉庫中查看。proj_geocentric_latitude()
APIetmerc
)。舊的實現能夠經過添加 +approx
參數(#404)PROJ_LIB
環境變量中使用多個目錄 (#1218)+t_obs
參數,從helmert 和deformation中 (#1264)+dt
參數到deformation中,用於替換移除的 +t_obs
(#1264)-k ellipsoid
選項到 projinfo (#1338)proj_normalize_for_visualization()
嘗試應用大多數 GIS 應用和 PROJ <6 使用的軸序 (#1387)PROJ_LIB
搜索路徑 (#1398)如下內容主要來自Version 4 to 5/6 API Migration。
這是但願將代碼遷移到使用PROJ 5的開發人員的過渡指南。
原文太長,這裏簡單抽取一部分。
一、以前老的API兩個座標參考系統之間的任何轉換都必須經過未明肯定義的WGS84框架進行中轉,新的API取消了對PROJ中轉換的限制。雖然任然能夠進行這種類型的轉換,可是在多數狀況下,有更好的替代方案。
二、若是你只關心到米級精度,那麼舊的API是夠用的。可是WGS84並不是真實世界的基礎,其它一切均可以經過WGS84進行轉換的觀點是有缺陷的。而且這裏說的WGS84是6個實現中的哪個呢?
三、對許多座標系統而言,轉換到WGS84,在舊系統之間可能變換精度在釐米級。
四、hub(這裏說的就是把全部座標之間的轉換都經過WGS84作中轉)框架("基準")概念自己沒有大問題。但世界本質是4維的,爲了得到大地測量精確變換,可能須要在四個維度下計算,新的API容許這樣作。
舊的API下,座標從座標系A轉換到座標系B的過程,須要從A變換到WGS84(反算),再從WGS84變換到B(正算)
$ echo 300000 6100000 | cs2cs +proj=utm +zone=33 +ellps=GRS80 +to +proj=utm +zone=32 +ellps=GRS80 683687.87 6099299.66 0.00
新的命令行工具cct
使用新的API,因此一樣的轉換可能結果不同
$ echo 300000 6100000 0 0 | cct +proj=pipeline +step +inv +proj=utm +zone=33 +ellps=GRS80 +step +proj=utm +zone=32 +ellps=GRS80 683687.8667 6099299.6624 0.0000 0.0000
這裏顯示了舊API和新API之間的區別,並舉了幾個例子。 下面咱們用兩個不一樣的API實現相同的程序。 程序從命令行讀取輸入經度和緯度,並使用墨卡託投影將它們轉換爲投影座標。
咱們首先編寫PROJ v.4的程序:
#include <proj_api.h> main(int argc, char **argv) { projPJ pj_merc, pj_longlat; double x, y; // 建立座標參考系對象 if (!(pj_longlat = pj_init_plus("+proj=longlat +ellps=clrk66")) ) return 1; if (!(pj_merc = pj_init_plus("+proj=merc +ellps=clrk66 +lat_ts=33")) ) return 1; // PROJ.4 API 默認的經緯度都是使用弧度值 while (scanf("%lf %lf", &x, &y) == 2) { x *= DEG_TO_RAD; /* 經度 */ y *= DEG_TO_RAD; /* 緯度 */ // 進行座標轉換 p = pj_transform(pj_longlat, pj_merc, 1, 1, &x, &y, NULL ); printf("%.2f\t%.2f\n", x, y); } pj_free(pj_longlat); pj_free(pj_merc); return 0; }
使用PROJ v.5實現的相同程序:
// 使用新的頭文件 #include <proj.h> main(int argc, char **argv) { PJ *P; PJ_COORD c; // 建立墨卡託投影座標系 P = proj_create(PJ_DEFAULT_CTX, "+proj=merc +ellps=clrk66 +lat_ts=33"); if (P==0) return 1; while (scanf("%lf %lf", &c.lp.lam, &c.lp.phi) == 2) { // 度轉弧度 c.lp.lam = proj_torad(c.lp.lam); c.lp.phi = proj_torad(c.lp.phi); // 進行座標轉換(正算) c = proj_trans(P, PJ_FWD, c); printf("%.2f\t%.2f\n", c.xy.x, c.xy.y); } proj_destroy(P); }
舊版 API 函數 | 新版 API 函數 |
---|---|
pj_fwd | proj_trans() |
pj_inv | proj_trans() |
pj_fwd3 | proj_trans() |
pj_inv3 | proj_trans() |
pj_transform | proj_trans_array or proj_trans_generic |
pj_init | proj_create() |
pj_init_plus | proj_create() |
pj_free | proj_destroy() |
pj_is_latlong | proj_angular_output() |
pj_is_geocent | proj_angular_output() |
pj_get_def | proj_pj_info() |
pj_latlong_from_proj | No equivalent |
pj_set_finder | No equivalent |
pj_set_searchpath | No equivalent |
pj_deallocate_grids | No equivalent |
pj_strerrno | No equivalent |
pj_get_errno_ref | proj_errno() |
pj_get_release | proj_info() |
這是但願遷移代碼以使用PROJ 6的開發人員的過渡指南。
這裏顯示了舊API和新API之間的區別,並舉了幾個例子。 下面咱們用兩個不一樣的API實現相同的程序。 程序從命令行讀取輸入經度和緯度,並使用墨卡託投影將它們轉換爲投影座標。
咱們首先編寫PROJ v.4的程序:
#include <proj_api.h> main(int argc, char **argv) { projPJ pj_merc, pj_longlat; double x, y; // 建立座標參考系對象 if (!(pj_longlat = pj_init_plus("+proj=longlat +ellps=clrk66")) ) return 1; if (!(pj_merc = pj_init_plus("+proj=merc +ellps=clrk66 +lat_ts=33")) ) return 1; // PROJ.4 API 默認的經緯度都是使用弧度值 while (scanf("%lf %lf", &x, &y) == 2) { x *= DEG_TO_RAD; /* 經度 */ y *= DEG_TO_RAD; /* 緯度 */ // 進行座標轉換 p = pj_transform(pj_longlat, pj_merc, 1, 1, &x, &y, NULL ); printf("%.2f\t%.2f\n", x, y); } pj_free(pj_longlat); pj_free(pj_merc); return 0; }
使用PROJ v.6實現的相同程序:
#include <proj.h> main(int argc, char **argv) { PJ *P; PJ_COORD c; /* 注意: 在PROJ 6中強烈建議不要使用 PROJ 格式字符串來定義 CRS ,由於 PROJ 格式字符串*/ /* 不是描述 CRS 的一種好方式,準確說來是其對大地基準的描述不夠詳細。 */ /* 使用權威機構提供的座標系代碼(例如"EPSG:4326", etc...)或者WKT字符串來建立,將可以 */ /* 充分利用PROJ的「transformation engine」來肯定兩個CRS直接的最佳轉換方式 */ P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "+proj=longlat +ellps=clrs66", "+proj=merc +ellps=clrk66 +lat_ts=33", NULL); if (P==0) return 1; { /* 對於特定的使用狀況下(轉換先後座標系已知),這是沒有必要的。 */ /* proj_normalize_for_visualization() 確保預期座標順序和由 proj_trans() */ /* 返回的順序是 大地座標系下先經度後緯度,投影座標系下先東向後北向 */ /* 若是不是使用上面的PROJ字符串,而是使用 "EPSG:XXXX" 代碼,這多是必要的。 */ PJ* P_for_GIS = proj_normalize_for_visualization(C, P); if( 0 == P_for_GIS ) { proj_destroy(P); return 1; } proj_destroy(P); P = P_for_GIS; } while (scanf("%lf %lf", &c.lp.lam, &c.lp.phi) == 2) { /* 不須要轉換到弧度 */ c = proj_trans(P, PJ_FWD, c); printf("%.2f\t%.2f\n", c.xy.x, c.xy.y); } proj_destroy(P); }
舊版 API 函數 | 新版 API 函數 |
---|---|
pj_fwd | proj_trans() |
pj_inv | proj_trans() |
pj_fwd3 | proj_trans() |
pj_inv3 | proj_trans() |
pj_transform | proj_create_crs_to_crs() + (proj_normalize_for_visualization() +) proj_trans() , proj_trans_array() or proj_trans_generic() |
pj_init | proj_create() / proj_create_crs_to_crs() |
pj_init | proj_create() / proj_create_crs_to_crs() |
pj_free | proj_destroy() |
pj_is_latlong | proj_get_type() |
pj_is_geocent | proj_get_type() |
pj_get_def | proj_pj_info() |
pj_latlong_from_proj | No direct equivalent, but can be accomplished by chaining proj_create() , proj_crs_get_horizontal_datum() and proj_create_geographic_crs_from_datum() |
pj_set_finder | proj_context_set_file_finder() |
pj_set_searchpath | proj_context_set_search_paths() |
pj_deallocate_grids | No equivalent |
pj_strerrno | No equivalent |
pj_get_errno_ref | proj_errno() |
pj_get_release | proj_info() |