GeoTools 自定義坐標系

前言

GIS開發中,坐標系統是重中之重,在接到任務時首先要確定的就是坐標系。大多數地圖庫或者互聯網地圖默認支持WGS84地理坐標系和Web墨卡托投影坐標系。而在我國要求使用自然資源數據使用2000國家大地坐標(CGCS2000)

1. 背景

經國務院批準,我國自2008年7月1日起,啟用2000國家大地坐標系

2000國家大地坐標系與原有國家大地坐標系轉換、銜接的過渡期為8至10年。根據原國家測繪地理信息局下發的《關于加快2000國家大地坐標系推廣使用的通知》(國測國發﹝2013﹞11號)和原國土資源部、原國家測繪地理信息局聯合發文《關于加快使用2000國家大地坐標系的通知》(國土資發﹝2017﹞30號)的文件要求,明確自2018年7月1日起全面使用2000國家大地坐標系

2018年6月底前完成全系統各類國土資源空間數據向2000國家大地坐標系轉換,7月1日后涉及空間坐標的報部審查和備案項目,全部采用2000國家大地坐標系,不再接受非2000系上報的項目報件。

2018年12月,自然資源部發布《關于停止提供1954年北京坐標系和1980西安坐標系基礎測繪成果的公告》(2018年第55號),決定自2019年1月1日起,全面停止向社會提供1954年北京坐標系和1980西安坐標系基礎測繪成果。

基于上述內容要求,在生產實踐中,從數據生產到數據成果入庫,都需要使用2000國家大地坐標系。

2. 開發環境

本文使用如下開發環境,以供參考。
:::block-1
時間:2025年

GeoTools:v34-SNAPSHOT

IDE:IDEA2025.1.2

JDK:v17

OpenLayers:v9.2.4

Layui:v2.9.14
:::

3. 自定義坐標系統

在項目目錄utils下新建一個工具類CrsLab,使用final定義幾個常用坐標系常量。坐標系的定義有多種標準,包括ogc標準、esri標準、Proj4js以及PostGIS等。在GeoTools中,采用符合行業規范的OGC標準格式。其中OGC格式又分為OGC WKT和OGC WKT2,代碼中分別表示為epsg4522wktepsg4522wkt2,經過測試驗證,目前尚未支持OGC WKT2格式。

最后定義一個坐標系解析方法getCRSByCodeNumber以返回目標坐標系統,該方法接收一個數字字符串參數,即EPSG編碼,如WGS84編碼為4326、web墨卡托編碼為3857(又900913或者3785)、CGCS2000編碼為4490。將坐標系常量傳遞給parseWKT解析為目標坐標系。

