前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于 ArcGIS 的坐标系转换

基于 ArcGIS 的坐标系转换

作者头像
被水淹没
发布2023-02-25 19:21:23
2.5K0
发布2023-02-25 19:21:23
举报
文章被收录于专栏:迈向架构师迈向架构师

基于 ArcGIS 的坐标系转换

在开发 GIS 相关系统的时候,我们常常遇见坐标转换的问题。

这里先大致介绍下坐标系的原理。

坐标系

我们常用到的坐标系一般分为两大类

  1. 地理坐标系(GCS)
  2. 投影坐标系(PCS)

地理坐标系就是把地球当成一个球体来看,以球心为参照点,通过经纬度来定位某个坐标点。

投影坐标系是指把地球这个球体垂直投影在一个平面。

图片引用自 数据规划那点事儿

投影坐标系

由于我们地球并非一个完美球体,而是凹凸不平的球体。面对地球表面的复杂地理环境,各地所使用的坐标系也就各不相同。

凹凸不平的地球

我国常见的地理坐标系有:

  • 北京54 坐标系
  • 西安80 坐标系
  • WGS-84 坐标系
  • 大地2000 坐标系
  • 其他独立坐标系(如火星坐标系、百度坐标系等,做了一定的变形与加密,目的是为了保护真实坐标,防止被恶意利用。)

地理坐标系进行水平面投影后,即可得到投影坐标系,常用投影坐标系

  • UTM 投影
  • 高斯-克吕格投影
  • 兰伯特正形圆锥投影

WKID

这里还得介绍下 WKID,由于各地使用了不同的坐标系、不同的投影方式、不同的投影分带,我们为众多的坐标系统打上一个唯一编号,也就是 WKID。

WKID 是一个ID,它的内容被称为WKT(Well-known Text),WKT 的二进制表现方式叫做WKB(well-known binary) 。WKT 包含内容如下:

  1. 总坐标系名
  2. 地理图形坐标系统名
  3. 基准面定义
  4. 椭球体的名字。长半轴和反扁率
  5. 本初子午线名和其与格林威治子午线的偏移值
  6. 投影方法类型(如横轴莫卡托)
  7. 投影参数列表(如中央经线等)
  8. 一个单位的名称和其米和弧度单位的转换参数
  9. 轴线的名称和顺序
  10. 在预定义的权威坐标系中的编码(如 EPSG)

举例:

代码语言:javascript
复制
["UTM Zone 19, Northern Hemisphere",(总体投影坐标带名字)
  GEOGCS["Geographic Coordinate System",(地理坐标系统名)      
    DATUM["NAD83",(基准面)
      SPHEROID["GRS 1980",6378137,298.2572220960423]椭球体,半径和反偏率
    ],
    PRIMEM["Greenwich",0],(中央经线,子午线)
    UNIT["degree",0.0174532925199433](转换因子 ""degree",0.0174532925199433" ""degree",0.0174532925199433")
  ],
  PROJECTION["Transverse_Mercator"], (投影方式)
  PARAMETER["latitude_of_origin",0], (起始经度)
  PARAMETER["central_meridian",-69], (中央经线)
  PARAMETER["scale_factor",0.9996],  (缩放比率)
  PARAMETER["false_easting",500000], (坐标整体向东偏移)
  PARAMETER["false_northing",0],     (坐标向北偏移)
  UNIT["Meter",1]                    (单位米)
]                     

重点主题来了

在开发 GIS 相关系统的时候,我们常常遇见坐标转换的问题。

比较常见的转换,例如WGS-84百度BD09坐标系、转大地2000坐标系等网上都有很多实现,国内的地图服务商(如百度、腾讯等)也有提供转换接口可供使用,但当你遇到一些比较特别的坐标系的时候,就需要自己来转换了。

经调研,有以下几种实现方式:

  • 手动实现
  • GDAL (OSGeo)
  • GeoTools (OSGeo)
  • ArcGIS

