之前一直在使用GDAL进行shp文件的坐标系转换,但是最近遇到一个问题,GDAL的windows环境部署比较麻烦。我调试好的代码,交给别人后会出现无法运行的状况。于是研究了一下基于GeoTools的shp文件坐标系转换。最后发现,还是这种方式,操作起来,相对比较简单,对电脑环境依赖不高。
依赖
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>readShp</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<geo.version>9.3</geo.version>
</properties>
<dependencies>
<!-- shp入库依赖-->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
<version>${geo.version}</version>
</dependency>
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-api</artifactId>
<version>${geo.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
<version>${geo.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-opengis</artifactId>
<version>${geo.version}</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>osgeo</id>
<name>OSGeo Release Repository</name>
<url>https://repo.osgeo.org/repository/release/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
<repository>
<id>osgeo-snapshot</id>
<name>OSGeo Snapshot Repository</name>
<url>https://repo.osgeo.org/repository/snapshot/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
</project>
Java代码
package com.test.shp;
import com.vividsolutions.jts.geom.Geometry;
import org.geotools.data.FeatureWriter;
import org.geotools.data.FileDataStoreFactorySpi;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import java.io.File;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public class ProjectTrans {
public static void projectShape(String inputShp, String outputShp, Integer targetSrid) throws Exception {
//源shape文件
ShapefileDataStore shapeDS = (ShapefileDataStore) new ShapefileDataStoreFactory().createDataStore(new File(inputShp).toURI().toURL());
//创建目标shape文件对象
Map<String, Serializable> params = new HashMap<String, Serializable>();
FileDataStoreFactorySpi factory = new ShapefileDataStoreFactory();
params.put(ShapefileDataStoreFactory.URLP.key, new File(outputShp).toURI().toURL());
ShapefileDataStore ds = (ShapefileDataStore) factory.createNewDataStore(params);
CoordinateReferenceSystem crs = CRS.decode("EPSG:" + targetSrid);
CoordinateReferenceSystem crsOld = shapeDS.getSchema().getCoordinateReferenceSystem();
System.out.println(crsOld.getName());
// 设置属性
SimpleFeatureSource fs = shapeDS.getFeatureSource(shapeDS.getTypeNames()[0]);
//下面这行还有其他写法,根据源shape文件的simpleFeatureType可以不用retype,而直接用fs.getSchema设置
System.out.println(crs.getName());
ds.createSchema(SimpleFeatureTypeBuilder.retype(fs.getSchema(), crs));
ds.forceSchemaCRS(crs);
//设置writer
FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT);
//写记录
SimpleFeatureIterator it = fs.getFeatures().features();
MathTransform transform = CRS.findMathTransform(crsOld, crs, true);
//遍历要素
try {
while (it.hasNext()) {
SimpleFeature f = it.next();
SimpleFeature fNew = writer.next();
fNew.setAttributes(f.getAttributes());
//图形坐标变换
Geometry geom = (Geometry) JTS.transform((Geometry) f.getAttribute("the_geom"), transform);
fNew.setAttribute("the_geom", geom);
}
} finally {
it.close();
}
writer.write();
writer.close();
ds.dispose();
shapeDS.dispose();
}
public static void main(String[] args) throws Exception {
projectShape("E:\\测试数据\\out.shp","E:\\测试数据\\result.shp",3857);
}
}
运行中问题
在转换shp的过程中,部分shp文件出现了一个问题。如下图:
- 转换前
- 转换后
从上面的图中,可以看出,发生了很大的变化,图形几乎是翻转了。这个问题困扰了我很久,最后终于找到了解决方案。这个是由于部分shp数据的xy的顺序反过来了导致的。在运行GeoTool是的代码初始位置加上下面的一句代码就可以解决:
System.setProperty("org.geotools.referencing.forceXY", "true");
在程序的初始位置加入上面代码后,转换结果正常。在ArcGIS验证,前后位置一致。