02-几何数据基础
几何数据基础
概述
几何数据是GIS的核心。所有的空间分析都建立在几何对象之上。本章介绍几何数据的基本概念、创建方法和常用操作。
几何对象模型
坐标点(Coordinate)
坐标点是几何数据的最小单元,由X、Y坐标组成(三维数据还包含Z坐标):
// 创建坐标点
Coordinate coord = new Coordinate(116.397, 39.908);
// 带高程的坐标点
Coordinate coord3D = new Coordinate(116.397, 39.908, 100);
几何工厂(GeometryFactory)
几何工厂用于创建各种几何对象:
// 使用默认精度模型
GeometryFactory factory = new GeometryFactory();
// 使用指定精度模型(浮点精度)
GeometryFactory factory = new GeometryFactory(
new PrecisionModel(PrecisionModel.FLOATING)
);
基本几何类型
点(Point)
点是最简单的几何类型,表示单个位置:
// 从坐标创建点
Point point = factory.createPoint(new Coordinate(116.397, 39.908));
// 获取坐标值
double x = point.getX();
double y = point.getY();
应用场景:POI(兴趣点)、设备位置、采样点等。
线(LineString)
线由一系列有序的点组成:
// 创建线
Coordinate[] coords = new Coordinate[] {
new Coordinate(0, 0),
new Coordinate(10, 10),
new Coordinate(20, 0)
};
LineString line = factory.createLineString(coords);
// 线的基本属性
double length = line.getLength(); // 长度
boolean closed = line.isClosed(); // 是否闭合
Point start = line.getStartPoint(); // 起点
Point end = line.getEndPoint(); // 终点
int numPoints = line.getNumPoints(); // 节点数
应用场景:道路、河流、管线等。
环(LinearRing)
环是闭合的线,首尾点坐标相同:
// 创建环(首尾点必须相同)
Coordinate[] ringCoords = new Coordinate[] {
new Coordinate(0, 0),
new Coordinate(10, 0),
new Coordinate(10, 10),
new Coordinate(0, 10),
new Coordinate(0, 0) // 与起点相同
};
LinearRing ring = factory.createLinearRing(ringCoords);
// 判断是否为环
boolean isRing = ring.isRing();
面(Polygon)
面由外环和可选的内环(岛洞)组成:
// 外环
LinearRing shell = factory.createLinearRing(outerCoords);
// 内环(岛洞)
LinearRing hole = factory.createLinearRing(innerCoords);
// 创建带洞的多边形
Polygon polygon = factory.createPolygon(shell, new LinearRing[]{hole});
// 面的基本属性
double area = polygon.getArea(); // 面积
Geometry exterior = polygon.getExteriorRing(); // 外环
int numHoles = polygon.getNumInteriorRing(); // 内环数量
Geometry interior = polygon.getInteriorRingN(0); // 第一个内环
应用场景:地块、行政区划、建筑物轮廓等。
多点(MultiPoint)
多个点的集合:
Point[] points = new Point[] {
factory.createPoint(new Coordinate(0, 0)),
factory.createPoint(new Coordinate(10, 10))
};
MultiPoint multiPoint = factory.createMultiPoint(points);
多线(MultiLineString)
多条线的集合:
LineString[] lines = new LineString[] {line1, line2, line3};
MultiLineString multiLine = factory.createMultiLineString(lines);
多面(MultiPolygon)
多个面的集合:
Polygon[] polygons = new Polygon[] {polygon1, polygon2};
MultiPolygon multiPolygon = factory.createMultiPolygon(polygons);
WKT格式
WKT(Well-Known Text)是几何对象的标准文本表示格式:
// WKT示例
String pointWkt = "POINT (116.397 39.908)";
String lineWkt = "LINESTRING (0 0, 10 10, 20 0)";
String polygonWkt = "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))";
String multiPolygonWkt = "MULTIPOLYGON (((0 0, 10 0, 10 10, 0 10, 0 0)))";
WKT与几何对象互转
// WKT转Geometry
public static Geometry wkt2Geometry(String wkt) {
WKTReader2 reader = new WKTReader2();
return reader.read(wkt);
}
// Geometry转WKT
public static String geometry2Wkt(Geometry geometry) {
WKTWriter2 writer = new WKTWriter2();
return writer.write(geometry);
}
实践要点:
- WKT是调试和日志记录的首选格式
- 数据交换时使用WKT可避免二进制格式的兼容性问题
- 大数据量场景下,WKB(二进制格式)效率更高
几何类型判断
判断几何类型是数据处理的常见需求:
/**
* 获取几何类型
*/
public static GeometryType geometryType(Geometry geom) {
return GeometryType.valueOfByTypeName(geom.getGeometryType());
}
// 使用方式
Geometry geom = wkt2Geometry(wkt);
GeometryType type = geometryType(geom);
switch (type) {
case POINT:
// 点处理逻辑
break;
case POLYGON:
case MULTIPOLYGON:
// 面处理逻辑
break;
// ...
}
基本属性获取
判断几何是否为空
/**
* 判断几何是否为空
*/
public static boolean isEmpty(Geometry geom) {
return geom.isEmpty();
}
获取几何维度
/**
* 获取几何维度
* 点为0,线为1,面为2
*/
public static int dimension(Geometry geom) {
return geom.getDimension();
}
获取节点数量
/**
* 获取节点个数
*/
public static int numPoints(Geometry geom) {
return geom.getNumPoints();
}
获取长度和面积
/**
* 获取几何长度
* 注意:结果单位与坐标系单位一致
*/
public static double length(Geometry geom) {
return geom.getLength();
}
/**
* 获取几何面积
* 注意:结果单位与坐标系单位一致
*/
public static double area(Geometry geom) {
return geom.getArea();
}
重要提醒:长度和面积的计算结果与坐标系相关:
- 地理坐标系(经纬度):单位为度,计算结果没有实际意义
- 投影坐标系:单位为米,计算结果为实际的米/平方米
中心点计算
几何中心(质心)
/**
* 获取几何中心点(质心)
* 可能位于几何外部
*/
public static Geometry centroid(Geometry geom) {
return geom.getCentroid();
}
内部中心点
/**
* 获取几何内部中心点
* 保证位于几何内部
*/
public static Geometry interiorPoint(Geometry geom) {
return geom.getInteriorPoint();
}
选择建议:
- 标注点位时使用
interiorPoint,确保标注在要素内部 - 统计分析时使用
centroid,获取几何质心
边界与外包矩形
获取边界
/**
* 获取几何边界
* 面返回边界线,线返回端点
*/
public static Geometry boundary(Geometry geom) {
return geom.getBoundary();
}
获取外包矩形
/**
* 获取几何外包矩形
* 返回包围几何的最小矩形
*/
public static Geometry envelope(Geometry geom) {
return geom.getEnvelope();
}
应用场景:
- 快速空间筛选(先用外包矩形过滤,再精确判断)
- 确定地图显示范围
- 空间索引构建
几何有效性检查
拓扑有效性
几何对象必须符合特定的拓扑规则才被认为是有效的:
/**
* 判断几何拓扑是否合法
*/
public static IsValidModel isValid(Geometry geom) {
IsValidOp isValidOp = new IsValidOp(geom);
if (!isValidOp.isValid()) {
TopologyValidationErrorType type = TopologyValidationErrorType
.getByErrorType(isValidOp.getValidationError().getErrorType());
String msg = type != null ? type.getDesc() : "未知拓扑错误";
return new IsValidModel(false,
isValidOp.getValidationError().getCoordinate(), type, msg);
}
return new IsValidModel(true, null, null, null);
}
常见的拓扑错误类型:
- 自相交:多边形边界与自身相交
- 重复点:相邻节点坐标相同
- 环方向错误:外环应逆时针,内环应顺时针
- 岛洞错误:内环不在外环内部
简单几何判断
/**
* 判断几何是否简单
* 线不自相交为简单,面无自相交为简单
*/
public static IsSimpleModel isSimple(Geometry geom) {
IsSimpleOp isSimpleOp = new IsSimpleOp(geom);
isSimpleOp.setFindAllLocations(true);
if (!isSimpleOp.isSimple()) {
return new IsSimpleModel(false, isSimpleOp.getNonSimpleLocations());
}
return new IsSimpleModel(true, null);
}
几何修复
对于无效的几何,可以尝试自动修复:
/**
* 修复无效几何
* 主要针对多边形的自相交问题
*/
public static Geometry validate(Geometry geom) {
if (geom instanceof Polygon) {
if (geom.isValid()) {
geom.normalize();
return geom;
}
Polygonizer polygonizer = new Polygonizer();
addPolygon((Polygon) geom, polygonizer);
return toPolygonGeometry(polygonizer.getPolygons());
} else if (geom instanceof MultiPolygon) {
if (geom.isValid()) {
geom.normalize();
return geom;
}
Polygonizer polygonizer = new Polygonizer();
for (int n = geom.getNumGeometries(); n-- > 0; ) {
addPolygon((Polygon) geom.getGeometryN(n), polygonizer);
}
return toPolygonGeometry(polygonizer.getPolygons());
}
return geom;
}
修复原理:通过多边形化(Polygonize)算法,将几何边界重新组织为有效的多边形。
实践案例
案例1:计算地块面积
// 读取WKT格式的地块数据
String wkt = "POLYGON((...))" ;
Geometry geom = wkt2Geometry(wkt);
// 检查坐标系
// 如果是经纬度坐标,需要先转换到投影坐标系
int wkid = 4490; // CGCS2000地理坐标系
int projWkid = CrsUtil.getProjectedWkid(geom); // 获取对应投影坐标系
// 坐标转换
Geometry projGeom = CrsUtil.transform(geom, wkid, projWkid);
// 计算面积(结果为平方米)
double areaSqm = area(projGeom);
double areaMu = areaSqm / 666.67; // 转换为亩
案例2:批量数据有效性检查
List<String> invalidWkts = new ArrayList<>();
for (WktFeature feature : layer.getFeatures()) {
Geometry geom = wkt2Geometry(feature.getWkt());
IsValidModel result = isValid(geom);
if (!result.isValid()) {
System.out.println("要素ID: " + feature.getWfId() +
" 错误类型: " + result.getMessage() +
" 错误位置: " + result.getCoordinate());
invalidWkts.add(feature.getWkt());
}
}
小结
本章介绍了几何数据的基础知识:
- 几何模型:点、线、面是基本几何类型,通过组合形成复杂几何
- WKT格式:标准的文本表示格式,便于数据交换和调试
- 基本属性:长度、面积、中心点等是常用的几何属性
- 有效性检查:数据处理前应检查几何有效性,必要时进行修复
下一章将介绍坐标系统,理解坐标系是正确处理GIS数据的关键。

浙公网安备 33010602011771号