手动实现:通过三参数七参数来计算出不同坐标系的转换结果,由于计算过程复杂,参数一般也不公开,需要向政府申请获取,总体来说比较麻烦。

GDAL:GDAL 是栅格和矢量地理空间数据格式的翻译库,隶属于OSGeo(开源地理空间基金会)下的开源产品,它提供了任意栅格/矢量文件转换与处理。(如果有需要进行栅格/矢量文件转换与处理的话,可以选择 GDAL-ORG)

GeoTools:也隶属于OSGeo(开源地理空间基金会)下的开源产品,为地理空间数据提供工具。(如果单纯转坐标系,可以选择,GeoTools 只需引入包即可进行转换,很方便)

ArcGIS:由ESRI出品的一个地理信息系统系列软件。

考虑到后续可能要转 GIS 地图,所以这里选了 ArcGIS 的方式来转换坐标系。

java8 最高可使用100.4.0版本,如果是 java11 可以自己填最新的 ArcGIS 版本号。

正式开始

这里先放个调用 ArcGIS 的示例。

代码语言:javascript
复制
SpatialReference 空间参考坐标系A = SpatialReference.create( wkidA );
SpatialReference 空间参考坐标系B = SpatialReference.create( wkidB );
Point A点= new Point(x, y, 空间参考坐标系A);
Point B点= (Point) GeometryEngine.project(A点,空间参考坐标系B);

如果是某地区的独立坐标,可能没有 wkid,这时就得自己编写 WKT 文本(相当于自定义一个 wkid)。

这里是去官方拷了下最接近我的需求的 CGCS2000_3_Degree_GK_CM_114E的 WKT 文本,然后稍微修改了下变成了符合我需要的坐标系:

代码语言:javascript
复制
// 自定义一个空间参考坐标系    
String xx2000WktMercator = "PROJCS[\"CGCS2000_3_Degree_GK_CM_114E\"" +
        ",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\",500000.0]" +
        ",PARAMETER[\"False_Northing\",0.0]" +
        ",PARAMETER[\"Central_Meridian\",114.0]" +
        ",PARAMETER[\"Scale_Factor\",1.0]" +
        ",PARAMETER[\"Latitude_Of_Origin\",0.0]" +
        ",UNIT[\"Meter\",1.0]]";

// 创建自定义独立坐标系
SpatialReference xx2000sp = SpatialReference.create(xx2000WktMercator);
// 创建 WGS84 坐标系
SpatialReference wgs84sp = SpatialReference.create(4326);

定义了需要的坐标系后就可以实现从一个独立坐标系转换为 WGS84 的功能,然后再从 WGS84 转成其他的坐标系,如百度的 BD09 等:

代码语言:javascript
复制
// 自定义独立坐标系的点数据
Point pointXx2000 = new Point(lon, lat, xx2000sp);
// 把独立坐标系的点数据转化为 WGS84 点数据
Point pointWgs84 = (Point) GeometryEngine.project(pointXx2000, wgs84sp);
// 获取点数据中的经纬度, X为经度lon,Y为纬度lat
double pointWgs84X = pointWgs84.getX();
double pointWgs84Y = pointWgs84.getY();

环境配置

ArcGIS 不像 GeoTools 那么方便(直接导包即可使用),所以需要配置一下。

第一步:设置私服地址

由于 ArcGIS 的 maven 库是私服的,需要自己设置私服地址。

maven设置:settings.xml:

代码语言:javascript
复制
<mirror>
    <id>nexus-aliyun</id>
    <mirrorOf>*,!arcgis,!arcgis-plugin</mirrorOf>
    <name>Nexus aliyun</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

重点在<mirrorOf>*,!arcgis,!arcgis-plugin</mirrorOf>,这里我 maven 之前设置过私服,所以要排除掉 ArcGIS 的私服下载,这样的话 maven 会使用项目POM.xml中的自定义配置:

