第06章 - 数据格式转换

第06章 - 数据格式转换

6.1 格式支持概述

6.1.1 支持的格式

geometry-api-java 支持多种空间数据格式的导入和导出:

格式 导入 导出 说明
JSON Esri JSON 格式
GeoJSON OGC GeoJSON 格式
WKT Well-Known Text
WKB Well-Known Binary
ESRI Shape Shapefile 二进制格式

6.1.2 格式转换算子

每种格式都有对应的导入和导出算子:

// JSON
OperatorImportFromJson / OperatorExportToJson

// GeoJSON  
OperatorImportFromGeoJson / OperatorExportToGeoJson

// WKT
OperatorImportFromWkt / OperatorExportToWkt

// WKB
OperatorImportFromWkb / OperatorExportToWkb

// ESRI Shape
OperatorImportFromESRIShape / OperatorExportToESRIShape

6.2 Esri JSON 格式

6.2.1 JSON 格式规范

Esri JSON 是 ArcGIS 使用的 JSON 几何格式:

// Point
{"x": 116.4, "y": 39.9}

// Point with Z and M
{"x": 116.4, "y": 39.9, "z": 100, "m": 1.5}

// Polyline
{
  "paths": [
    [[0, 0], [10, 10], [20, 0]],
    [[30, 30], [40, 40]]
  ]
}

// Polygon
{
  "rings": [
    [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]],
    [[2, 2], [2, 8], [8, 8], [8, 2], [2, 2]]
  ]
}

// MultiPoint
{
  "points": [[0, 0], [10, 10], [20, 20]]
}

// With Spatial Reference
{
  "x": 116.4,
  "y": 39.9,
  "spatialReference": {"wkid": 4326}
}

6.2.2 导入 JSON

// 从 JSON 字符串导入
String json = "{\"x\": 116.4, \"y\": 39.9}";

// 方式一:使用 GeometryEngine
MapGeometry mapGeom = GeometryEngine.jsonToGeometry(json);
Geometry geometry = mapGeom.getGeometry();
SpatialReference sr = mapGeom.getSpatialReference();

// 方式二:使用 Operator
OperatorImportFromJson op = OperatorImportFromJson.local();
MapGeometry result = op.execute(Geometry.Type.Unknown, json);

6.2.3 导出 JSON

Point point = new Point(116.4, 39.9);
SpatialReference sr = SpatialReference.create(4326);

// 方式一:使用 GeometryEngine
String json = GeometryEngine.geometryToJson(sr, point);

// 方式二:使用 Operator
OperatorExportToJson op = OperatorExportToJson.local();
String json2 = op.execute(sr, point);

System.out.println(json);
// {"x":116.4,"y":39.9,"spatialReference":{"wkid":4326}}

6.2.4 批量转换

// 批量导出
Geometry[] geometries = {point1, line1, polygon1};
SimpleGeometryCursor cursor = new SimpleGeometryCursor(geometries);

OperatorExportToJson op = OperatorExportToJson.local();
JsonCursor jsonCursor = op.execute(sr, cursor);

String json;
while ((json = jsonCursor.next()) != null) {
    System.out.println(json);
}

6.3 GeoJSON 格式

6.3.1 GeoJSON 格式规范

GeoJSON 是 OGC 标准的 JSON 格式:

// Point
{
  "type": "Point",
  "coordinates": [116.4, 39.9]
}

// LineString
{
  "type": "LineString",
  "coordinates": [[0, 0], [10, 10], [20, 0]]
}

// Polygon
{
  "type": "Polygon",
  "coordinates": [
    [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]],
    [[2, 2], [2, 8], [8, 8], [8, 2], [2, 2]]
  ]
}

// MultiPoint
{
  "type": "MultiPoint",
  "coordinates": [[0, 0], [10, 10]]
}

// GeometryCollection
{
  "type": "GeometryCollection",
  "geometries": [
    {"type": "Point", "coordinates": [0, 0]},
    {"type": "LineString", "coordinates": [[0, 0], [10, 10]]}
  ]
}

