如何把空间数据[Geometry类型]从CGCS2000[2000国家大地坐标系]转换到WGS84坐标和BD09坐标 ---JAVA语言实现

如何把空间数据[Geometry类型]从CGCS2000[2000国家大地坐标系]转换到WGS84坐标系和BD09坐标系 ---JAVA语言实现

  • ==1.背景说明==
  • ==2.名词说明==
    • 空间数据
    • 坐标系与坐标
    • CGCS2000
    • WGS84
    • BD09
  • ==3.读取数据库中的geometry数据==
    • 可能遇到的问题
    • 解决办法
  • ==4.坐标转换的工具类==
    • CGCS2000坐标 转换为WGS84和BD09坐标的工具类代码
    • 相关说明-BD09坐标系中点的表示
    • 相关说明-WGS84坐标转BD09坐标的工具类
  • ==5.声明==

1.背景说明

最近的项目中涉及到空间数据的转换,主要把CGCS200坐标转换为WGS84坐标和BD09坐标。我在网上找了一天多,只找到了WGS84坐标转BD09坐标的工具类,但没有找到CGCS200转换到WGS84坐标的工具类。我实在没有办法,就只有自己写。但我不太熟悉测量学知识,就只有从ArcGIS提供的 ArcGIS Runtime SDK for Java中寻找方法。目前已经完成此工具类,测试效果也还不错。现在写出这篇文章,共享我的代码,希望能帮到有同样问题的同行。

2.名词说明

首先阐释下相关的名词概念,以免读者混淆。

空间数据

从数据库的角度来看,是指在表中以geometry类型存在的数据。
从java语言的角度来看,是指com.esri.arcgisruntime.geometry包下各种类型数据,包括Point、Multipoint、Polyline、Polygon等等.

坐标系与坐标

本文中,xx坐标表示xx坐标系下的空间数据对象,xx坐标系才是表示xx坐标系本身。请注意区别。

CGCS2000

CGCS2000就是2000国家大地坐标系,是我国当前最新的国家大地坐标系,英文名称为China Geodetic Coordinate System 2000,缩写为CGCS2000。
该坐标系在ArcGIS中有众多子坐标。如下图所示。
本文选用的是CGCS2000_3_Degree_GK_CM_105E。
如何把空间数据[Geometry类型]从CGCS2000[2000国家大地坐标系]转换到WGS84坐标和BD09坐标 ---JAVA语言实现_第1张图片

WGS84

WGS84:World Geodetic System 1984,是为GPS全球定位系统使用而建立的坐标系统。通过遍布世界的卫星观测站观测到的坐标建立,其初次WGS84的精度为1-2m,在1994年1月2号,通过10个观测站在GPS测量方法上改正,得到了WGS84(G730),G表示由GPS测量得到,730表示为GPS时间第730个周。1996年,National Imagery and Mapping Agency (NIMA) 为美国国防部 (U.S.Departemt of Defense, DoD)做了一个新的坐标系统。这样实现了新的WGS版本:WGS(G873)。其因为加入了USNO站和北京站的改正,其东部方向加入了31-39cm 的改正。所有的其他坐标都有在1分米之内的修正。第三次精化:WGS84(G1150),于2002年1月20日启用。(此段解释来自百度百科)

BD09

BD09坐标系就是百度地图坐标系,它是在标准Web墨卡托的基础上进行GCJ-02加偏之后,再加上百度自身的加偏算法,也就是在Web墨卡托的基础之上进行了两次加偏。坐标系的坐标值为Web墨卡托格式,单位为米。(此段解释来自百度百科)

3.读取数据库中的geometry数据

可能遇到的问题

本文通过Spring data jpa连接数据库,笔者参照 在java程序中如何读写带有Geometry对象的表 这一文章,在实体类中加入 Geometry,或Polygon 类的字段后,项目启动就会报错。 如果有读者参照那篇文章,或者用其他方式,能成功地把数据库中的geometry字段映射到实体类中,并查询出来,请留言给我,我也希望能向您学习一下。

解决办法

我采用的方式是在数据库用SQL语句查询出geometry字段的String表达形式,再做后续处理。代码片段如下:

   @Query( value = "select SHAPE.STAsText() FROM LAND WHERE ID=?", nativeQuery = true)
    String  getShapeString (String id);

下面这个字符串是本文通过此方法在数据库中查询出来的,此字符串表示一个地块的坐标,逗号分隔出每个坐标点,多个坐标点连成一个面。(此数据是测试数据,由笔者随意编造,没有描述任何真实意义)

POLYGON ((370907.330099999904697 3418398.496099999174576, 370899.395100000314615 3418410.75789999861853, 370909.574500000104318 3418415.690899999812245))

4.坐标转换的工具类

CGCS2000坐标 转换为WGS84和BD09坐标的工具类代码

