如何使用 GeoTools MathTransform?
How to use GeoTools MathTransform?
我需要使用 GeoTools Java 库将点从 EPSG:4312 转换为 WGS84。
但是我不确定我是否正确使用它,我也不确定它是否提供了正确的结果。
参见以下代码示例:
@Test
public void testSingle4312ToWGS84() throws FactoryException, TransformException {
double latitude = 29.0;
double longitude = -99.0;
CoordinateReferenceSystem sourceCrs = CRS.decode("EPSG:4312");
CoordinateReferenceSystem targetCrs = CRS.decode("EPSG:4326");
MathTransform engine = CRS.findMathTransform(sourceCrs, targetCrs, false);
DirectPosition source = new DirectPosition2D(sourceCrs, longitude, latitude);
DirectPosition target = new DirectPosition2D(targetCrs);
engine.transform(source, target);
System.out.println("x,y=" + target.getCoordinate()[0] + "," + target.getCoordinate()[1]);
}
当 运行 以上代码时,我得到以下结果:
x,y=-81.00483829765083,-150.99434404015307
这是错误的,因为 -150 不是有效的纬度。
当我创建 source 对象时,我用经度初始化 X,用纬度初始化 Y,遵循实际上 X 是经度,Y 是纬度的基本原理(根据地理社区)。
但是,如果我反转它们:
DirectPosition source = new DirectPosition2D(sourceCrs, latitude, longitude);
我现在得到了一个看起来更真实的结果:
x,y=29.003866857343915,-98.99222530180596
当然我现在必须将 X 解释为纬度,将 Y 解释为经度。
那么,问题 #1,我们是否应该使用逆有理将 X 视为纬度,将 Y 视为经度?
接下来,我想验证一下结果。首先,尝试使用 Oracle SQL SDO 函数转换相同的点:
select sdo_cs.transform (
MDSYS.SDO_GEOMETRY(2001, 4312, MDSYS.SDO_POINT_TYPE(-99, 29, NULL), NULL, NULL),
8307
) from dual;
提供以下结果:
MDSYS.SDO_GEOMETRY(2001, 8307, MDSYS.SDO_POINT_TYPE(-98.9924748682774, 29.0036029261273, NULL), NULL, NULL)
转换后的点与GeoTools生成的点类似,但相差~40米。
接下来,我尝试了这个 website 提供的转换,它提供了与 Oracle 相同的结果。
我还使用了 Luciad AIXM Viewer,一个用于 GML 的图形表示工具,它也将我的点显示在由 Oracle 计算的相同位置。
所以,我有 3 个独立的工具提供相同的结果点,与 GeoTools 计算的结果点相距 40 米。
问题 #2,为什么 Geotools 会失败? Geotools 对 CRS 转换可靠吗?
对于轴顺序的第一个问题,您遇到了一个常见的初学者问题,即假设您知道投影的轴顺序是什么,并且在 ESPG:4326 的情况下它是固定的。
例如下面的代码:
CoordinateReferenceSystem targetCrs = CRS.decode("EPSG:4326");
System.out.println("EPSG:4326 - " + CRS.getAxisOrder(targetCrs));
System.out.println("WGS84 - " + CRS.getAxisOrder(DefaultGeographicCRS.WGS84));
给出此输出:
EPSG:4326 - NORTH_EAST
WGS84 - EAST_NORTH
但是如果你添加行 Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
输出变成:
EPSG:4326 - EAST_NORTH
WGS84 - EAST_NORTH
因此,一般来说,您永远不应依赖代码中的“已知”轴顺序,而应使用类似以下内容:
double latitude = 29.0;
double longitude = -99.0;
CoordinateReferenceSystem sourceCrs = CRS.decode("EPSG:4312");
CoordinateReferenceSystem targetCrs = CRS.decode("EPSG:4326");
MathTransform engine = CRS.findMathTransform(sourceCrs, targetCrs, false);
DirectPosition2D source;
if (CRS.getAxisOrder(sourceCrs).equals(org.geotools.referencing.CRS.AxisOrder.EAST_NORTH)) {
source = new DirectPosition2D(sourceCrs, longitude, latitude);
} else {
source = new DirectPosition2D(sourceCrs, latitude, longitude);
}
DirectPosition target = new DirectPosition2D(targetCrs);
engine.transform(source, target);
if (CRS.getAxisOrder(targetCrs).equals(org.geotools.referencing.CRS.AxisOrder.EAST_NORTH)) {
System.out.println("lon,lat=" + target.getCoordinate()[0] + "," + target.getCoordinate()[1]);
} else {
System.out.println("lon,lat=" + target.getCoordinate()[1] + "," + target.getCoordinate()[0]);
}
至于转换的准确性,这取决于您导入的引用模块以及 Oracle 使用的 CRS 定义。加载 gt-epsg-hsql
模块后,我看到与 EPSG registry. If there is an NTv2 transformation available then adding that to your project 中提供的最准确变换相同的 ToWGS84[601.705, 84.263, 485.227, 4.7354, -1.3145, -5.393, -2.3887]
矩阵应该会提高精度。
我需要使用 GeoTools Java 库将点从 EPSG:4312 转换为 WGS84。 但是我不确定我是否正确使用它,我也不确定它是否提供了正确的结果。
参见以下代码示例:
@Test
public void testSingle4312ToWGS84() throws FactoryException, TransformException {
double latitude = 29.0;
double longitude = -99.0;
CoordinateReferenceSystem sourceCrs = CRS.decode("EPSG:4312");
CoordinateReferenceSystem targetCrs = CRS.decode("EPSG:4326");
MathTransform engine = CRS.findMathTransform(sourceCrs, targetCrs, false);
DirectPosition source = new DirectPosition2D(sourceCrs, longitude, latitude);
DirectPosition target = new DirectPosition2D(targetCrs);
engine.transform(source, target);
System.out.println("x,y=" + target.getCoordinate()[0] + "," + target.getCoordinate()[1]);
}
当 运行 以上代码时,我得到以下结果:
x,y=-81.00483829765083,-150.99434404015307
这是错误的,因为 -150 不是有效的纬度。
当我创建 source 对象时,我用经度初始化 X,用纬度初始化 Y,遵循实际上 X 是经度,Y 是纬度的基本原理(根据地理社区)。 但是,如果我反转它们:
DirectPosition source = new DirectPosition2D(sourceCrs, latitude, longitude);
我现在得到了一个看起来更真实的结果:
x,y=29.003866857343915,-98.99222530180596
当然我现在必须将 X 解释为纬度,将 Y 解释为经度。
那么,问题 #1,我们是否应该使用逆有理将 X 视为纬度,将 Y 视为经度?
接下来,我想验证一下结果。首先,尝试使用 Oracle SQL SDO 函数转换相同的点:
select sdo_cs.transform (
MDSYS.SDO_GEOMETRY(2001, 4312, MDSYS.SDO_POINT_TYPE(-99, 29, NULL), NULL, NULL),
8307
) from dual;
提供以下结果:
MDSYS.SDO_GEOMETRY(2001, 8307, MDSYS.SDO_POINT_TYPE(-98.9924748682774, 29.0036029261273, NULL), NULL, NULL)
转换后的点与GeoTools生成的点类似,但相差~40米。
接下来,我尝试了这个 website 提供的转换,它提供了与 Oracle 相同的结果。 我还使用了 Luciad AIXM Viewer,一个用于 GML 的图形表示工具,它也将我的点显示在由 Oracle 计算的相同位置。
所以,我有 3 个独立的工具提供相同的结果点,与 GeoTools 计算的结果点相距 40 米。 问题 #2,为什么 Geotools 会失败? Geotools 对 CRS 转换可靠吗?
对于轴顺序的第一个问题,您遇到了一个常见的初学者问题,即假设您知道投影的轴顺序是什么,并且在 ESPG:4326 的情况下它是固定的。
例如下面的代码:
CoordinateReferenceSystem targetCrs = CRS.decode("EPSG:4326");
System.out.println("EPSG:4326 - " + CRS.getAxisOrder(targetCrs));
System.out.println("WGS84 - " + CRS.getAxisOrder(DefaultGeographicCRS.WGS84));
给出此输出:
EPSG:4326 - NORTH_EAST
WGS84 - EAST_NORTH
但是如果你添加行 Hints.putSystemDefault(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
输出变成:
EPSG:4326 - EAST_NORTH
WGS84 - EAST_NORTH
因此,一般来说,您永远不应依赖代码中的“已知”轴顺序,而应使用类似以下内容:
double latitude = 29.0;
double longitude = -99.0;
CoordinateReferenceSystem sourceCrs = CRS.decode("EPSG:4312");
CoordinateReferenceSystem targetCrs = CRS.decode("EPSG:4326");
MathTransform engine = CRS.findMathTransform(sourceCrs, targetCrs, false);
DirectPosition2D source;
if (CRS.getAxisOrder(sourceCrs).equals(org.geotools.referencing.CRS.AxisOrder.EAST_NORTH)) {
source = new DirectPosition2D(sourceCrs, longitude, latitude);
} else {
source = new DirectPosition2D(sourceCrs, latitude, longitude);
}
DirectPosition target = new DirectPosition2D(targetCrs);
engine.transform(source, target);
if (CRS.getAxisOrder(targetCrs).equals(org.geotools.referencing.CRS.AxisOrder.EAST_NORTH)) {
System.out.println("lon,lat=" + target.getCoordinate()[0] + "," + target.getCoordinate()[1]);
} else {
System.out.println("lon,lat=" + target.getCoordinate()[1] + "," + target.getCoordinate()[0]);
}
至于转换的准确性,这取决于您导入的引用模块以及 Oracle 使用的 CRS 定义。加载 gt-epsg-hsql
模块后,我看到与 EPSG registry. If there is an NTv2 transformation available then adding that to your project 中提供的最准确变换相同的 ToWGS84[601.705, 84.263, 485.227, 4.7354, -1.3145, -5.393, -2.3887]
矩阵应该会提高精度。