6.3.2 导入 GeoJSON

String geoJson = "{\"type\": \"Point\", \"coordinates\": [116.4, 39.9]}";

// 方式一:使用 GeometryEngine
MapGeometry mapGeom = GeometryEngine.geoJsonToGeometry(
    geoJson, 0, Geometry.Type.Unknown);
Geometry geometry = mapGeom.getGeometry();

// 方式二:使用 Operator
OperatorImportFromGeoJson op = OperatorImportFromGeoJson.local();
MapGeometry result = op.execute(0, Geometry.Type.Unknown, geoJson, null);

6.3.3 导出 GeoJSON

Point point = new Point(116.4, 39.9);
SpatialReference sr = SpatialReference.create(4326);

// 方式一:使用 GeometryEngine(不带空间参考)
String geoJson = GeometryEngine.geometryToGeoJson(point);

// 方式二:使用 GeometryEngine(带空间参考)
String geoJson2 = GeometryEngine.geometryToGeoJson(sr, point);

// 方式三:使用 Operator
OperatorExportToGeoJson op = OperatorExportToGeoJson.local();
String geoJson3 = op.execute(sr, point);

6.3.4 GeoJSON 导入/导出标志

// GeoJsonImportFlags
int IMPORT_FLAGS = GeoJsonImportFlags.geoJsonImportDefaults;
// geoJsonImportDefaults = 0
// geoJsonImportNonTrusted = 2  // 不信任输入,进行验证

// GeoJsonExportFlags
int EXPORT_FLAGS = GeoJsonExportFlags.geoJsonExportDefaults;
// geoJsonExportDefaults = 0
// geoJsonExportPreferMultiGeometry = 1  // 优先输出 Multi* 类型

6.3.5 处理 FeatureCollection

// GeoJSON FeatureCollection 需要先解析
String featureCollectionJson = "{ \"type\": \"FeatureCollection\", ...}";

// 使用 Jackson 或其他 JSON 库解析
// 然后提取 geometry 字段进行处理

// 示例:使用 OGC API
import com.esri.core.geometry.ogc.*;

String pointGeoJson = "{\"type\": \"Point\", \"coordinates\": [116.4, 39.9]}";
OGCGeometry ogcGeom = OGCGeometry.fromGeoJson(pointGeoJson);
Geometry esriGeom = ogcGeom.getEsriGeometry();

6.4 WKT 格式

6.4.1 WKT 格式规范

Well-Known Text (WKT) 是一种文本格式:

POINT (116.4 39.9)
POINT Z (116.4 39.9 100)
POINT M (116.4 39.9 50)
POINT ZM (116.4 39.9 100 50)

LINESTRING (0 0, 10 10, 20 0)
LINESTRING EMPTY

POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))
POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 8, 8 8, 8 2, 2 2))

MULTIPOINT ((0 0), (10 10))
MULTILINESTRING ((0 0, 10 10), (20 20, 30 30))
MULTIPOLYGON (((0 0, 10 0, 10 10, 0 10, 0 0)))

GEOMETRYCOLLECTION (POINT (0 0), LINESTRING (0 0, 10 10))

6.4.2 导入 WKT

String wkt = "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))";

// 方式一:使用 GeometryEngine
Geometry geometry = GeometryEngine.geometryFromWkt(
    wkt, 
    WktImportFlags.wktImportDefaults, 
    Geometry.Type.Unknown
);

// 方式二:使用 Operator
OperatorImportFromWkt op = OperatorImportFromWkt.local();
Geometry result = op.execute(0, Geometry.Type.Unknown, wkt, null);

6.4.3 导出 WKT

Polygon polygon = createPolygon();

// 方式一:使用 GeometryEngine
String wkt = GeometryEngine.geometryToWkt(polygon, WktExportFlags.wktExportDefaults);

// 方式二:使用 Operator
OperatorExportToWkt op = OperatorExportToWkt.local();
String wkt2 = op.execute(0, polygon, null);

System.out.println(wkt);
// POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))

