在我们当前的项目中,我们使用 Maven 设置来管理依赖项并运行单元测试。在开发的某个时刻,我们的一项测试停止工作(我们不确定究竟是在什么时候,所以我们不知道到底发生了什么变化)。失败的具体事情是使用 geotools(9 和 9.1 尝试过)从笛卡尔坐标到地理坐标的转换。有趣的是,同样的测试在 eclipse 中也能正常工作。我们在分析问题上投入了大量精力,并创建了一个最小示例来显示我们看到的行为,我们(合理地)确定它不是类路径问题。
这个例子
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.geotest</groupId>
<artifactId>geotest</artifactId>
<name>geotest</name>
<version>1.0.0</version>
<description></description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<geotools.version>9.1</geotools.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>${geotools.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.example.geotest.Geotest</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net repository</name>
<url>http://download.java.net/maven/2</url>
</repository>
<repository>
<id>osgeo</id>
<name>Open Source Geospatial Foundation Repository</name>
<url>http://download.osgeo.org/webdav/geotools/</url>
</repository>
</repositories>
</project>
测试者.java
package com.example.geotest;
import java.awt.geom.Point2D;
import java.util.Collections;
import java.util.Map;
import org.geotools.referencing.CRS;
import org.geotools.referencing.ReferencingFactoryFinder;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.referencing.cs.DefaultCartesianCS;
import org.geotools.referencing.factory.ReferencingFactoryContainer;
import org.geotools.referencing.operation.DefaultConversion;
import org.geotools.referencing.operation.DefiningConversion;
import org.junit.Test;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.crs.CRSFactory;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.referencing.operation.TransformException;
public class Tester {
@Test
public void testtesttest() throws Exception {
// prepare actuall action
final MathTransformFactory mtFactory = ReferencingFactoryFinder.getMathTransformFactory(null);
final ReferencingFactoryContainer factories = new ReferencingFactoryContainer(null);
final GeographicCRS geoCRS = DefaultGeographicCRS.WGS84;
final CartesianCS cartCS = DefaultCartesianCS.GENERIC_2D;
ProjectedCRS projCRS;
MathTransform transformGeoToCrs;
MathTransform transformCrsToGeo;
ParameterValueGroup parameters = mtFactory.getDefaultParameters("Transverse_Mercator");
parameters.parameter("central_meridian").setValue(9);
parameters.parameter("latitude_of_origin").setValue(0.0);
//0.9996 (a reduction of 1:2500); (40 cm/km)
parameters.parameter("scale_factor").setValue(0.9996);
//500 km for north hemisphere
parameters.parameter("false_easting").setValue(500000.0);
//10,0000 km for south hemisphere
parameters.parameter("false_northing").setValue(0.0);
Map<String, String> properties = Collections.singletonMap("name", "WGS 84 / UTM Zone 32");
CRSFactory crsFactory = factories.getCRSFactory();
DefiningConversion conv = new DefiningConversion("test", parameters);
projCRS = crsFactory.createProjectedCRS(properties, geoCRS, conv, cartCS);
transformGeoToCrs = CRS.findMathTransform(geoCRS, projCRS);
transformCrsToGeo = CRS.findMathTransform(projCRS, geoCRS);
// execute actual test
double[] src = new double[] {5838597.0, 807147.75};
double[] dest = new double[2];
try {
// this fails in maven
transformCrsToGeo.transform(src, 0, dest, 0, 1);
} catch (TransformException e) {
throw new RuntimeException(e);
}
Point2D.Double geo = new Point2D.Double(dest[0], dest[1]);
}
}
如果我们对此调用“mvn 测试”,我们会得到以下异常:
Tests in error:
testtesttest(com.example.geotest.Tester): org.geotools.referencing.operation.projection.ProjectionException: The transform result may be 9.478,277 meters away from the expected position. Are you sure that the input coordinates are inside this map projection area of validity? The point is located 43°20.6'E away from the central meridian and 5°19.1'N away from the latitude of origin. The projection is "Transverse_Mercator".
如果我们从 Eclipse 运行 JUnit 测试,这将完美运行。任何想法为什么会发生这种情况或我们如何避免它?
作为旁注:以下三行是已弃用的 factory.createProjectedCRS(properties, geoCRS, null, parameters, cartCS) 方法的解决方法,如果有人有更好的解决方案,请作为我的客人:)
CRSFactory crsFactory = factories.getCRSFactory();
DefiningConversion conv = new DefiningConversion("test", parameters);
projCRS = crsFactory.createProjectedCRS(properties, geoCRS, conv, cartCS);