海外营销网站设计做网上推广
什么是叠加分析?
叠加分析通过对两个或多个地理图层执行几何运算,生成新的图层,用于分析空间关系。也可参考合集中叠加分析内容。常见的叠加操作包括:
- 交集(Intersection):提取两个图层重叠的部分。
- JTS 方法:geometry1.intersection(geometry2)
- 示例:找出河流穿越的农田区域。
- 并集(Union):合并两个图层的几何,保留所有区域。
- JTS 方法:geometry1.union(geometry2)
- 示例:合并农田和森林,生成综合土地使用图层。
- 差集(Difference):从一个图层中移除与另一个图层重叠的部分。
- JTS 方法:geometry1.difference(geometry2)
- 示例:从城市区域移除河流缓冲区。
- 对称差(Symmetric Difference):提取两个图层中互不重叠的部分。
- JTS 方法:geometry1.symDifference(geometry2)
- 示例:分析保护区与采矿区的非重叠区域。
叠加分析广泛应用于:
- 土地利用规划:分析不同土地类型的重叠区域。
- 洪水风险评估:确定洪水淹没区与居民区的交集。
- 环境管理:评估保护区与开发项目的空间冲突。
GeoTools 借助 JTS(Java Topology Suite) 提供高效的几何运算能力,结合其数据处理功能,成为实现叠加分析的理想工具。
开发环境准备
在开始代码实践之前,需要配置 GeoTools 环境:
添加 Maven 依赖
在 pom.xml 中添加以下依赖:
<repositories><repository><id>osgeo</id><name>OSGeo Repository</name><url>https://repo.osgeo.org/repository/release/</url></repository>
</repositories><dependencies><dependency><groupId>org.geotools</groupId><artifactId>gt-main</artifactId><version>27.0</version></dependency><dependency><groupId>org.geotools</groupId><artifactId>gt-shapefile</artifactId><version>27.0</version></dependency><dependency><groupId>org.geotools</groupId><artifactId>gt-epsg-hsql</artifactId><version>27.0</version></dependency>
</dependencies>
准备测试数据
使用 Shapefile 格式的地理数据,例如:
- land_use.shp:包含农田、森林、城市区域的多边形(Polygon),属性包括 land_type(字符串)。
- rivers.shp:包含河流的线状几何(LineString),属性包括 name(字符串)。
- 坐标参考系统(CRS):EPSG:4326(WGS84)。
你可以通过 Natural Earth 或其他公开数据集获取测试数据。
开发工具
- JDK:1.8 或以上
- IDE:IntelliJ IDEA
- Maven:3.69
GeoTools 叠加分析代码示例
以下是一个完整的 GeoTools 程序,展示如何实现交集、并集、差集、对称差和缓冲区分析。我们将:
- 计算农田与河流的交集。
- 合并农田和森林区域。
- 从城市区域移除河流缓冲区。
- 生成河流的 100 米缓冲区并与土地使用图层交集。
- 计算保护区与采矿区的对称差。
完整代码
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
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 com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Polygon;
import org.geotools.data.shapefile.ShapefileDataStore;import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;public class OverlayAnalysisDemo {public static void main(String[] args) throws Exception {// 加载 ShapefileFile landUseFile = new File("path/to/land_use.shp");File riversFile = new File("path/to/rivers.shp");FileDataStore landUseStore = FileDataStoreFinder.getDataStore(landUseFile);FileDataStore riversStore = FileDataStoreFinder.getDataStore(riversFile);SimpleFeatureSource landUseSource = landUseStore.getFeatureSource();SimpleFeatureSource riversSource store.getFeatureSource();SimpleFeatureCollection landUseFeatures = landUseSource.getFeatures();SimpleFeatureCollection riverFeatures = riversSource.getFeatures();// 确保 CRS 一致CoordinateReferenceSystem landUseCRS = landUseSource.getSchema().getCoordinateReferenceSystem();CoordinateReferenceSystem riverCRS = riversSource.getSchema().getCoordinateReferenceSystem();if (!CRS.equalsIgnoreMetadata(landUseCRS, riverCRS)) {throw new Exception("CRS mismatch between layers!");}// 交集分析:农田与河流SimpleFeatureCollection intersectionResult = performIntersection(landUseFeatures, riverFeatures);saveShapefile(intersectionResult, "intersection_output.shp");// 并集分析:农田与森林SimpleFeatureCollection unionResult = performUnion(landUseFeatures);saveShapefile(unionResult, "union_output.shp");// 差集分析:城市区域移除河流SimpleFeatureCollection differenceResult = performDifference(landUseFeatures, riverFeatures);saveShapefile(differenceResult, "difference_output.shp");// 对称差分析:保护区与采矿区SimpleFeatureCollection symDiffResult = performSymmetricDifference(landUseFeatures, riverFeatures);saveShapefile(symDiffResult, "sym_diff_output.shp");// 缓冲区分析:河流 100 米缓冲区与土地使用SimpleFeatureCollection bufferResult = performBufferAndIntersection(landUseFeatures, riverFeatures, 100.0);saveShapefile(bufferResult, "buffer_intersection_output.shp");// 清理资源landUseStore.dispose();riversStore.dispose();}// 交集分析private static SimpleFeatureCollection performIntersection(SimpleFeatureCollection landUseFeatures, SimpleFeatureCollection riverFeatures) throws Exception {DefaultFeatureCollection result = new DefaultFeatureCollection();SimpleFeatureType resultType = createFeatureType("IntersectionType", Polygon.class);try (SimpleFeatureIterator landUseIterator = landUseFeatures.features()) {while (landUseIterator.hasNext()) {SimpleFeature landUseFeature = landUseIterator.next();Geometry landUseGeom = (Geometry) landUseFeature.getDefaultGeometry();try (SimpleFeatureIterator riverIterator = riverFeatures.features()) {while (riverIterator.hasNext()) {SimpleFeature riverFeature = riverIterator.next();Geometry riverGeom = (Geometry) riverFeature.getDefaultGeometry();Geometry intersection = landUseGeom.intersection(riverGeom);if (!intersection.isEmpty() && intersection instanceof Polygon) {SimpleFeatureBuilder builder = new SimpleFeatureBuilder(resultType);builder.set("geometry", intersection);builder.set("land_type", landUseFeature.getAttribute("land_type"));result.add(builder.buildFeature(null));}}}}}return result;}// 并集分析private static SimpleFeatureCollection performUnion(SimpleFeatureCollection landUseFeatures) throws Exception {DefaultFeatureCollection result = new DefaultFeatureCollection();SimpleFeatureType resultType = createFeatureType("UnionType", Polygon.class);List<Geometry> geometries = new ArrayList<>();try (SimpleFeatureIterator iterator = landUseFeatures.features()) {while (iterator.hasNext()) {SimpleFeature feature = iterator.next();Geometry geom = (Geometry) feature.getDefaultGeometry();geometries.add(geom);}}Geometry union = geometries.get(0);for (int i = 1; i < geometries.size(); i++) {union = union.union(geometries.get(i));}if (union instanceof Polygon || union instanceof MultiPolygon) {SimpleFeatureBuilder builder = new SimpleFeatureBuilder(resultType);builder.set("geometry", union);builder.set("land_type", "Combined");result.add(builder.buildFeature(null));}return result;}// 差集分析private static SimpleFeatureCollection performDifference(SimpleFeatureCollection landUseFeatures, SimpleFeatureCollection riverFeatures) throws Exception {DefaultFeatureCollection result = new DefaultFeatureCollection();SimpleFeatureType resultType = createFeatureType("DifferenceType", Polygon.class);try (SimpleFeatureIterator landUseIterator = landUseFeatures.features()) {while (landUseIterator.hasNext()) {SimpleFeature landUseFeature = landUseIterator.next();Geometry landUseGeom = (Geometry) landUseFeature.getDefaultGeometry();try (SimpleFeatureIterator riverIterator = riverFeatures.features()) {Geometry combinedRivers = null;while (riverIterator.hasNext()) {SimpleFeature riverFeature = riverIterator.next();Geometry riverGeom = (Geometry) riverFeature.getDefaultGeometry();combinedRivers = combinedRivers == null ? riverGeom : combinedRivers.union(riverGeom);}if (combinedRivers != null) {Geometry difference = landUseGeom.difference(combinedRivers);if (!difference.isEmpty() && difference instanceof Polygon) {SimpleFeatureBuilder builder = new SimpleFeatureBuilder(resultType);builder.set("geometry", difference);builder.set("land_type", landUseFeature.getAttribute("land_type"));result.add(builder.buildFeature(null));}}}}}return result;}// 对称差分析private static SimpleFeatureCollection performSymmetricDifference(SimpleFeatureCollection landUseFeatures, SimpleFeatureCollection riverFeatures) throws Exception {DefaultFeatureCollection result = new DefaultFeatureCollection();SimpleFeatureType resultType = createFeatureType("SymDiffType", Polygon.class);try (SimpleFeatureIterator landUseIterator = landUseFeatures.features()) {while (landUseIterator.hasNext()) {SimpleFeature landUseFeature = landUseIterator.next();Geometry landUseGeom = (Geometry) landUseFeature.getDefaultGeometry();try (SimpleFeatureIterator riverIterator = riverFeatures.features()) {while (riverIterator.hasNext()) {SimpleFeature riverFeature = riverIterator.next();Geometry riverGeom = (Geometry) riverFeature.getDefaultGeometry();Geometry symDiff = landUseGeom.symDifference(riverGeom);if (!symDiff.isEmpty()) {SimpleFeatureBuilder builder = new SimpleFeatureBuilder(resultType);builder.set("geometry", symDiff);builder.set("type", "NonOverlapping");result.add(builder.buildFeature(null));}}}}}return result;}// 缓冲区分析与交集private static SimpleFeatureCollection performBufferAndIntersection(SimpleFeatureCollection landUseFeatures, SimpleFeatureCollection riverFeatures, double bufferDistance) throws Exception {DefaultFeatureCollection result = new DefaultFeatureCollection();SimpleFeatureType resultType = createFeatureType("BufferIntersectionType", Polygon.class);List<Geometry> bufferGeoms = new ArrayList<>();try (SimpleFeatureIterator riverIterator = riverFeatures.features()) {while (riverIterator.hasNext()) {SimpleFeature riverFeature = riverIterator.next();Geometry riverGeom = (Geometry) riverFeature.getDefaultGeometry();Geometry buffer = riverGeom.buffer(bufferDistance);bufferGeoms.add(buffer);}}try (SimpleFeatureIterator landUseIterator = landUseFeatures.features()) {while (landUseIterator.hasNext()) {SimpleFeature landUseFeature = landUseIterator.next();Geometry landUseGeom = (Geometry) landUseFeature.getDefaultGeometry();for (Geometry bufferGeom : bufferGeoms) {Geometry intersection = landUseGeom.intersection(bufferGeom);if (!intersection.isEmpty() && intersection instanceof Polygon) {SimpleFeatureBuilder builder = new SimpleFeatureBuilder(resultType);builder.set("geometry", intersection);builder.set("land_type", landUseFeature.getAttribute("land_type"));result.add(builder.buildFeature(null));}}}}return result;}// 创建 FeatureTypeprivate static SimpleFeatureType createFeatureType(String typeName, Class<? extends Geometry> geomType) throws Exception {SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();builder.setName(typeName);builder.setCRS(CRS.decode("EPSG:4326"));builder.add("geometry", geomType);builder.add("land_type", String.class);return builder.buildFeatureType();}// 保存到 Shapefileprivate static void saveShapefile(SimpleFeatureCollection featureCollection, String outputPath) throws Exception {File outputFile = new File(outputPath);ShapefileDataStore dataStore = new ShapefileDataStore(outputFile.toURI().toURL());dataStore.setCharset(StandardCharsets.UTF_8);dataStore.createSchema(featureCollection.getSchema());try (SimpleFeatureIterator iterator = featureCollection.features()) {while (iterator.hasNext()) {SimpleFeature feature = iterator.next();dataStore.getFeatureWriterAppend().write(feature);}}dataStore.dispose();}
}
代码说明
- 数据加载:使用 FileDataStoreFinder 读取 Shapefile,获取 SimpleFeatureCollection。
- CRS 检查:确保两个图层的 CRS 一致(如 EPSG:4326)。
- 几何运算:
- 交集:使用 geometry1.intersection(geometry2) 提取农田与河流重叠区域。
- 并集:通过 geometry1.union(geometry2) 合并农田和森林。
- 差集:使用 geometry1.difference(geometry2) 从城市区域移除河流。
- 对称差:通过 geometry1.symDifference(geometry2) 提取非重叠区域。
- 缓冲区:使用 geometry.buffer(distance) 生成河流缓冲区,再与土地使用图层交集。
- 结果保存:将结果保存为新的 Shapefile 文件,可用 QGIS 或 ArcGIS 查看。
运行结果
运行后生成以下文件:
- intersection_output.shp:农田与河流的交集。
- union_output.shp:农田与森林的合并区域。
- difference_output.shp:城市区域移除河流后的结果。
- sym_diff_output.shp:保护区与河流的非重叠区域。
- buffer_intersection_output.shp:河流 100 米缓冲区与土地使用的交集。
应用场景
叠加分析在实际项目中有广泛应用,以下是两个典型场景的代码实现。
土地利用规划:绿地与道路交集
目标:找出城市绿地被道路穿越的区域,用于规划修复。
private static SimpleFeatureCollection findGreenRoadsIntersection(SimpleFeatureCollection greenAreas, SimpleFeatureCollection roads) throws Exception {DefaultFeatureCollection result = new DefaultFeatureCollection();SimpleFeatureType resultType = createFeatureType("GreenRoadsIntersection", Polygon.class);try (SimpleFeatureIterator greenIterator = greenAreas.features()) {while (greenIterator.hasNext()) {SimpleFeature greenFeature = greenIterator.next();Geometry greenGeom = (Geometry) greenFeature.getDefaultGeometry();try (SimpleFeatureIterator roadIterator = roads.features()) {while (roadIterator.hasNext()) {SimpleFeature roadFeature = roadIterator.next();Geometry roadGeom = (Geometry) roadFeature.getDefaultGeometry();Geometry intersection = greenGeom.intersection(roadGeom);if (!intersection.isEmpty() && intersection instanceof Polygon) {SimpleFeatureBuilder builder = new SimpleFeatureBuilder(resultType);builder.set("geometry", intersection);builder.set("area_name", greenFeature.getAttribute("name"));result.add(builder.buildFeature(null));}}}}}return result;
}
应用:帮助城市规划者识别需要修复的绿地碎片。
洪水风险评估:洪水淹没区与居民区
目标:分析洪水风险区 200 米缓冲区内的居民区,评估受影响的房屋
private static SimpleFeatureCollection floodRiskAnalysis(SimpleFeatureCollection floodZones, SimpleFeatureCollection residentialAreas, double bufferDistance) throws Exception {DefaultFeatureCollection result = new DefaultFeatureCollection();SimpleFeatureType resultType = createFeatureType("FloodRiskType", Polygon.class);List<Geometry> floodBuffers = new ArrayList<>();try (SimpleFeatureIterator floodIterator = floodZones.features()) {while (floodIterator.hasNext()) {SimpleFeature floodFeature = floodIterator.next();Geometry floodGeom = (Geometry) floodFeature.getDefaultGeometry();Geometry buffer = floodGeom.buffer(bufferDistance);floodBuffers.add(buffer);}}try (SimpleFeatureIterator residentialIterator = residentialAreas.features()) {while (residentialIterator.hasNext()) {SimpleFeature residentialFeature = residentialIterator.next();Geometry residentialGeom = (Geometry) residentialFeature.getDefaultGeometry();for (Geometry floodBuffer : floodBuffers) {Geometry intersection = residentialGeom.intersection(floodBuffer);if (!intersection.isEmpty() && intersection instanceof Polygon) {SimpleFeatureBuilder builder = new SimpleFeatureBuilder(resultType);builder.set("geometry", intersection);builder.set("res_type", residentialFeature.getAttribute("type"));result.add(builder.buildFeature(null));}}}}return result;
}
应用:为防洪规划提供数据支持,识别需要搬迁的居民区。
常见问题与优化
-
性能优化:
-
问题:大数据量图层运算缓慢。
-
解决:使用 GeoTools 的 Quadtree 或 STRtree 空间索引,减少几何比较次数。
-
示例:在处理前构建索引:
STRtree index = new STRtree(); try (SimpleFeatureIterator iterator = features.features()) {while (iterator.hasNext()) {SimpleFeature feature = iterator.next();index.insert(((Geometry) feature.getDefaultGeometry()).getEnvelopeInternal(), feature);} }
-
-
几何有效性:
- 问题:无效几何(如自相交)导致运算失败。
- 解决:使用 Geometry.isValid() 检查,调用 Geometry.buffer(0) 修复。
-
CRS 不一致:
- 解决:使用 CRS.transform 将图层投影到统一 CRS。
-
空几何处理:
- 解决:检查 Geometry.isEmpty(),跳过无效结果。
GeoTools 结合 JTS 提供了强大的叠加分析功能,支持交集、并集、差集、对称差和缓冲区操作,适用于土地利用规划、洪水风险评估、环境管理等场景。本文通过详细的代码示例和实际应用场景,展示了如何使用 GeoTools 实现这些操作。