6.4.4 WKT 导入/导出标志

// WktImportFlags
int flags = WktImportFlags.wktImportDefaults;    // 默认
int flags2 = WktImportFlags.wktImportNonTrusted; // 不信任输入

// WktExportFlags
int exportFlags = WktExportFlags.wktExportDefaults;   // 默认
int exportFlags2 = WktExportFlags.wktExportMultiPoint; // 导出为 MULTIPOINT
int exportFlags3 = WktExportFlags.wktExportLineString; // 导出为 LINESTRING
int exportFlags4 = WktExportFlags.wktExportPolygon;    // 导出为 POLYGON
int exportFlags5 = WktExportFlags.wktExportPoint;      // 导出为 POINT

6.4.5 处理带 Z/M 的 WKT

// 导入带 Z 的 WKT
String wktZ = "POINT Z (116.4 39.9 100)";
Geometry geom = GeometryEngine.geometryFromWkt(wktZ, 0, Geometry.Type.Unknown);
Point point = (Point) geom;
System.out.println("Z 值: " + point.getZ());

// 导入带 M 的 WKT
String wktM = "POINT M (116.4 39.9 50.5)";
Geometry geomM = GeometryEngine.geometryFromWkt(wktM, 0, Geometry.Type.Unknown);

// 导入带 ZM 的 WKT
String wktZM = "POINT ZM (116.4 39.9 100 50.5)";
Geometry geomZM = GeometryEngine.geometryFromWkt(wktZM, 0, Geometry.Type.Unknown);

6.5 WKB 格式

6.5.1 WKB 格式概述

Well-Known Binary (WKB) 是 WKT 的二进制版本,用于高效存储和传输:

结构:
[字节序(1字节)] [几何类型(4字节)] [坐标数据...]

字节序:
01 = 小端序 (Little Endian)
00 = 大端序 (Big Endian)

几何类型:
1 = Point
2 = LineString
3 = Polygon
4 = MultiPoint
5 = MultiLineString
6 = MultiPolygon
7 = GeometryCollection

6.5.2 导入 WKB

byte[] wkbBytes = getWkbData();
ByteBuffer wkb = ByteBuffer.wrap(wkbBytes);

// 方式一:使用 Operator
OperatorImportFromWkb op = OperatorImportFromWkb.local();
Geometry geometry = op.execute(0, Geometry.Type.Unknown, wkb, null);

// 支持 OGC 结构
OGCStructure ogcStructure = op.executeOGC(0, wkb, null);

6.5.3 导出 WKB

Polygon polygon = createPolygon();

// 方式一:使用 Operator
OperatorExportToWkb op = OperatorExportToWkb.local();
ByteBuffer wkb = op.execute(0, polygon, null);

// 转换为字节数组
byte[] bytes = new byte[wkb.remaining()];
wkb.get(bytes);

6.5.4 WKB 字节序

// 设置字节序
int flags = WkbExportFlags.wkbExportDefaults;      // 默认(大端序)
int flagsLE = WkbExportFlags.wkbExportLittleEndian; // 小端序

ByteBuffer wkbLE = OperatorExportToWkb.local().execute(
    WkbExportFlags.wkbExportLittleEndian, 
    geometry, 
    null
);

6.5.5 WKB 与数据库集成

// PostGIS 通常使用 WKB 格式
// 从 ResultSet 读取 WKB
ResultSet rs = stmt.executeQuery("SELECT ST_AsBinary(geom) FROM table");
while (rs.next()) {
    byte[] wkb = rs.getBytes(1);
    ByteBuffer buffer = ByteBuffer.wrap(wkb);
    Geometry geom = OperatorImportFromWkb.local()
        .execute(0, Geometry.Type.Unknown, buffer, null);
}

// 将 WKB 写入数据库
ByteBuffer wkb = OperatorExportToWkb.local().execute(0, geometry, null);
pstmt.setBytes(1, wkb.array());

6.6 ESRI Shape 格式

6.6.1 Shape 格式概述