代码语言:javascript
复制
<!--自定义的私服:包括阿里云私服以及arcgis地图工具的私服 -->
<repositories>
    <repository>
        <id>aliyun</id>
        <name>aliyun Repository</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>arcgis</id>
        <url>https://esri.bintray.com/arcgis</url>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>arcgis-plugin</id>
        <url>https://esri.bintray.com/arcgis</url>
    </pluginRepository>
</pluginRepositories>

<dependencies>
    <!--ArcGIS Runtime SDK jar dependency  java8最高使用100.4.0版本,如果是java11可以自己填最新版本号-->
    <dependency>
        <groupId>com.esri.arcgisruntime</groupId>
        <artifactId>arcgis-java</artifactId>
        <version>100.4.0</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <!--ArcGIS Java Maven Plugin-->
        <plugin>
            <groupId>com.esri.arcgisruntime</groupId>
            <artifactId>arcgis-java-maven-plugin</artifactId>
            <version>1.0</version>
            <configuration>
                <!--specify the SDK version-->
                <version>100.4.0</version>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <release>11</release>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.6.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>java</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <mainClass>com.mycompany.app.App</mainClass>
            </configuration>
        </plugin>
        <plugin>
            <groupId>io.takari</groupId>
            <artifactId>maven</artifactId>
            <version>0.7.4</version>
        </plugin>
    </plugins>
</build>

plugin 填写后可以直接执行 maven 命令下载 ArcGIS 依赖库

Mavendependency:unpack

或者在 IDEA 里双击执行:

等同 Mavendependency:unpack

以上操作会自动将本地库下载解压到本机的$USER_HOME/.arcgis文件夹中:

$USER_HOME/.arcgis

也可以直接手动把db文件夹下的.arcgis解压到上面的文件夹中。

API 将自动在此目录中查找以查找本机库(也可以手动指定,如设置环境变量或放至应用根目录,请查阅官方sdk指南)。

如果未正确配置本机库,你将看到类似于以下内容的异常:

代码语言:javascript
复制
Caused by: java.lang.RuntimeException: Could not find runtime in any of:
- A directory specified by calling ArcGISRuntimeEnvironment.setInstallDirectory()
- The current directory C:\Users\johndoe\my-project-directory
- A location specified by the environment variable ARCGISRUNTIMESDKJAVA_100_4_0
- Within the ".arcgis" directory in the user's home path C:\Users\johndoe\.arcgis

手动设置本地库的方法:

设置环境变量:ARCGISRUNTIMESDKJAVA_10****** 指向arcgis的根目录(环境变量名需要使用当前版本的变量名,而 arcgis 本地依赖库目录无须版本号):

配置环境变量 ARCGISRUNTIMESDKJAVA_100_4_0 指向自定义文件夹 D:testArcGIS

或者直接把本地依赖库放到应用根目录里:

应用根目录

实例

自己实际用的工具类示例:

代码语言:javascript
复制
import com.esri.arcgisruntime.geometry.GeometryEngine;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.geometry.SpatialReference;
/**
* 地图坐标转换工具类
*/
public class MapCoordTransUtils {
    /**
     * fs2000 转 wgs84
     */
    private static CoordinatesDTO fs2000ToWgs84(Double lat, Double lon) {
        // 自定义一个空间参考坐标系:佛山2000独立系 
        // 通过zf公开文件得知的值:中央子午线113度和700KM偏移
        String fs2000WktMercator = "PROJCS[\"CGCS2000_3_Degree_GK_CM_113E\"" +
                ",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\",700000.0]" +
                ",PARAMETER[\"False_Northing\",0.0]" +
                ",PARAMETER[\"Central_Meridian\",113.0]" +
                ",PARAMETER[\"Scale_Factor\",1.0]" +
                ",PARAMETER[\"Latitude_Of_Origin\",0.0]" +
                ",UNIT[\"Meter\",1.0]]";

        SpatialReference fs2000sp = SpatialReference.create(fs2000WktMercator);
        SpatialReference wgs84sp = SpatialReference.create(4326);
        // FS2000点数据
        Point pointFs2000 = new Point(lon, lat, fs2000sp);
        // 把FS2000点数据转化为WGS84点数据
        Point pointWgs84 = (Point) GeometryEngine.project(pointFs2000, wgs84sp);
        // 获取点数据中的经纬度, X为经度lon,Y为纬度lat
        double pointWgs84X = pointWgs84.getX();
        double pointWgs84Y = pointWgs84.getY();
        return new CoordinatesDTO(pointWgs84Y, pointWgs84X);
    }