package org.geotools.utils;import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
import org.geotools.referencing.CRS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class CrsLab {private static final Logger log = LoggerFactory.getLogger(CrsLab.class);// ogc wkt formatfinal static String epsg4490 = "GEOGCS["China Geodetic Coordinate System 2000",n" +"    DATUM["China_2000",n" +"        SPHEROID["CGCS2000",6378137,298.257222101,n" +"            AUTHORITY["EPSG","1024"]],n" +"        AUTHORITY["EPSG","1043"]],n" +"    PRIMEM["Greenwich",0,n" +"        AUTHORITY["EPSG","8901"]],n" +"    UNIT["degree",0.0174532925199433,n" +"        AUTHORITY["EPSG","9122"]],n" +"    AUTHORITY["EPSG","4490"]]";// ogc wkt formatfinal static String epsg4522wkt = "PROJCS["CGCS2000 / 3-degree Gauss-Kruger zone 34",n" +"    GEOGCS["China Geodetic Coordinate System 2000",n" +"        DATUM["China_2000",n" +"            SPHEROID["CGCS2000",6378137,298.257222101,n" +"                AUTHORITY["EPSG","1024"]],n" +"            AUTHORITY["EPSG","1043"]],n" +"        PRIMEM["Greenwich",0,n" +"            AUTHORITY["EPSG","8901"]],n" +"        UNIT["degree",0.0174532925199433,n" +"            AUTHORITY["EPSG","9122"]],n" +"        AUTHORITY["EPSG","4490"]],n" +"    PROJECTION["Transverse_Mercator"],n" +"    PARAMETER["latitude_of_origin",0],n" +"    PARAMETER["central_meridian",102],n" +"    PARAMETER["scale_factor",1],n" +"    PARAMETER["false_easting",34500000],n" +"    PARAMETER["false_northing",0],n" +"    UNIT["metre",1,n" +"        AUTHORITY["EPSG","9001"]],n" +"    AUTHORITY["EPSG","4522"]]";final static String epsg4522wkt2 = "PROJCRS["CGCS2000 / 3-degree Gauss-Kruger zone 34",BASEGEOGCRS["China Geodetic Coordinate System 2000",DATUM["China 2000",ELLIPSOID["CGCS2000",6378137,298.257222101,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4490]],CONVERSION["3-degree Gauss-Kruger zone 34",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",102,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",1,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",34500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["northing (X)",north,ORDER[1],LENGTHUNIT["metre",1]],AXIS["easting (Y)",east,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Cadastre, engineering survey, topographic mapping (large scale)."],AREA["China - between 100°30'E and 103°30'E."],BBOX[21.13,100.5,42.69,103.5]],ID["EPSG",4522]]";// esri wkt formatfinal static String epsg4522esriwkt =  "PROJCS["CGCS2000_3_Degree_GK_Zone_34",GEOGCS["GCS_China_Geodetic_Coordinate_System_2000",DATUM["D_China_2000",SPHEROID["CGCS2000",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Gauss_Kruger"],PARAMETER["False_Easting",34500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",102.0],PARAMETER["Scale_Factor",1.0],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]";final static String epsg3857 = "PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3857"]]";public static CoordinateReferenceSystem getCRSByCodeNumber(String epsgCode) throws Exception {CoordinateReferenceSystem crs = null;if(epsgCode.equals("4490")){crs = CRS.parseWKT(epsg4490);}else if(epsgCode.equals("4522")){crs = CRS.parseWKT(epsg4522esriwkt);}else if(epsgCode.equals("3857")){crs = CRS.parseWKT(epsg3857);}System.out.println("坐標系統:"+CRS.toSRS(crs));// 坐標系統:CGCS2000_3_Degree_GK_Zone_34return crs;}
}

編寫完成以上代碼已經可以根據系統要求自定義坐標系了。

以下介紹一些拓展信息。GeoTools中有一個接口CRSAuthorityFactory提供了getSupportedCodes(String authority)方法,用于獲取指定權威機構(authority)支持的所有坐標參考系統(CRS)的代碼。這里的authority參數指的是定義CRS的權威機構的名稱,如“EPSG”。

常見的權威機構包括:

可以通過以下方法獲取各權威機構坐標定義數量及編號使用情況。

// 獲取 CRS 權威工廠
CRSAuthorityFactory authorityFactory = CRS.getAuthorityFactory(true);// 指定權威機構并獲取支持的代碼
String authority = "EPSG"; // 這里可以替換為其他權威機構
Set<String> authorityCodes = authorityFactory.getAuthorityCodes(CoordinateReferenceSystem.class);
System.out.println("authorityCodes:"+authorityCodes);Set<String> supportedCodes = CRS.getSupportedCodes(authority);
// 輸出默認支持的坐標系
System.out.println("默認支持的EPSG坐標系數量:"+supportedCodes.size());
System.out.println("默認支持的EPSG坐標列表:"+supportedCodes);

以EPSG權威機構為例,輸出信息如下,首次調用輸出情況可能會稍慢,數據量還是有點多。
:::block-1
authorityCodes:[AUTO:42001, AUTO:42002, AUTO:42003, AUTO:42004, AUTO:97001,······]

默認支持的EPSG坐標系數量:7921

默認支持的EPSG坐標:[WGS84(DD), 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,······]
:::
檢查目標坐標系是否存在,如CGCS2000_3_Degree_GK_Zone_34(4522)

// 檢查指定坐標是否被支持
String epsgcode = "4522"; // CGCS2000_3_Degree_GK_Zone_34
if (supportedCodes.contains(epsgcode)) {System.out.println(authority + "權威機構支持 EPSG 編碼為 " + epsgcode + " 的坐標系");
}else{System.out.println(authority + " 權威機構暫不支持 EPSG 編碼為 " + epsgcode + " 的坐標系");
}

在EPSG權威機構中進行查找,以上代碼將會輸出EPSG權威機構支持 EPSG 編碼為 4522 的坐標系