上面的这个字符串表示的是CGCS2000坐标系下的数据。我们写一个工具类将其转换为WGS84和BD09坐标。下面是具体代码。

package com.wja.test.report.utils;

import com.wja.test.report.model.dto.CoordinatesDTO;
import com.wja.test.util.JsonUtil;
import com.esri.arcgisruntime.geometry.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 用于坐标转换的工具类
 *
 * @author wang.jingan
 * @since 2019-07-20 10:39:16
 */
public class CoordTransform {
    /**
     * 通过String字符串得到三个坐标系的空间数据对象和json字符串
     *
     * @param  shape 转化为String的Geometry数据
     * @return  数据集,内含三个坐标系的空间数据对象和json字符串
     */
      public  static Map<String, Object> shapeStringToJsons(String shape){
          Map<String, Object> result = new HashMap<>();
          //获取两个坐标系
          SpatialReference cgcs2000 = SpatialReference.create(4544);
          SpatialReference wgs84 = SpatialReference.create(4326);
          //创建一个CGCS2000的点收集器,为创建Polygon对象做准备
          PointCollection land = new PointCollection(cgcs2000);
          //准备返回的百度坐标点集合
          List<CoordinatesDTO> pointsBD09 =new ArrayList<>();
          //获取需要的字符串
          String shapeSubstring = shape.substring(10,shape.length()-2);
          //得到每个点的原始数据
          String[] points = shapeSubstring.split(",");
          //遍历每个点
          for (String pointString:points) {
              //去前后的空格
              pointString=pointString.trim();
              //把经纬度分开成两个数据
              String[] xy = pointString.split(" ");
              Double x = Double.valueOf(xy[0]);
              Double y = Double.valueOf(xy[1]);
              //把点添加到点收集器
              land.add(x, y);

              //得到CGCS2000点数据
              Point pointCgcs2000 = new Point(x, y, cgcs2000);
              //把CGCS2000点数据转化为WGS84点数据
              Point pointwgs84 = (Point)GeometryEngine.project(pointCgcs2000,wgs84);

              //获取点数据中的经纬度,X为经度,Y为纬度
              double pointwgs84X = pointwgs84.getX();
              double pointwgs84Y = pointwgs84.getY();

              //把wgs84点坐标转化为bdo9点坐标
              double[] bd09 = GPSUtil.gps84_To_bd09(pointwgs84Y, pointwgs84X);
              CoordinatesDTO coordinatesDTO = new CoordinatesDTO();
              coordinatesDTO.setLat(bd09[0]);
              coordinatesDTO.setLon(bd09[1]);
              pointsBD09.add(coordinatesDTO);
          }
          //从点收集器中创建Polygon,得到一个cgcs2000的Polygon
          Polygon polygonCgcs2000 = new Polygon(land);
          //转换为wgs84的Polygon
          Polygon polygonWgs84 = (Polygon)GeometryEngine.project(polygonCgcs2000,wgs84);
          //装入返回数据
          result.put("cgcs2000",polygonCgcs2000);
          result.put("wgs84",polygonWgs84);
          result.put("bd09",pointsBD09);
          
          String polygonCgcs2000Json = polygonCgcs2000.toJson();
          String polygonWgs84Json = polygonWgs84.toJson();
          String pointsBD09Json = JsonUtil.toJson(pointsBD09);
          result.put("cgcs2000Json",polygonCgcs2000Json);
          result.put("wgs84Json",polygonWgs84Json);
          result.put("bd09Json",pointsBD09Json);
          
          return  result;
      }
}

相关说明-BD09坐标系中点的表示

在ArcGIS中wkid用于表示相关坐标系的代码, 并用SpatialReference.create(int wkid) 进行创建对应的坐标系。但BD09坐标系 在ArcGIS中没有相关的wkid,所以BD09坐标是通过点的集合表示,而WGS84的坐标是通过com.esri.arcgisruntime.geometry 包下的Polygon类的对象表示。
BD09坐标系的点是笔者自己定义的一个类。代码如下:

package com.wja.test.report.model.dto;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class CoordinatesDTO {

    private Double lat;
    private Double lon;
}

相关说明-WGS84坐标转BD09坐标的工具类

此工具类网上有很多,同时涉及到很多测量学和数学知识,我也不太擅长那些方面,所以就没有自己写,直接用了 各系地图坐标互相转换【JS版和Java版】 这篇文章的代码。

5.声明

本文的参考文献已经在正文中注明了出处。如果转载本文,也请注明出处和作者。这篇文章是我在CSDN上写的第一篇博客,时间仓促,技术有限,也不太了解CSDN上写博客的技巧,难免有些纰漏,欢迎读者指出其中的不足,也希望大家在博客下的留言区积极讨论。

你可能感兴趣的:(ArcGIS)