ESRI Shape 格式是 Shapefile 中存储几何的二进制格式:

结构:
[ShapeType(4字节)] [BoundingBox(32字节)] [Parts...] [Points...]

6.6.2 导入 Shape

byte[] shapeBytes = getShapeData();

// 使用 GeometryEngine
Geometry geometry = GeometryEngine.geometryFromEsriShape(
    shapeBytes, 
    Geometry.Type.Unknown
);

// 使用 Operator
OperatorImportFromESRIShape op = OperatorImportFromESRIShape.local();
ByteBuffer buffer = ByteBuffer.wrap(shapeBytes);
buffer.order(ByteOrder.LITTLE_ENDIAN);
Geometry result = op.execute(0, Geometry.Type.Unknown, buffer);

6.6.3 导出 Shape

Polygon polygon = createPolygon();

// 使用 GeometryEngine
byte[] shapeBytes = GeometryEngine.geometryToEsriShape(polygon);

// 使用 Operator
OperatorExportToESRIShape op = OperatorExportToESRIShape.local();
ByteBuffer buffer = op.execute(0, polygon);

6.6.4 Shape 导入/导出标志

// ShapeImportFlags
int flags = ShapeImportFlags.ShapeImportDefaults;    // 默认
int flags2 = ShapeImportFlags.ShapeImportNonTrusted; // 不信任输入

// ShapeExportFlags
int exportFlags = ShapeExportFlags.ShapeExportDefaults; // 默认

6.7 格式转换实战

6.7.1 WKT 转 GeoJSON

public String wktToGeoJson(String wkt) {
    Geometry geometry = GeometryEngine.geometryFromWkt(
        wkt, 0, Geometry.Type.Unknown);
    return GeometryEngine.geometryToGeoJson(geometry);
}

// 使用
String wkt = "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))";
String geoJson = wktToGeoJson(wkt);

6.7.2 GeoJSON 转 WKT

public String geoJsonToWkt(String geoJson) {
    MapGeometry mapGeom = GeometryEngine.geoJsonToGeometry(
        geoJson, 0, Geometry.Type.Unknown);
    return GeometryEngine.geometryToWkt(mapGeom.getGeometry(), 0);
}

// 使用
String geoJson = "{\"type\": \"Point\", \"coordinates\": [116.4, 39.9]}";
String wkt = geoJsonToWkt(geoJson);
// 结果: POINT (116.4 39.9)

6.7.3 批量格式转换

/**
 * 批量将 WKT 转换为 GeoJSON
 */
public List<String> batchWktToGeoJson(List<String> wktList) {
    List<String> results = new ArrayList<>();
    
    OperatorImportFromWkt importOp = OperatorImportFromWkt.local();
    OperatorExportToGeoJson exportOp = OperatorExportToGeoJson.local();
    
    for (String wkt : wktList) {
        Geometry geom = importOp.execute(0, Geometry.Type.Unknown, wkt, null);
        String geoJson = exportOp.execute(null, geom);
        results.add(geoJson);
    }
    
    return results;
}

6.7.4 格式转换工具类

public class GeometryFormatConverter {
    
    public static Geometry fromWkt(String wkt) {
        return GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown);
    }
    
    public static String toWkt(Geometry geometry) {
        return GeometryEngine.geometryToWkt(geometry, 0);
    }
    
    public static Geometry fromGeoJson(String geoJson) {
        MapGeometry mg = GeometryEngine.geoJsonToGeometry(
            geoJson, 0, Geometry.Type.Unknown);
        return mg.getGeometry();
    }
    
    public static String toGeoJson(Geometry geometry) {
        return GeometryEngine.geometryToGeoJson(geometry);
    }
    
    public static Geometry fromWkb(byte[] wkb) {
        ByteBuffer buffer = ByteBuffer.wrap(wkb);
        return OperatorImportFromWkb.local()
            .execute(0, Geometry.Type.Unknown, buffer, null);
    }
    
    public static byte[] toWkb(Geometry geometry) {
        ByteBuffer buffer = OperatorExportToWkb.local()
            .execute(0, geometry, null);
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes);
        return bytes;
    }
    
    public static Geometry fromJson(String json) {
        MapGeometry mg = GeometryEngine.jsonToGeometry(json);
        return mg.getGeometry();
    }
    
    public static String toJson(Geometry geometry, SpatialReference sr) {
        return GeometryEngine.geometryToJson(sr, geometry);
    }
}