將上述變量epsgcode的值改為4490,通過輸出結果EPSG權威機構支持 EPSG 編碼為 4490 的坐標系可以看到該坐標系也是受到支持的。

以下代碼可以用于獲取常用權威機構支持的坐標信息。

// 獲取常用權威機構支持的代碼
Set<String> epsgCodes = getSupportedCodes("EPSG");  // 標準地理坐標系
Set<String> esriCodes = getSupportedCodes("ESRI");  // Esri特定坐標系
Set<String> iauCodes = getSupportedCodes("IAU");    // 天體坐標系
Set<String> autoCodes = getSupportedCodes("AUTO");  // 自動投影

我們知道在GeoTools中可以直接使用CRS.decode("EPSG:4326")此種方式定義目標坐標系,這種方式使用起來簡單明了,那么為什么不直接使用此種方式,而是要自定義坐標系統呢?

下面來看一下我使用兩種方式將Shp數據經過坐標轉換后導入PostGIS空間數據庫的輸出結果。坐標系為WGS84地理坐標系,元數據定義如下:
:::block-1
GEOGCS["Geographic Coordinate System",DATUM["D_WGS84",SPHEROID["WGS84",6378137,298.257223560493]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
:::
(1)CrsLab.getCRSByCodeNumber("4522")

(2)CRS.decode("EPSG:4522")

從以上輸出結果來看,使用兩種方式轉換的數據,坐標值存在一定的差異。第二種方式x和y值的順序相反,與工作實際使用不太相符,要怎么解決這種情況呢?需要在坐標定義時多加一個布爾值參數,CoordinateReferenceSystem targetCrs = CRS.decode("EPSG:4522",Boolean.TRUE),并將參數值設置為TRUE即可。

在GIS軟件ArcMap中打開經過投影轉換后的Shp數據,其坐標顯示結果與使用GeoTools轉換入庫后的結果保持一致。

4. 坐標轉換

在進行坐標轉換前,需要獲取源數據坐標系信息,然后使用以下任意一種方式定義目標坐標系,使用第二種方式的時候需要注意x和y坐標的順序,將第二個參數設置為TRUE可使得數據與日常使用習慣保持一致。

坐標轉換流程大致如下

// 源數據坐標系
CoordinateReferenceSystem originalCrs = dataSchema.getCoordinateReferenceSystem();
// 方式一:自定義坐標系
// CoordinateReferenceSystem targetCrs =  CrsLab.getCRSByCodeNumber("4522");// 方式二:使用epsg code 定義坐標系,強制使用經度在前、緯度在后的順序
CoordinateReferenceSystem targetCrs =  CRS.decode("EPSG:4522",Boolean.TRUE);

使用findMathTransform進行坐標轉換。第一個參數為原始坐標系,第二個參數為目標坐標系,第三個參數表示即使沒有可用于基準偏移的信息,也應該創建數學變換。默認值為false。

// 定義坐標轉換
MathTransform transform = CRS.findMathTransform(originCrs,targetCrs,true);

獲取到源幾何對象之后,調用JTS.transform方法對其進行坐標轉換,最后將轉換完成的幾何對象寫入幾何字段。

// 源幾何對象
Geometry sourceGeometry = (Geometry) feature.getDefaultGeometry();
// 轉換后的幾何對象
Geometry crsTransformGeometry = JTS.transform(sourceGeometry, transform);
// 設置參考系數字
crsTransformGeometry.setSRID(4522);
// 寫入轉換后的幾何對象
targetFeature.setAttribute("geom", crsTransformGeometry);

5. 查看數據庫坐標系

將成果數據導入PostGIS空間數據庫之后,怎么知道使用了正確的坐標系了呢?在PostGIS中,有以下幾種方式可以查看數據坐標系。

(1)使用ST_SRID函數

SELECT ST_SRID(geom) AS srid FROM province LIMIT 3;

該方法會返回表中第一個幾何列的空間參考ID(SRID)。

(2)查詢 geometry_columns視圖
:::block-1
SELECT f_table_name, f_geometry_column, srid FROM geometry_columns WHERE f_table_name = ‘你的表名’; // 如 province
:::
該方式也會返回幾何列的空間參考ID(SRID)。

6. 坐標拓展

https://epsg.io網站查詢出的坐標系信息有多種格式,包括OGC WKT、OGC WKT2以及ESRI WKT等。正常情況下,可以采用OGC WKT、ESRI WKT兩種方式定義坐標系。

(1)OGC WKT格式

(2)OGC WKT2格式

(3)ESRI WKT格式

使用時可以直接選中復制坐標信息,也可以點擊【Copy Text】按鈕或者【Copy Formatted】按鈕進行復制。

7. 參考資料

  • EPSG 坐標系網站:https://epsg.io

  • GeoTools API:https://docs.geotools.org/latest/javadocs/org/geotools/api/referencing/crs/CoordinateReferenceSystem.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92123.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92123.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92123.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[特殊字符] Java反射從入門到飛升:手撕類結構,動態解析一切![特殊字符]

【&#x1f50d;震撼揭秘】 你是否曾想窺探Java類的內部結構&#xff1f;&#x1f914; 是否好奇Spring框架如何實現"萬物皆可注入"&#xff1f;? 本文將帶你從反射小白晉升為反射高手&#xff0c;用一行代碼透視任意類的構造方法、成員變量和私有方法&#xff01;&…

CMake與catkin_make的find_package()命令使用說明

在 CMake 中&#xff0c;find_package() 是一個核心函數&#xff0c;用于查找并加載外部依賴庫的配置。它的主要作用是定位頭文件、庫文件&#xff0c;并設置相關變量&#xff0c;以便后續編譯和鏈接。以下是詳細解析&#xff1a; 1. 基本語法 find_package(<PackageName&g…

Spring--BeanFactoryPostProcessor的用法

原文網址&#xff1a;Spring--BeanFactoryPostProcessor的用法_IT利刃出鞘的博客-CSDN博客 簡介 說明 本文介紹Spring的BeanFactoryPostProcessor的用法。 BeanPostProcessor和BeanFactoryPostProcessor的區別 項BeanPostProcessorBeanFactoryPostProcessor處理的對象處理…

了解類加載器嗎?類加載器的類型有哪些?

一、什么是類加載器&#xff08;ClassLoader&#xff09; 類加載器是 Java 虛擬機中的一部分&#xff0c;負責將 .class 文件加載到 JVM 內存中&#xff0c;生成對應的 Class 對象。 Java 程序中所有的類在使用前都必須通過類加載器加載進 JVM&#xff0c;才能被執行。二、類加…

PHP面向對象高級特性:魔術方法、對象迭代器與設計模式應用

引言 在前一篇文章中,我們探討了PHP的Traits、匿名類和對象比較機制。本文將深入PHP面向對象編程的更多高級特性,包括魔術方法、對象迭代器以及常用設計模式的實際應用,這些特性能夠幫助開發者構建更加靈活和強大的面向對象系統。 魔術方法深度解析 魔術方法是PHP中一組以…

【Java基礎】一個月教你輕松掌握Java——第三篇Git

一、Java概述&#xff08;之前的文章&#xff09;二、版本控制工具Git其實這個與Java基礎關系不大&#xff0c;但是這個工具還是很重要的&#xff0c;不管是團隊之間打比賽還是就業都應該學會它&#xff0c;秉持著學的早一些&#xff0c;用的時間長一點&#xff0c;會更熟練。&…

【C# in .NET】16. 探秘類成員-索引器:通過索引訪問對象

探秘類成員-索引器:通過索引訪問對象 在 C# 中,索引器(Indexer)是一種獨特的類成員,它允許類或結構的實例像數組一樣被索引訪問,為數據訪問提供了極大的靈活性。本文將從基礎概念出發,深入.NET 框架底層,剖析索引器的實現機制,并通過實戰案例展示其強大的應用價值。 …

idea出現:java: Target level ‘1.7‘ is incompatible with source level ‘1.8‘.解決辦法

在文件->設置->java編譯器&#xff0c;把這里版本對應上。這里用的是8版本

ssms(SQL 查詢編輯器) 添加快捷鍵 Ctrl+D(功能等于Ctrl+C + Ctrl+V),一步到位

1,打開ssms 工具&#xff0c;打開對應添加快捷鍵得地方2&#xff0c;分配 快捷鍵3&#xff0c;看效果

數學建模--層次分析法

層次分析法&#xff08;AHP&#xff09;筆記 一、核心概念 &#xff08;一&#xff09;問題本質 面對多方案、多準則決策&#xff0c;將復雜問題分層拆解&#xff0c;通過定性與定量結合&#xff0c;確定各因素權重&#xff0c;選出最優方案&#xff0c;比如選“微博之星”時綜…

人工智能教研室暑期培訓flask全棧開發培訓

人工智能教研室暑期培訓flask全棧開發培訓第一天&#xff1a;Flask 基礎入門與環境搭建實踐項目&#xff1a;搭建個人博客首頁&#xff0c;包含文章列表與詳情頁上午&#xff1a;環境搭建與 Flask 基礎1. 安裝 Python 與虛擬環境配置2. Flask 框架簡介與第一個 "Hello Wor…

MySQL(141)如何處理重復數據問題?

處理重復數據問題是數據管理中的一個常見挑戰。重復數據會影響數據庫的性能、占用資源&#xff0c;并且可能導致數據分析結果的偏差。以下是處理重復數據問題的詳細步驟以及結合代碼的示例。 一、識別重復數據 首先&#xff0c;需要識別數據庫中的重復數據。可以使用 SQL 查詢來…

MySQL 核心知識點梳理(3)

目錄 SQL優化 23什么是慢SQL 如何優化呢? 如何利于覆蓋索引 如何使用聯合索引 如何進行分頁優化 Join代替子查詢 為什么要小表驅動大表? 為什么避免join太多的表? 如何進行排序優化 什么是filesort 全字段排序和rowid排序 條件下推 索引 索引為什么能提高MyS…

關于注冊登錄功能制作的步驟(文件IO存儲+LVGL彈窗提示)

按你的需求&#xff08;文件IO存儲LVGL彈窗提示&#xff09;&#xff0c;工程需創建以下文件&#xff0c;代碼按功能模塊化存放&#xff0c;清晰明了&#xff1a;一、需要創建的文件清單 文件名 作用 存放內容 main.c 程序入口 主函數、硬件初始化、LVGL初始化、啟動界面 ui.…

自媒體端后臺設計指南:從注冊認證到內容管理的全流程搭建

自媒體端后臺設計指南&#xff1a;從注冊認證到內容管理的全流程搭建自媒體端后臺是專業創作者管理內容、粉絲和數據的核心陣地&#xff0c;其設計直接影響創作效率和平臺運營質量。一個功能清晰、操作便捷的后臺系統&#xff0c;能讓創作者專注于內容生產&#xff0c;而非被復…

uniapp掃描二維碼反色處理

在開發掃描二維碼過程中&#xff0c;發現白底黑碼可以直接用uni.scanCode掃描出來&#xff0c;但是黑底白碼就掃不出來&#xff0c;于是就試試反色后的二維碼能不能掃描出來&#xff0c;沒想到真的可以&#xff0c;下面附上完整代碼&#xff1a; <u-icon name"scan&quo…

C語言定義fixed_t什么意思

在 C 語言中&#xff0c;fixed_t 通常是一個自定義的類型別名&#xff08;typedef&#xff09;&#xff0c;用于表示固定點數&#xff08;Fixed-Point Number&#xff09;&#xff0c;而非 C 語言標準庫中的原生類型。它主要用于需要高效實數運算但無法使用浮點數的場景&#x…

音頻3A處理簡介之ANS(自動噪聲抑制)

我們常用的手機、消費類攝像頭等產品的麥克風所采集的原始聲音信號中往往包含了比較多的背景噪音&#xff0c;不僅影響用戶錄音和回放的使用體驗&#xff0c;而且這些噪聲數據還會降低音頻編碼的壓縮效率&#xff0c;因此有必要對音頻底噪進行抑制處理&#xff0c;這就是ANS&am…

Python 使用期物處理并發(使用concurrent.futures模塊啟動 進程)

使用concurrent.futures模塊啟動進程 concurrent.futures 模塊的文檔 &#xff08;https://docs.python.org/3/library/concurrent.futures.html&#xff09;副標題 是“Launching parallel tasks”&#xff08;執行并行任務&#xff09;。這個模塊實現的是真正 的并行計算&…

【系統全面】Linux內核原理——基礎知識介紹

理解內核&#xff1a;內核原理 計算機系統的軟件分層 不同于單片機中使用代碼直接與硬件交互&#xff0c;對于這種方式的缺點深有&#xff1a; &#xff08;1&#xff09;復雜度高&#xff0c;調用難度高&#xff0c;需要深入理解硬件的工作原理和細節。 &#xff08;2&#xf…