    /**
     * 佛山2000转百度09
     *
     * @param lat =y
     * @param lon =x
     * @return
     */
    public static CoordinatesDTO fs2000ToBD09(Double lat, Double lon) {
        // 先转wgs84
        CoordinatesDTO wgs84 = fs2000ToWgs84(lat, lon);
        // 把wgs84点坐标转化为bdo9点坐标
        // 这里是直接使用别人写好的工具类:
        // https://blog.csdn.net/a13570320979/article/details/51366355 
        // 而且改名为:MapCoordConversionUtils
        double[] gps84ToBd09 = MapCoordConversionUtils.gps84_To_bd09(wgs84.getLat(), wgs84.getLon());
        return new CoordinatesDTO(gps84ToBd09[0], gps84ToBd09[1]);
    }
}

自己 build 用的 dockerfile

代码语言:javascript
复制
# 这里填写中间件版本,不填版本号默认最新版
FROM tomcat:9.0.21-jdk8

# 使用root用户
USER root

# 进入目录
WORKDIR /usr/local/

# 创建项目文件夹,并将外部文件夹内容添加进去
RUN mkdir project
ADD ./project ./project
RUN cd project

# 配置环境变量 
ENV ARCGISRUNTIMESDKJAVA_100_4_0 /usr/local/project

# 国内镜像
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
# 安装环境 arcgis 需要 [libgl1-mesa-glx]
RUN apt-get clean && apt-get update && apt install -y nano vim libgl1-mesa-glx

#开放端口
EXPOSE 8080

#启动命令
CMD ["java","-jar","/usr/local/project/springboot.jar","--spring.profiles.active=docker"]

疑难杂症

找不到依赖库解决方法

  • Windows:
    • 下载DirectX4.0,安装dll以及C++
  • Linux(docker也适用):
    • sudo apt update
    • sudo apt install libgl1-mesa-glx
    • 安装 libgl1-mesa-glx 依赖 ↑

可供参考资料

ArcGIS Runtime SDK 官方文档[1]

WKID 官方文档[2]

GIS坐标系转换指南-叫我三三就好[3]

geotools 官网[4]

gdal 官网[5]

gdal 坐标参考系和坐标转换教程[6]

[1]

ArcGIS Runtime SDK 官方文档: https://developers.arcgis.com/java/get-started/

[2]

Projected Coordinate Systems(WKID 官方文档): https://developers.arcgis.com/javascript/3/jshelp/pcs.html

[3]

这可能是最简单的GIS坐标系转换指南了-叫我三三就好: https://zhuanlan.zhihu.com/p/122217326

[4]

geotools 官网: https://www.geotools.org/

[5]

gdal官网: https://gdal.org/

[6]

gdal 官网的坐标参考系和坐标转换教程: https://gdal.org/tutorials/osr_api_tut.html

今天的分享就先到这,本文主要讲了如何使用 ArcGIS 来转换坐标系数据。

下一篇分享如何使用 GDAL 实现任意栅格/矢量文件转换。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 迈向架构师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基于 ArcGIS 的坐标系转换
    • 坐标系
      • WKID
        • 重点主题来了
          • 正式开始
            • 环境配置
              • 实例
                • 疑难杂症
                  • 找不到依赖库解决方法
                • 可供参考资料
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档