最近有一個(gè)需求,需要去做大量空間數(shù)據(jù)的相交檢驗(yàn)督函,如果每一個(gè)圖形都去讀取出來(lái)與剩下的圖形去對(duì)比嘀粱,太耗費(fèi)時(shí)間和性能,一起做了很多不必要的相交辰狡。
為了稍微提升一些速度锋叨,借鑒了在空間數(shù)據(jù)處理分任務(wù)時(shí)的,片區(qū)劃分的方法宛篇,將與一個(gè)片區(qū)的取出來(lái)單獨(dú)處理娃磺,這樣會(huì)減少單次數(shù)據(jù)處理的量。 而且避免了很多相隔較遠(yuǎn)的數(shù)據(jù)的也需要去做相交比對(duì)的這種必要的操作叫倍。
下面就將我的做法分享出來(lái)
1.先貼pom.xml 文件
<?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>gis_data_fragment</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>7</source>
<target>7</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>28.2</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-opengis</artifactId>
<version>28.2</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-metadata</artifactId>
<version>28.2</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
<version>28.2</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-referencing</artifactId>
<version>28.2</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
<version>28.2</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-swing</artifactId>
<version>28.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.19.0</version>
</dependency>
<dependency>
<groupId>si.uom</groupId>
<artifactId>si-quantity</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>si.uom</groupId>
<artifactId>si-units</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>si.uom</groupId>
<artifactId>si-units-java8</artifactId>
<version>0.7.1</version>
</dependency>
<dependency>
<groupId>tech.units</groupId>
<artifactId>indriya</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>javax.measure</groupId>
<artifactId>unit-api</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>tech.uom.lib</groupId>
<artifactId>uom-lib-common</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>systems.uom</groupId>
<artifactId>systems-common</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>osgeo</id>
<name>Open Source Geospatial Foundation Repository</name>
<url>https://repo.osgeo.org/repository/release/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
</project>
2. shp 文件讀取的方法 偷卧,同時(shí)獲取到數(shù)據(jù)的范圍,方便后面計(jì)算分片
引入的jar包
import org.geotools.data.DefaultTransaction;
import org.geotools.data.FeatureStore;
import org.geotools.data.Transaction;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.store.ContentFeatureCollection;
import org.geotools.data.store.ContentFeatureSource;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.util.factory.FactoryFinder;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.operation.union.UnaryUnionOp;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.text.DecimalFormat;
import java.util.*;
// 地址就是這種 ./src/main/data/shp/pewg.shp段标,當(dāng)然也可以直接選一個(gè)硬盤(pán)上的地址
//傳入shp文件的地址涯冠,讀取數(shù)據(jù),獲取數(shù)據(jù)范圍
private void readSHP(String url) {
//創(chuàng)建一個(gè)file對(duì)象
File file = new File(url);
ReferencedEnvelope bounds = new ReferencedEnvelope();
try {
ShapefileDataStore dataStore = new ShapefileDataStore(file.toURI().toURL());
ContentFeatureSource featureSource = dataStore.getFeatureSource();
ContentFeatureCollection features = featureSource.getFeatures();
SimpleFeatureIterator featureIterator = features.features();
//創(chuàng)建一個(gè)shp文件中的所有MultiPolygon的集合
ArrayList<MultiPolygon> multiPolygons = new ArrayList<>();
while (featureIterator.hasNext()) {
SimpleFeature feature = featureIterator.next();
multiPolygons.add((MultiPolygon) feature.getDefaultGeometry());
}
//1.獲取數(shù)據(jù)范圍
bounds = featureSource.getBounds();
//2.根據(jù)數(shù)據(jù)范圍逼庞,進(jìn)行數(shù)據(jù)分片,得到分片的分為
Polygon[] polygons = partition(bounds, 15, 15);//對(duì)shp范圍進(jìn)行分區(qū)
//3.將分片與數(shù)據(jù)相交瞻赶,得到每一小片相交的數(shù)據(jù)
dataIntersectionDetection(polygons, multiPolygons);
// polygonsAddToSHP(polygons); // 將切片圖形寫(xiě)入shp文件
dataStore.dispose();
} catch (Exception e) {
e.printStackTrace();
}
}
3.根據(jù)數(shù)據(jù)范圍赛糟,計(jì)算分片的數(shù)量
/*
*根據(jù)范圍數(shù)據(jù),計(jì)算分片
* bounds: 范圍
* divisionsX:橫向分割數(shù)
* divisionsY: 縱向分割數(shù)
* */
private Polygon[] partition(ReferencedEnvelope bounds, int divisionsX, int divisionsY) throws IOException {
//最大最小的經(jīng)緯度點(diǎn)
Coordinate bottomLeft = new Coordinate(
keep9DecimalPlaces(bounds.getMinX()),
keep9DecimalPlaces(bounds.getMinY())); // 左下角
Coordinate topRight = new Coordinate(
keep9DecimalPlaces(bounds.getMaxX()),
keep9DecimalPlaces(bounds.getMaxY())); // 右上角
double minX = bottomLeft.x;
double minY = bottomLeft.y;
double maxX = topRight.x;
double maxY = topRight.y;
//大矩形范圍
Coordinate[] rectangleRadius = {
bottomLeft,
new Coordinate(bottomLeft.x, topRight.y),
topRight,
new Coordinate(topRight.x, bottomLeft.y),
bottomLeft
};
// 將大矩形橫向和縱向劃分為10等分和5等分
int numDivisionsX = divisionsX;
int numDivisionsY = divisionsY;
// 存放劃分好的小矩形的數(shù)組
double[][][] dividedRectangles = new double[numDivisionsX][numDivisionsY][4];
// 計(jì)算橫向和縱向的步長(zhǎng)
double xStep = (maxX - minX) / numDivisionsX;
double yStep = (maxY - minY) / numDivisionsY;
// 劃分大矩形并將每個(gè)小矩形的四個(gè)頂點(diǎn)坐標(biāo)存放到數(shù)組中
for (int i = 0; i < numDivisionsX; i++) {
for (int j = 0; j < numDivisionsY; j++) {
double x1 = (minX + i * xStep);
double y1 = (minY + j * yStep);
double x2 = (minX + (i + 1) * xStep);
double y2 = (minY + (j + 1) * yStep);
//dividedRectangles[i][j] = new double[]{x1, y1, x2, y2};
dividedRectangles[i][j] = new double[]{
keep9DecimalPlaces(x1),
keep9DecimalPlaces(y1),
keep9DecimalPlaces(x2),
keep9DecimalPlaces(y2)
};
}
}
//將劃分的小矩形添加到MultiPolygon中
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
Polygon[] polygons = new Polygon[numDivisionsX * numDivisionsY];
int index = 0;
for (double[][] row : dividedRectangles) {
for (double[] rectangle : row) {
Coordinate[] coordinate = {
new Coordinate(rectangle[0], rectangle[1]),
new Coordinate(rectangle[2], rectangle[1]),
new Coordinate(rectangle[2], rectangle[3]),
new Coordinate(rectangle[0], rectangle[3]),
new Coordinate(rectangle[0], rectangle[1]),
};
Polygon polygon = geometryFactory.createPolygon(coordinate);
polygons[index] = polygon;
++index;
}
}
return polygons;
}
4.將分片數(shù)據(jù)與原始數(shù)據(jù)進(jìn)行相交砸逊,將每一片相交的元素?cái)?shù)據(jù)存到一個(gè)集合中
/*
* 將分片數(shù)據(jù)和原始數(shù)據(jù)傳入方法
* */
private void dataIntersectionDetection(Polygon[] polygons, ArrayList<MultiPolygon> multiPolygons) throws IOException {
// 將相交的數(shù)據(jù)存到一個(gè)大集合中
ArrayList<ArrayList<MultiPolygon>> bigList = new ArrayList<>();
for (int j = 0; j < polygons.length; j++) {
//將每個(gè)相交的數(shù)據(jù)存到一個(gè)小集合
ArrayList<MultiPolygon> smallList = new ArrayList<>();
for (int m = 0; m < multiPolygons.size(); m++) {
Polygon polygon = polygons[j];
MultiPolygon multiPolygon = multiPolygons.get(m);
boolean intersects = polygon.intersects(multiPolygon);// 是否相交
if (intersects) {// 將相交的數(shù)據(jù)璧南,保存到一個(gè)集合中
smallList.add(multiPolygon);
}
}
bigList.add(smallList);
}
/*// 將分片相交好的數(shù)據(jù)寫(xiě)入shp文件
for (int i = 0; i < bigList.size(); i++) {
if (bigList.get(i).isEmpty()) {// 為空的數(shù)據(jù)不寫(xiě)入
continue;
}
multiPolygonsAddToSHP(bigList.get(i), i);
}*/
}
最后在分享幾個(gè) 將 圖形數(shù)據(jù) 寫(xiě)入shp文件的方法,方便進(jìn)行數(shù)據(jù)驗(yàn)證和查看
//將多個(gè)Polygon添加到shp
private void polygonsAddToSHP(Polygon[] polygons) throws IOException {
// 創(chuàng)建Shapefile的DataStore
File newFile = new File("src/main/data/shp/partition.shp");
Map<String, Serializable> params = new HashMap<>();
params.put("url", newFile.toURI().toURL());
params.put("create spatial index", Boolean.TRUE);
ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
// 定義FeatureType
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
typeBuilder.setName("Polygon");
typeBuilder.setSRS("EPSG:4490");//設(shè)置坐標(biāo)系
typeBuilder.add("the_geom", Polygon.class); // 將數(shù)據(jù)寫(xiě)入shp文件中 一定要是 the_geom
typeBuilder.add("num", Integer.class);//添加一個(gè)num 用于取數(shù)據(jù)
SimpleFeatureType featureType = typeBuilder.buildFeatureType();
// 將FeatureType寫(xiě)入DataStore
dataStore.createSchema(featureType);
// 開(kāi)啟事務(wù)
Transaction transaction = new DefaultTransaction("create");
// 獲取FeatureStore
String typeName = dataStore.getTypeNames()[0];
FeatureStore<SimpleFeatureType, SimpleFeature> featureStore = (FeatureStore<SimpleFeatureType, SimpleFeature>) dataStore.getFeatureSource(typeName);
// 創(chuàng)建FeatureList
List<SimpleFeature> featureList = new LinkedList<>();
for (int i = 0; i < polygons.length; i++) {
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
featureBuilder.add(polygons[i]);
featureBuilder.add(i);
SimpleFeature feature = featureBuilder.buildFeature(null);
featureList.add(feature);
}
try {
// 添加FeatureList到Shapefile
ListFeatureCollection featureCollection = new ListFeatureCollection(featureType, featureList);
featureStore.setTransaction(transaction);
featureStore.addFeatures(featureCollection);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
transaction.close();
dataStore.dispose();
}
}
//將一個(gè)MultiPolygon添加到shp
private void multiPolygonAddToSHP(MultiPolygon multiPolygon) throws IOException {
// 創(chuàng)建Shapefile的DataStore
File newFile = new File("src/main/data/shp/multiPolygon1.shp");
Map<String, Serializable> params = new HashMap<>();
params.put("url", newFile.toURI().toURL());
params.put("create spatial index", Boolean.TRUE);
ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
// 定義FeatureType
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
typeBuilder.setName("MultiPolygon");
typeBuilder.setSRS("EPSG:4490");//設(shè)置坐標(biāo)系
typeBuilder.add("the_geom", MultiPolygon.class); // 將數(shù)據(jù)寫(xiě)入shp文件中 一定要是 the_geom
//typeBuilder.add("num", Integer.class);//添加一個(gè)num 用于取數(shù)據(jù)
SimpleFeatureType featureType = typeBuilder.buildFeatureType();
// 將FeatureType寫(xiě)入DataStore
dataStore.createSchema(featureType);
// 開(kāi)啟事務(wù)
Transaction transaction = new DefaultTransaction("create");
// 獲取FeatureStore
String typeName = dataStore.getTypeNames()[0];
FeatureStore<SimpleFeatureType, SimpleFeature> featureStore = (FeatureStore<SimpleFeatureType, SimpleFeature>) dataStore.getFeatureSource(typeName);
// 創(chuàng)建Feature
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
featureBuilder.add(multiPolygon);
SimpleFeature feature = featureBuilder.buildFeature(null);
try {
// 添加FeatureList到Shapefile
ListFeatureCollection featureCollection = new ListFeatureCollection(featureType, feature);
featureStore.setTransaction(transaction);
featureStore.addFeatures(featureCollection);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
transaction.close();
dataStore.dispose();
}
}
// 將多個(gè)MultiPolygon添加到shp,生成多個(gè)shp
private void multiPolygonsAddToSHP(ArrayList<MultiPolygon> multiPolygons, Integer num) throws IOException {
// 創(chuàng)建Shapefile的DataStore
File newFile = new File("src/main/data/shp/number/multiPolygons" + num + ".shp");
Map<String, Serializable> params = new HashMap<>();
params.put("url", newFile.toURI().toURL());
params.put("create spatial index", Boolean.TRUE);
ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
ShapefileDataStore dataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
// 定義FeatureType
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
typeBuilder.setName("Polygon");
typeBuilder.setSRS("EPSG:4490");//設(shè)置坐標(biāo)系
typeBuilder.add("the_geom", MultiPolygon.class); // 將數(shù)據(jù)寫(xiě)入shp文件中 一定要是 the_geom
SimpleFeatureType featureType = typeBuilder.buildFeatureType();
// 將FeatureType寫(xiě)入DataStore
dataStore.createSchema(featureType);
// 開(kāi)啟事務(wù)
Transaction transaction = new DefaultTransaction("create");
// 獲取FeatureStore
String typeName = dataStore.getTypeNames()[0];
FeatureStore<SimpleFeatureType, SimpleFeature> featureStore = (FeatureStore<SimpleFeatureType, SimpleFeature>) dataStore.getFeatureSource(typeName);
// 創(chuàng)建FeatureList
List<SimpleFeature> featureList = new LinkedList<>();
for (int i = 0; i < multiPolygons.size(); i++) {
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
featureBuilder.add(multiPolygons.get(i));
SimpleFeature feature = featureBuilder.buildFeature(null);
featureList.add(feature);
}
try {
// 添加FeatureList到Shapefile
ListFeatureCollection featureCollection = new ListFeatureCollection(featureType, featureList);
featureStore.setTransaction(transaction);
featureStore.addFeatures(featureCollection);
transaction.commit();
} catch (Exception e) {
e.printStackTrace();
transaction.rollback();
} finally {
transaction.close();
dataStore.dispose();
}
}
//將多個(gè)MultiPolygon合并為一個(gè)
private MultiPolygon mergeMultiPolygons(List<MultiPolygon> multiPolygons) {
// 合并的時(shí)間根據(jù)數(shù)據(jù)復(fù)雜程度师逸,時(shí)間可能會(huì)長(zhǎng)達(dá)幾分鐘司倚。
UnaryUnionOp unaryUnionOp = new UnaryUnionOp(multiPolygons);
return (MultiPolygon) unaryUnionOp.union();
}
// 保留9位小數(shù),經(jīng)緯度保留9未小數(shù),精度約為0.0001米=0.1毫米
private double keep9DecimalPlaces(double d) {
DecimalFormat df = new DecimalFormat("#.#########");
return Double.parseDouble(df.format(d));
}