第04章 - 空间操作详解
第04章 - 空间操作详解
4.1 算子模式详解
4.1.1 Operator 基类
所有空间操作都继承自 Operator 抽象类:
public abstract class Operator {
// 算子类型枚举
public enum Type {
Project,
ExportToJson, ImportFromJson,
ExportToESRIShape, ImportFromESRIShape,
Union, Difference,
Proximity2D, Centroid2D,
Relate, Equals, Disjoint, Intersects, Within, Contains, Crosses, Touches, Overlaps,
Buffer, Distance, Intersection, Clip, Cut, DensifyByLength, DensifyByAngle, LabelPoint,
GeodesicBuffer, GeodeticDensifyByLength, ShapePreservingDensify, GeodeticLength, GeodeticArea,
Simplify, SimplifyOGC, Offset, Generalize,
ExportToWkb, ImportFromWkb, ExportToWkt, ImportFromWkt,
ImportFromGeoJson, ExportToGeoJson,
SymmetricDifference, ConvexHull, Boundary
}
// 获取算子类型
public abstract Type getType();
// 加速几何(用于重复操作的优化)
public boolean accelerateGeometry(Geometry geometry,
SpatialReference sr, GeometryAccelerationDegree degree);
// 判断是否可加速
public boolean canAccelerateGeometry(Geometry geometry);
// 移除加速
public static void deaccelerateGeometry(Geometry geometry);
}
4.1.2 获取算子实例
// 方式一:通过工厂获取
OperatorBuffer buffer = (OperatorBuffer) OperatorFactoryLocal
.getInstance()
.getOperator(Operator.Type.Buffer);
// 方式二:使用静态方法(推荐)
OperatorBuffer buffer = OperatorBuffer.local();
OperatorUnion union = OperatorUnion.local();
OperatorIntersection intersection = OperatorIntersection.local();
4.1.3 GeometryCursor 流式处理
// 创建几何游标
Geometry[] geometries = {polygon1, polygon2, polygon3};
SimpleGeometryCursor inputCursor = new SimpleGeometryCursor(geometries);
// 执行批量操作
GeometryCursor resultCursor = OperatorBuffer.local().execute(
inputCursor,
spatialReference,
new double[]{10.0}, // 缓冲距离
true, // 是否合并结果
null // 进度追踪器
);
// 读取结果
Geometry result;
while ((result = resultCursor.next()) != null) {
// 处理每个结果
}
4.2 缓冲区操作 (Buffer)
4.2.1 基本缓冲区
// 创建点的缓冲区
Point point = new Point(116.4, 39.9);
SpatialReference sr = SpatialReference.create(4326);
// 使用 GeometryEngine
Polygon buffer = GeometryEngine.buffer(point, sr, 0.1);
// 使用 Operator
OperatorBuffer op = OperatorBuffer.local();
Polygon buffer2 = (Polygon) op.execute(point, sr, 0.1, null);
4.2.2 自定义缓冲区参数
// 控制缓冲区精度
OperatorBuffer op = OperatorBuffer.local();
// 参数说明:
// max_deviation: 最大偏差(与真实缓冲区的最大误差)
// max_vertices_in_full_circle: 完整圆的最大顶点数
double[] distances = {10.0};
double maxDeviation = 0.1;
int maxVertices = 96; // 默认值
GeometryCursor result = op.execute(
new SimpleGeometryCursor(geometry),
sr,
distances,
maxDeviation,
maxVertices,
true, // 是否合并
null // 进度追踪器
);
4.2.3 负缓冲区
// 负缓冲区用于多边形内缩
Polygon polygon = createPolygon();
SpatialReference sr = SpatialReference.create(4326);
// 负数表示内缩
Polygon shrunk = GeometryEngine.buffer(polygon, sr, -0.01);
// 注意:如果内缩过多,可能返回空几何
if (shrunk.isEmpty()) {
System.out.println("几何完全被内缩了");
}
4.2.4 批量缓冲区
// 对多个几何同时计算缓冲区
Geometry[] geometries = {point1, point2, line1, polygon1};
double[] distances = {10, 20, 15, 5}; // 各自的缓冲距离
Polygon[] buffers = GeometryEngine.buffer(geometries, sr, distances, false);
// false = 不合并结果,返回各自的缓冲区
// 合并所有缓冲区
Polygon[] unionedBuffer = GeometryEngine.buffer(geometries, sr, distances, true);
// true = 合并结果,返回单个多边形
4.3 合并操作 (Union)
4.3.1 基本合并
// 合并两个几何
Polygon p1 = createPolygon1();
Polygon p2 = createPolygon2();
SpatialReference sr = SpatialReference.create(4326);
// 使用数组合并
Geometry[] geometries = {p1, p2};
Geometry result = GeometryEngine.union(geometries, sr);
4.3.2 使用 Operator 合并
OperatorUnion op = OperatorUnion.local();
// 合并多个几何
Geometry[] geometries = {polygon1, polygon2, polygon3};
SimpleGeometryCursor cursor = new SimpleGeometryCursor(geometries);
GeometryCursor resultCursor = op.execute(cursor, sr, null);
Geometry unionResult = resultCursor.next();
4.3.3 增量合并
对于大量几何的合并,建议使用增量方式:
public Geometry unionMany(List<Geometry> geometries, SpatialReference sr) {
if (geometries.isEmpty()) {
return new Polygon();
}
OperatorUnion op = OperatorUnion.local();
// 每次合并一批
int batchSize = 100;
List<Geometry> current = new ArrayList<>(geometries);
while (current.size() > 1) {
List<Geometry> next = new ArrayList<>();
for (int i = 0; i < current.size(); i += batchSize) {
int end = Math.min(i + batchSize, current.size());
Geometry[] batch = current.subList(i, end).toArray(new Geometry[0]);
SimpleGeometryCursor cursor = new SimpleGeometryCursor(batch);
GeometryCursor result = op.execute(cursor, sr, null);
next.add(result.next());
}
current = next;
}
return current.get(0);
}
4.4 求交操作 (Intersection)
4.4.1 基本求交
Polygon p1 = createPolygon1();
Polygon p2 = createPolygon2();
SpatialReference sr = SpatialReference.create(4326);
// 计算交集
Geometry intersection = GeometryEngine.intersect(p1, p2, sr);
// 结果类型取决于输入几何
// 两个多边形的交集可能是:多边形、线、点或空
4.4.2 指定结果维度
OperatorIntersection op = OperatorIntersection.local();
// dimension 参数:
// 1 = 只返回点
// 2 = 只返回线
// 4 = 只返回面
// 7 = 返回所有 (1+2+4)
GeometryCursor result = op.execute(
new SimpleGeometryCursor(geometry1),
new SimpleGeometryCursor(geometry2),
sr,
null,
7 // 返回所有维度的结果
);
// 遍历不同维度的结果
Geometry g;
while ((g = result.next()) != null) {
System.out.println("类型: " + g.getType() + ", 维度: " + g.getDimension());
}
4.4.3 与包围盒求交
// 使用 Clip 操作与矩形求交更高效
Envelope clipEnvelope = new Envelope(0, 0, 100, 100);
Geometry clipped = GeometryEngine.clip(geometry, clipEnvelope, sr);
4.5 差集操作 (Difference)
4.5.1 基本差集
Polygon p1 = createPolygon1();
Polygon p2 = createPolygon2();
SpatialReference sr = SpatialReference.create(4326);
// 计算 p1 - p2(从 p1 中减去与 p2 相交的部分)
Geometry difference = GeometryEngine.difference(p1, p2, sr);
4.5.2 对称差集
// 对称差集:(A - B) ∪ (B - A)
// 即两个几何不重叠的部分
Geometry symDiff = GeometryEngine.symmetricDifference(p1, p2, sr);
// 使用 Operator
OperatorSymmetricDifference op = OperatorSymmetricDifference.local();
Geometry result = op.execute(p1, p2, sr, null);
4.5.3 擦除操作示例
/**
* 从地图区域中擦除湖泊区域
*/
public Polygon eraseLakes(Polygon landArea, List<Polygon> lakes, SpatialReference sr) {
Polygon result = landArea;
for (Polygon lake : lakes) {
Geometry diff = GeometryEngine.difference(result, lake, sr);
if (!diff.isEmpty() && diff instanceof Polygon) {
result = (Polygon) diff;
}
}
return result;
}
4.6 裁剪操作 (Clip)
4.6.1 基本裁剪
// Clip 专门用于矩形裁剪,比 Intersection 更高效
Geometry geometry = createComplexPolygon();
Envelope clipRect = new Envelope(10, 10, 50, 50);
SpatialReference sr = SpatialReference.create(4326);
Geometry clipped = GeometryEngine.clip(geometry, clipRect, sr);
4.6.2 批量裁剪
OperatorClip op = OperatorClip.local();
Geometry[] geometries = {polygon1, polygon2, polygon3};
SimpleGeometryCursor cursor = new SimpleGeometryCursor(geometries);
Envelope2D clipEnv = Envelope2D.construct(0, 0, 100, 100);
GeometryCursor result = op.execute(cursor, clipEnv, sr, null);
Geometry g;
while ((g = result.next()) != null) {
// 处理裁剪结果
}
4.7 切割操作 (Cut)
4.7.1 使用线切割多边形
Polygon polygon = createPolygon();
Polyline cutter = new Polyline();
cutter.startPath(-10, 50);
cutter.lineTo(110, 50); // 水平线
SpatialReference sr = SpatialReference.create(4326);
// 切割多边形
Geometry[] pieces = GeometryEngine.cut(polygon, cutter, sr);
// 结果包含切割后的各个部分
for (Geometry piece : pieces) {
System.out.println("切割片面积: " + piece.calculateArea2D());
}
4.7.2 切割折线
Polyline polyline = createPolyline();
Polyline cutter = createCutterLine();
SpatialReference sr = SpatialReference.create(4326);
OperatorCut op = OperatorCut.local();
GeometryCursor result = op.execute(true, polyline, cutter, sr, null);
// true = 考虑左右两侧
// 结果按左侧/右侧分组
4.8 凸包操作 (ConvexHull)
4.8.1 单个几何的凸包
MultiPoint points = new MultiPoint();
points.add(0, 0);
points.add(10, 0);
points.add(5, 8);
points.add(3, 3);
points.add(7, 3);
// 计算凸包
Geometry hull = GeometryEngine.convexHull(points);
// 结果是包含所有点的最小凸多边形
4.8.2 多个几何的合并凸包
Geometry[] geometries = {polygon1, polygon2, multiPoint};
// merge = true: 计算所有几何的合并凸包
Geometry[] hulls = GeometryEngine.convexHull(geometries, true);
// 结果只有一个几何
// merge = false: 分别计算每个几何的凸包
Geometry[] individualHulls = GeometryEngine.convexHull(geometries, false);
4.9 简化操作 (Simplify)
4.9.1 ESRI 简化
// ESRI 简化规则
Geometry geometry = createComplexGeometry();
SpatialReference sr = SpatialReference.create(4326);
Geometry simplified = GeometryEngine.simplify(geometry, sr);
4.9.2 OGC 简化
// OGC 简化规则(更严格)
OperatorSimplifyOGC op = OperatorSimplifyOGC.local();
Geometry simplified = op.execute(geometry, sr, true, null);
// true = 强制执行
// 检查是否需要简化
boolean isSimple = op.isSimpleOGC(geometry, sr, true, null, null);
4.9.3 简化检查结果
NonSimpleResult result = new NonSimpleResult();
boolean isSimple = OperatorSimplify.local().isSimpleAsFeature(
geometry, sr, true, result, null);
if (!isSimple) {
System.out.println("不简单的原因: " + result.m_reason);
System.out.println("问题点索引: " + result.m_vertexIndex1);
}
4.10 泛化操作 (Generalize)
4.10.1 道格拉斯-普克算法
Polyline complexLine = createComplexPolyline();
// 泛化参数:最大偏差距离
double maxDeviation = 1.0;
OperatorGeneralize op = OperatorGeneralize.local();
Geometry simplified = op.execute(
complexLine,
maxDeviation,
true, // 移除退化部分
null
);
System.out.println("原始点数: " + ((Polyline)complexLine).getPointCount());
System.out.println("简化后点数: " + ((Polyline)simplified).getPointCount());
4.10.2 批量泛化
Geometry[] geometries = {line1, line2, polygon1};
SimpleGeometryCursor cursor = new SimpleGeometryCursor(geometries);
GeometryCursor result = OperatorGeneralize.local().execute(
cursor,
1.0, // 最大偏差
true, // 移除退化
null
);
Geometry g;
while ((g = result.next()) != null) {
// 处理简化后的几何
}
4.11 偏移操作 (Offset)
4.11.1 线偏移
Polyline line = new Polyline();
line.startPath(0, 0);
line.lineTo(100, 0);
line.lineTo(100, 100);
SpatialReference sr = SpatialReference.create(4326);
OperatorOffset op = OperatorOffset.local();
// 正数 = 左偏移,负数 = 右偏移
double offsetDistance = 10.0;
// 连接类型
OperatorOffset.JoinType joinType = OperatorOffset.JoinType.Round;
// Round = 圆角连接
// Miter = 尖角连接
// Bevel = 斜角连接
// 斜接限制(仅 Miter 类型有效)
double bevelRatio = 2.0;
// 扁平度(仅 Round 类型有效)
double flatness = 0.0;
GeometryCursor result = op.execute(
new SimpleGeometryCursor(line),
sr,
offsetDistance,
joinType,
bevelRatio,
flatness,
null
);
Geometry offsetLine = result.next();
4.11.2 多边形偏移
Polygon polygon = createPolygon();
// 正偏移 = 外扩,负偏移 = 内缩
Geometry outer = OperatorOffset.local().execute(
new SimpleGeometryCursor(polygon),
sr, 5.0,
OperatorOffset.JoinType.Round,
2.0, 0.0, null
).next();
Geometry inner = OperatorOffset.local().execute(
new SimpleGeometryCursor(polygon),
sr, -3.0,
OperatorOffset.JoinType.Round,
2.0, 0.0, null
).next();
4.12 加密操作 (Densify)
4.12.1 按长度加密
Polyline sparseLine = new Polyline();
sparseLine.startPath(0, 0);
sparseLine.lineTo(100, 0);
SpatialReference sr = SpatialReference.create(4326);
// 每 10 单位插入一个点
OperatorDensifyByLength op = OperatorDensifyByLength.local();
GeometryCursor result = op.execute(
new SimpleGeometryCursor(sparseLine),
10.0, // 最大线段长度
null
);
Polyline densified = (Polyline) result.next();
System.out.println("原始点数: " + sparseLine.getPointCount());
System.out.println("加密后点数: " + densified.getPointCount());
4.12.2 测地加密
// 按大地测量距离加密(考虑地球曲率)
OperatorGeodeticDensifyByLength op =
(OperatorGeodeticDensifyByLength) OperatorFactoryLocal
.getInstance()
.getOperator(Operator.Type.GeodeticDensifyByLength);
GeometryCursor result = op.execute(
new SimpleGeometryCursor(geometry),
sr,
1000.0, // 1000 米
null // 使用默认曲线类型
);
4.13 边界操作 (Boundary)
4.13.1 获取边界
// 多边形的边界是折线
Polygon polygon = createPolygon();
Geometry boundary = polygon.getBoundary();
System.out.println("边界类型: " + boundary.getType()); // Polyline
// 折线的边界是端点(多点)
Polyline polyline = createPolyline();
Geometry endpoints = polyline.getBoundary();
System.out.println("端点类型: " + endpoints.getType()); // MultiPoint
// 点没有边界
Point point = new Point(0, 0);
Geometry pointBoundary = point.getBoundary();
System.out.println("点边界: " + pointBoundary); // null
4.13.2 使用 Operator
OperatorBoundary op = OperatorBoundary.local();
Geometry boundary = op.execute(geometry, null);
4.14 几何加速
4.14.1 加速原理
对于重复的空间关系测试,可以预先加速几何对象:
Polygon largePolygon = createLargePolygon();
SpatialReference sr = SpatialReference.create(4326);
// 预先加速几何
OperatorContains op = OperatorContains.local();
boolean canAccelerate = op.canAccelerateGeometry(largePolygon);
if (canAccelerate) {
op.accelerateGeometry(
largePolygon,
sr,
Geometry.GeometryAccelerationDegree.enumMedium
);
}
// 现在对大量点进行包含测试会更快
for (Point point : thousandsOfPoints) {
boolean contains = op.execute(largePolygon, point, sr, null);
}
// 完成后移除加速(释放内存)
Operator.deaccelerateGeometry(largePolygon);
4.14.2 加速级别
public enum GeometryAccelerationDegree {
enumMild, // 轻度加速,内存占用最小
enumMedium, // 中度加速,平衡
enumHot // 高度加速,最快但内存最大
}
4.15 本章小结
本章详细介绍了 geometry-api-java 的空间操作:
- 算子模式:所有操作通过 Operator 类执行
- 流式处理:GeometryCursor 支持大数据处理
- 缓冲区:Buffer 操作,支持正负距离
- 布尔运算:Union、Intersection、Difference、SymmetricDifference
- 裁剪切割:Clip(矩形裁剪)、Cut(线切割)
- 几何处理:ConvexHull、Simplify、Generalize、Offset、Densify
- 边界操作:获取几何边界
- 几何加速:优化重复操作性能
最佳实践:
- 简单操作使用 GeometryEngine
- 批量操作使用 Operator + Cursor
- 重复判断使用几何加速
- 大数据使用流式处理

浙公网安备 33010602011771号