6.8 处理复杂几何

6.8.1 GeometryCollection 处理

// 导入 GeometryCollection
String wkt = "GEOMETRYCOLLECTION (POINT (0 0), LINESTRING (0 0, 10 10))";

// 使用 OGC API 处理
OGCGeometry ogcGeom = OGCGeometry.fromText(wkt);
if (ogcGeom instanceof OGCConcreteGeometryCollection) {
    OGCConcreteGeometryCollection collection = 
        (OGCConcreteGeometryCollection) ogcGeom;
    
    int numGeoms = collection.numGeometries();
    for (int i = 0; i < numGeoms; i++) {
        OGCGeometry geom = collection.geometryN(i);
        System.out.println(geom.geometryType());
    }
}

6.8.2 多部分几何

// MultiPolygon WKT
String multiPolygonWkt = "MULTIPOLYGON (((0 0, 10 0, 10 10, 0 10, 0 0)), " +
    "((20 20, 30 20, 30 30, 20 30, 20 20)))";

Geometry geom = GeometryEngine.geometryFromWkt(
    multiPolygonWkt, 0, Geometry.Type.Unknown);

// 在 ESRI 几何中,MultiPolygon 表示为单个 Polygon 多个环
Polygon polygon = (Polygon) geom;
int pathCount = polygon.getPathCount();
System.out.println("环数量: " + pathCount);

6.9 错误处理

6.9.1 格式解析错误

public Geometry safeParseWkt(String wkt) {
    try {
        return GeometryEngine.geometryFromWkt(wkt, 0, Geometry.Type.Unknown);
    } catch (IllegalArgumentException e) {
        System.err.println("WKT 解析错误: " + e.getMessage());
        return null;
    } catch (GeometryException e) {
        System.err.println("几何错误: " + e.getMessage());
        return null;
    }
}

public Geometry safeParseGeoJson(String geoJson) {
    try {
        MapGeometry mg = GeometryEngine.geoJsonToGeometry(
            geoJson, 0, Geometry.Type.Unknown);
        return mg.getGeometry();
    } catch (Exception e) {
        System.err.println("GeoJSON 解析错误: " + e.getMessage());
        return null;
    }
}

6.9.2 验证几何

public boolean isValidGeometry(Geometry geometry, SpatialReference sr) {
    if (geometry == null || geometry.isEmpty()) {
        return false;
    }
    
    // 检查是否简单
    OperatorSimplify op = OperatorSimplify.local();
    NonSimpleResult result = new NonSimpleResult();
    boolean isSimple = op.isSimpleAsFeature(geometry, sr, true, result, null);
    
    if (!isSimple) {
        System.err.println("几何不简单: " + result.m_reason);
        return false;
    }
    
    return true;
}

6.10 本章小结

本章详细介绍了 geometry-api-java 的数据格式转换:

  1. JSON 格式:Esri JSON,带空间参考
  2. GeoJSON 格式:OGC 标准格式
  3. WKT 格式:文本格式,支持 Z/M
  4. WKB 格式:二进制格式,适合数据库存储
  5. Shape 格式:Shapefile 几何格式
  6. 格式转换:相互转换的方法
  7. 复杂几何:GeometryCollection 处理
  8. 错误处理:解析和验证

最佳实践

  • 根据场景选择合适格式
  • 使用工具类封装转换逻辑
  • 处理可能的解析错误
  • 验证输入几何的有效性

← 上一章:空间关系判断 | 下一章:坐标系与空间参考 →

posted @ 2025-12-03 15:15  我才是银古  阅读(6)  评论(0)    收藏  举报