第04章 - 统一图层模型详解

第04章 - 统一图层模型详解

4.1 模型设计理念

4.1.1 为什么需要统一模型

在GIS开发中,不同的库使用不同的数据模型:

要素类 要素 几何
GeoTools SimpleFeatureType SimpleFeature Geometry
GDAL/OGR Layer Feature Geometry
ESRI FeatureClass Feature Geometry

这种差异带来的问题:

  1. 代码不可移植:为GeoTools写的代码不能用于GDAL
  2. 学习成本高:每个库都有自己的概念体系
  3. 维护困难:需要熟悉多套API

OGU4J的统一模型解决了这些问题,提供了与底层库无关的数据抽象。

4.1.2 模型设计原则

  1. 简洁性:只保留必要的属性和方法
  2. 通用性:适用于所有GIS数据格式
  3. 可序列化:支持JSON序列化/反序列化
  4. 可扩展性:支持元数据扩展

4.1.3 模型类图

┌─────────────────────────────────────────────────────────────────────┐
│                              OguLayer                                │
│                          (统一图层定义)                              │
├─────────────────────────────────────────────────────────────────────┤
│  - name: String              图层名称                                │
│  - wkid: Integer             坐标系WKID                              │
│  - geometryType: GeometryType 几何类型                               │
│  - fields: List<OguField>    字段列表                                │
│  - features: List<OguFeature> 要素列表                               │
│  - metadata: OguLayerMetadata 元数据                                 │
├─────────────────────────────────────────────────────────────────────┤
│  + validate()                 验证图层完整性                          │
│  + filter(OguFeatureFilter)   过滤要素                               │
│  + getFeatureCount()          获取要素数量                            │
│  + toJSON() / fromJSON()      JSON序列化                             │
└─────────────────────────────────────────────────────────────────────┘
         │                           │                      │
         │ 1:n                       │ 1:n                  │ 1:1
         ▼                           ▼                      ▼
┌─────────────────┐    ┌─────────────────────┐    ┌─────────────────────┐
│    OguField     │    │    OguFeature       │    │  OguLayerMetadata   │
│  (字段定义)     │    │    (要素类)         │    │   (图层元数据)      │
├─────────────────┤    ├─────────────────────┤    ├─────────────────────┤
│ - name          │    │ - fid               │    │ - dataSource        │
│ - alias         │    │ - wkt               │    │ - coordinateSystem  │
│ - dataType      │    │ - attributes: Map   │    │ - zoneNumber        │
│ - length        │    │   <String,          │    │ - projectionType    │
│ - precision     │    │    OguFieldValue>   │    │ - measureUnit       │
│ - nullable      │    ├─────────────────────┤    │ - extendedInfo      │
├─────────────────┤    │ + getValue()        │    └─────────────────────┘
│ + 标准getter    │    │ + setValue()        │
│ + 标准setter    │    │ + getAttribute()    │
└─────────────────┘    └─────────────────────┘
                                │
                                │ 1:n
                                ▼
                       ┌─────────────────────┐
                       │   OguFieldValue     │
                       │   (字段值容器)      │
                       ├─────────────────────┤
                       │ - value: Object     │
                       ├─────────────────────┤
                       │ + getStringValue()  │
                       │ + getIntValue()     │
                       │ + getDoubleValue()  │
                       │ + getDateValue()    │
                       │ + getBooleanValue() │
                       └─────────────────────┘

4.2 OguLayer - 图层类

4.2.1 类定义

/**
 * 统一的GIS图层定义
 * 代表一个完整的GIS图层,包含图层名称、坐标系、几何类型、字段定义和要素集合
 * 
 * 设计理念:
 * - 独立于任何GIS库的数据表示
 * - 支持JSON序列化,便于传输和存储
 * - 提供便捷的操作方法
 */
@Data
public class OguLayer {
    
    /**
     * 图层名称
     */
    private String name;
    
    /**
     * 坐标系WKID(Well-Known ID)
     * 例如:4490 = CGCS2000地理坐标系
     *       4524 = CGCS2000 / 3-degree Gauss-Kruger zone 39
     */
    private Integer wkid;
    
    /**
     * 几何类型
     */
    private GeometryType geometryType;
    
    /**
     * 字段定义列表
     */
    private List<OguField> fields;
    
    /**
     * 要素列表
     */
    private List<OguFeature> features;
    
    /**
     * 图层元数据(可选)
     */
    private OguLayerMetadata metadata;
    
    // ... 方法定义
}

4.2.2 创建图层

方式1:代码构建

// 创建图层
OguLayer layer = new OguLayer();
layer.setName("行政区划");
layer.setWkid(4490);
layer.setGeometryType(GeometryType.POLYGON);

// 定义字段
List<OguField> fields = new ArrayList<>();

OguField codeField = new OguField();
codeField.setName("CODE");
codeField.setAlias("行政区划代码");
codeField.setDataType(FieldDataType.STRING);
codeField.setLength(12);

OguField nameField = new OguField();
nameField.setName("NAME");
nameField.setAlias("名称");
nameField.setDataType(FieldDataType.STRING);
nameField.setLength(100);

fields.add(codeField);
fields.add(nameField);
layer.setFields(fields);

// 添加要素
List<OguFeature> features = new ArrayList<>();
OguFeature feature = new OguFeature();
feature.setFid("1");
feature.setWkt("POLYGON((116 39, 116 40, 117 40, 117 39, 116 39))");
feature.setValue("CODE", "110000");
feature.setValue("NAME", "北京市");
features.add(feature);
layer.setFeatures(features);

方式2:从JSON创建

String json = "{" +
    "\"name\":\"行政区划\"," +
    "\"wkid\":4490," +
    "\"geometryType\":\"POLYGON\"," +
    "\"fields\":[...]," +
    "\"features\":[...]" +
    "}";

OguLayer layer = OguLayer.fromJSON(json);

方式3:从数据源读取

OguLayer layer = OguLayerUtil.readLayer(
    DataFormatType.SHP,
    "D:/data/districts.shp",
    null, null, null,
    GisEngineType.GEOTOOLS
);

4.2.3 图层验证

/**
 * 验证图层数据完整性
 * 检查项包括:
 * - 图层名称不能为空
 * - 几何类型必须设置
 * - 字段列表不能为null
 * - 要素的几何类型必须与图层一致
 */
layer.validate();

// 可能抛出的异常
try {
    layer.validate();
} catch (LayerValidationException e) {
    System.out.println("验证失败: " + e.getMessage());
}

4.2.4 要素过滤

// 使用Lambda表达式过滤要素
List<OguFeature> beijingFeatures = layer.filter(
    feature -> "北京市".equals(feature.getValue("NAME"))
);

// 复杂过滤条件
List<OguFeature> largeAreas = layer.filter(feature -> {
    Double area = feature.getAttribute("AREA").getDoubleValue();
    return area != null && area > 10000;
});

// 组合过滤
List<OguFeature> result = layer.filter(feature -> {
    String name = feature.getAttribute("NAME").getStringValue();
    Integer level = feature.getAttribute("LEVEL").getIntValue();
    return name != null && name.contains("市") && level != null && level == 1;
});

4.2.5 JSON序列化

// 转换为JSON
String json = layer.toJSON();
System.out.println(json);

// 从JSON恢复
OguLayer restored = OguLayer.fromJSON(json);

// 格式化输出(便于阅读)
String prettyJson = JSON.toJSONString(layer, 
    JSONWriter.Feature.PrettyFormat);

4.3 OguField - 字段类

4.3.1 类定义

/**
 * 统一的字段定义类
 * 描述图层中的一个属性字段
 */
@Data
public class OguField {
    
    /**
     * 字段名称(必填)
     * 建议使用英文,符合数据库命名规范
     */
    private String name;
    
    /**
     * 字段别名(可选)
     * 用于显示的中文名称
     */
    private String alias;
    
    /**
     * 数据类型(必填)
     */
    private FieldDataType dataType;
    
    /**
     * 字段长度(字符串类型必填)
     */
    private Integer length;
    
    /**
     * 数值精度(可选,用于浮点数)
     */
    private Integer precision;
    
    /**
     * 是否允许空值,默认true
     */
    private Boolean nullable = true;
    
    /**
     * 默认值(可选)
     */
    private Object defaultValue;
}

4.3.2 字段数据类型

/**
 * 字段数据类型枚举
 */
public enum FieldDataType {
    STRING("字符串"),
    INTEGER("整数"),
    LONG("长整数"),
    DOUBLE("浮点数"),
    FLOAT("单精度浮点"),
    DATE("日期"),
    DATETIME("日期时间"),
    BOOLEAN("布尔值"),
    BINARY("二进制");
    
    private final String desc;
    
    // 类型转换方法
    public static FieldDataType fromJavaType(Class<?> clazz) {
        if (String.class.equals(clazz)) return STRING;
        if (Integer.class.equals(clazz)) return INTEGER;
        if (Long.class.equals(clazz)) return LONG;
        if (Double.class.equals(clazz)) return DOUBLE;
        if (Float.class.equals(clazz)) return FLOAT;
        if (Date.class.equals(clazz)) return DATETIME;
        if (Boolean.class.equals(clazz)) return BOOLEAN;
        return STRING;
    }
}

4.3.3 创建字段

// 字符串字段
OguField nameField = new OguField();
nameField.setName("NAME");
nameField.setAlias("名称");
nameField.setDataType(FieldDataType.STRING);
nameField.setLength(100);
nameField.setNullable(false);

// 数值字段
OguField areaField = new OguField();
areaField.setName("AREA");
areaField.setAlias("面积");
areaField.setDataType(FieldDataType.DOUBLE);
areaField.setPrecision(2);

// 日期字段
OguField dateField = new OguField();
dateField.setName("CREATE_TIME");
dateField.setAlias("创建时间");
dateField.setDataType(FieldDataType.DATETIME);

// 布尔字段
OguField activeField = new OguField();
activeField.setName("IS_ACTIVE");
activeField.setAlias("是否有效");
activeField.setDataType(FieldDataType.BOOLEAN);
activeField.setDefaultValue(true);

4.4 OguFeature - 要素类

4.4.1 类定义

/**
 * 统一的要素类
 * 代表图层中的一个地理要素,包含ID、几何信息和属性值
 */
@Data
public class OguFeature {
    
    /**
     * 要素ID(FID)
     * 唯一标识一个要素
     */
    private String fid;
    
    /**
     * 几何信息(WKT格式)
     * 例如:"POLYGON((116 39, 116 40, 117 40, 117 39, 116 39))"
     */
    private String wkt;
    
    /**
     * 属性值集合
     * Key: 字段名称
     * Value: 字段值容器
     */
    private Map<String, OguFieldValue> attributes;
    
    /**
     * 坐标列表(可选,用于国土TXT格式)
     */
    private List<OguCoordinate> coordinates;
    
    // ... 方法定义
}

4.4.2 属性操作

获取属性值

OguFeature feature = layer.getFeatures().get(0);

// 方式1:直接获取原始值
Object value = feature.getValue("NAME");
String name = (String) value;

// 方式2:通过OguFieldValue获取(推荐)
OguFieldValue fieldValue = feature.getAttribute("NAME");
String name = fieldValue.getStringValue();
Integer code = feature.getAttribute("CODE").getIntValue();
Double area = feature.getAttribute("AREA").getDoubleValue();

// 安全获取(处理null值)
String safeName = Optional.ofNullable(feature.getAttribute("NAME"))
    .map(OguFieldValue::getStringValue)
    .orElse("未知");

设置属性值

// 设置单个属性
feature.setValue("NAME", "北京市");
feature.setValue("AREA", 16410.54);
feature.setValue("POPULATION", 21540000);

// 批量设置
Map<String, Object> values = new HashMap<>();
values.put("NAME", "上海市");
values.put("AREA", 6340.5);
values.put("POPULATION", 24280000);
feature.setValues(values);

4.4.3 几何操作

// 获取WKT
String wkt = feature.getWkt();
System.out.println(wkt);
// 输出: POLYGON((116 39, 116 40, 117 40, 117 39, 116 39))

// 设置WKT
feature.setWkt("POLYGON((120 30, 120 31, 121 31, 121 30, 120 30))");

// 转换为JTS Geometry进行操作
Geometry geom = GeometryUtil.wkt2Geometry(feature.getWkt());
double area = geom.getArea();
Geometry centroid = geom.getCentroid();

// 更新几何
Geometry buffered = geom.buffer(0.01);
feature.setWkt(GeometryUtil.geometry2Wkt(buffered));

4.5 OguFieldValue - 字段值容器

4.5.1 类定义

/**
 * 字段值容器
 * 封装原始值,提供类型安全的值获取方法
 * 
 * 设计理念:
 * - 统一处理null值
 * - 提供类型转换
 * - 避免ClassCastException
 */
@Data
public class OguFieldValue {
    
    /**
     * 原始值
     */
    private Object value;
    
    public OguFieldValue() {}
    
    public OguFieldValue(Object value) {
        this.value = value;
    }
    
    /**
     * 获取字符串值
     */
    public String getStringValue() {
        if (value == null) return null;
        return String.valueOf(value);
    }
    
    /**
     * 获取整数值
     */
    public Integer getIntValue() {
        if (value == null) return null;
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        try {
            return Integer.parseInt(String.valueOf(value));
        } catch (NumberFormatException e) {
            return null;
        }
    }
    
    /**
     * 获取Double值
     */
    public Double getDoubleValue() {
        if (value == null) return null;
        if (value instanceof Number) {
            return ((Number) value).doubleValue();
        }
        try {
            return Double.parseDouble(String.valueOf(value));
        } catch (NumberFormatException e) {
            return null;
        }
    }
    
    /**
     * 获取Long值
     */
    public Long getLongValue() {
        if (value == null) return null;
        if (value instanceof Number) {
            return ((Number) value).longValue();
        }
        try {
            return Long.parseLong(String.valueOf(value));
        } catch (NumberFormatException e) {
            return null;
        }
    }
    
    /**
     * 获取布尔值
     */
    public Boolean getBooleanValue() {
        if (value == null) return null;
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        String str = String.valueOf(value).toLowerCase();
        return "true".equals(str) || "1".equals(str) || "yes".equals(str);
    }
    
    /**
     * 获取日期值
     */
    public Date getDateValue() {
        if (value == null) return null;
        if (value instanceof Date) {
            return (Date) value;
        }
        // 可以扩展日期解析逻辑
        return null;
    }
}

4.5.2 使用示例

OguFeature feature = layer.getFeatures().get(0);

// 安全地获取各类型值
String name = feature.getAttribute("NAME").getStringValue();
Integer level = feature.getAttribute("LEVEL").getIntValue();
Double area = feature.getAttribute("AREA").getDoubleValue();
Boolean active = feature.getAttribute("IS_ACTIVE").getBooleanValue();

// 处理可能为null的情况
OguFieldValue areaValue = feature.getAttribute("AREA");
if (areaValue != null && areaValue.getDoubleValue() != null) {
    double area = areaValue.getDoubleValue();
    System.out.println("面积: " + area);
}

// 类型转换
OguFieldValue codeValue = feature.getAttribute("CODE");
// 原始数据可能是整数或字符串
String codeStr = codeValue.getStringValue();  // 转为字符串
Integer codeInt = codeValue.getIntValue();    // 转为整数

4.6 OguCoordinate - 坐标类

4.6.1 类定义

/**
 * 坐标类
 * 支持二维/三维坐标,以及国土TXT格式的点号和圈号
 */
@Data
public class OguCoordinate {
    
    /**
     * X坐标(经度或东坐标)
     */
    private Double x;
    
    /**
     * Y坐标(纬度或北坐标)
     */
    private Double y;
    
    /**
     * Z坐标(高程,可选)
     */
    private Double z;
    
    /**
     * 点号(用于国土TXT格式)
     */
    private String pointNo;
    
    /**
     * 圈号(用于国土TXT格式,区分内外环)
     */
    private Integer ringNo;
    
    // 构造函数
    public OguCoordinate() {}
    
    public OguCoordinate(double x, double y) {
        this.x = x;
        this.y = y;
    }
    
    public OguCoordinate(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

4.6.2 使用场景

主要用于国土TXT格式的界址点管理:

// 创建带点号的坐标
OguCoordinate coord = new OguCoordinate();
coord.setX(500000.123);
coord.setY(4000000.456);
coord.setPointNo("J1");
coord.setRingNo(1);  // 外环

// 批量创建坐标点
List<OguCoordinate> coords = new ArrayList<>();
coords.add(new OguCoordinate(500000.0, 4000000.0) {{ setPointNo("J1"); setRingNo(1); }});
coords.add(new OguCoordinate(500100.0, 4000000.0) {{ setPointNo("J2"); setRingNo(1); }});
coords.add(new OguCoordinate(500100.0, 4000100.0) {{ setPointNo("J3"); setRingNo(1); }});
coords.add(new OguCoordinate(500000.0, 4000100.0) {{ setPointNo("J4"); setRingNo(1); }});
coords.add(new OguCoordinate(500000.0, 4000000.0) {{ setPointNo("J1"); setRingNo(1); }});

feature.setCoordinates(coords);

4.7 OguLayerMetadata - 图层元数据

4.7.1 类定义

/**
 * 图层元数据
 * 存储图层的扩展信息,主要用于国土TXT格式
 */
@Data
public class OguLayerMetadata {
    
    /**
     * 数据来源
     * 例如:"自然资源部"
     */
    private String dataSource;
    
    /**
     * 坐标系名称
     * 例如:"2000国家大地坐标系"
     */
    private String coordinateSystemName;
    
    /**
     * 分带方式
     * 例如:"3" 表示3度分带
     */
    private String zoneDivision;
    
    /**
     * 投影类型
     * 例如:"高斯克吕格"
     */
    private String projectionType;
    
    /**
     * 计量单位
     * 例如:"米"
     */
    private String measureUnit;
    
    /**
     * 扩展信息(自定义)
     */
    private Map<String, Object> extendedInfo;
}

4.7.2 使用示例

// 创建元数据
OguLayerMetadata metadata = new OguLayerMetadata();
metadata.setDataSource("自然资源部");
metadata.setCoordinateSystemName("2000国家大地坐标系");
metadata.setZoneDivision("3");
metadata.setProjectionType("高斯克吕格");
metadata.setMeasureUnit("米");

// 添加扩展信息
Map<String, Object> extInfo = new HashMap<>();
extInfo.put("version", "1.0");
extInfo.put("createDate", "2024-01-01");
extInfo.put("author", "张三");
metadata.setExtendedInfo(extInfo);

// 设置到图层
layer.setMetadata(metadata);

// 保存为国土TXT格式时使用
GtTxtUtil.saveTxt(layer, txtPath, metadata, null, 39);

4.8 OguFeatureFilter - 要素过滤器

4.8.1 接口定义

/**
 * 要素过滤器(函数式接口)
 * 用于过滤图层中的要素
 */
@FunctionalInterface
public interface OguFeatureFilter {
    
    /**
     * 测试要素是否满足条件
     * @param feature 待测试的要素
     * @return true表示保留,false表示过滤掉
     */
    boolean test(OguFeature feature);
}

4.8.2 使用示例

// 使用Lambda表达式
List<OguFeature> result = layer.filter(f -> 
    f.getValue("NAME").toString().contains("市"));

// 使用方法引用
List<OguFeature> result = layer.filter(this::isValid);

private boolean isValid(OguFeature feature) {
    String wkt = feature.getWkt();
    if (wkt == null) return false;
    
    TopologyValidationResult validResult = 
        GeometryUtil.isValid(GeometryUtil.wkt2Geometry(wkt));
    return validResult.isValid();
}

// 组合过滤器
OguFeatureFilter filter1 = f -> f.getAttribute("LEVEL").getIntValue() == 1;
OguFeatureFilter filter2 = f -> f.getAttribute("AREA").getDoubleValue() > 1000;

List<OguFeature> result = layer.filter(f -> filter1.test(f) && filter2.test(f));

4.9 GeometryType - 几何类型枚举

4.9.1 枚举定义

/**
 * 几何类型枚举
 * 定义所有支持的几何类型
 */
public enum GeometryType {
    
    POINT("Point", "点"),
    MULTIPOINT("MultiPoint", "多点"),
    LINESTRING("LineString", "线"),
    MULTILINESTRING("MultiLineString", "多线"),
    POLYGON("Polygon", "面"),
    MULTIPOLYGON("MultiPolygon", "多面"),
    GEOMETRYCOLLECTION("GeometryCollection", "几何集合");
    
    private final String wktName;
    private final String desc;
    
    /**
     * 从WKT几何名称获取枚举
     */
    public static GeometryType fromWktName(String wktName) {
        for (GeometryType type : values()) {
            if (type.wktName.equalsIgnoreCase(wktName)) {
                return type;
            }
        }
        return null;
    }
    
    /**
     * 从JTS Geometry获取类型
     */
    public static GeometryType fromGeometry(Geometry geom) {
        return fromWktName(geom.getGeometryType());
    }
}

4.9.2 使用示例

// 设置图层几何类型
layer.setGeometryType(GeometryType.POLYGON);

// 从WKT判断类型
String wkt = "POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))";
GeometryType type = GeometryType.fromWktName("POLYGON");

// 从Geometry判断类型
Geometry geom = GeometryUtil.wkt2Geometry(wkt);
GeometryType type = GeometryType.fromGeometry(geom);

// 类型判断
if (layer.getGeometryType() == GeometryType.POLYGON || 
    layer.getGeometryType() == GeometryType.MULTIPOLYGON) {
    // 处理面状数据
    processPolygonLayer(layer);
}

4.10 实战案例

4.10.1 创建完整的图层

public class LayerExample {
    
    public static OguLayer createCityLayer() {
        // 1. 创建图层
        OguLayer layer = new OguLayer();
        layer.setName("中国城市");
        layer.setWkid(4490);
        layer.setGeometryType(GeometryType.POINT);
        
        // 2. 定义字段
        List<OguField> fields = new ArrayList<>();
        fields.add(createField("CODE", "城市代码", FieldDataType.STRING, 6));
        fields.add(createField("NAME", "城市名称", FieldDataType.STRING, 50));
        fields.add(createField("PROVINCE", "所属省份", FieldDataType.STRING, 50));
        fields.add(createField("POPULATION", "人口(万)", FieldDataType.INTEGER, null));
        fields.add(createField("GDP", "GDP(亿元)", FieldDataType.DOUBLE, null));
        fields.add(createField("LEVEL", "城市等级", FieldDataType.INTEGER, null));
        layer.setFields(fields);
        
        // 3. 添加要素
        List<OguFeature> features = new ArrayList<>();
        features.add(createCity("1", "110000", "北京", "北京", 2154, 40269.6, 1, 
            "POINT(116.407 39.904)"));
        features.add(createCity("2", "310000", "上海", "上海", 2428, 43214.9, 1, 
            "POINT(121.473 31.230)"));
        features.add(createCity("3", "440100", "广州", "广东", 1881, 28839.0, 2, 
            "POINT(113.264 23.129)"));
        features.add(createCity("4", "440300", "深圳", "广东", 1756, 32387.7, 2, 
            "POINT(114.057 22.543)"));
        layer.setFeatures(features);
        
        // 4. 验证
        layer.validate();
        
        return layer;
    }
    
    private static OguField createField(String name, String alias, 
            FieldDataType dataType, Integer length) {
        OguField field = new OguField();
        field.setName(name);
        field.setAlias(alias);
        field.setDataType(dataType);
        field.setLength(length);
        return field;
    }
    
    private static OguFeature createCity(String fid, String code, String name,
            String province, int population, double gdp, int level, String wkt) {
        OguFeature feature = new OguFeature();
        feature.setFid(fid);
        feature.setWkt(wkt);
        feature.setValue("CODE", code);
        feature.setValue("NAME", name);
        feature.setValue("PROVINCE", province);
        feature.setValue("POPULATION", population);
        feature.setValue("GDP", gdp);
        feature.setValue("LEVEL", level);
        return feature;
    }
}

4.10.2 图层数据分析

public class LayerAnalysis {
    
    public static void analyze(OguLayer layer) {
        System.out.println("=== 图层分析报告 ===");
        System.out.println("图层名称: " + layer.getName());
        System.out.println("坐标系: WKID " + layer.getWkid());
        System.out.println("几何类型: " + layer.getGeometryType());
        System.out.println("要素数量: " + layer.getFeatureCount());
        
        // 字段统计
        System.out.println("\n=== 字段信息 ===");
        for (OguField field : layer.getFields()) {
            System.out.printf("%s (%s) - %s%n",
                field.getName(),
                field.getDataType(),
                field.getAlias());
        }
        
        // 数值字段统计
        System.out.println("\n=== 数值统计 ===");
        for (OguField field : layer.getFields()) {
            if (field.getDataType() == FieldDataType.DOUBLE ||
                field.getDataType() == FieldDataType.INTEGER) {
                DoubleSummaryStatistics stats = layer.getFeatures().stream()
                    .map(f -> f.getAttribute(field.getName()))
                    .filter(v -> v != null && v.getDoubleValue() != null)
                    .mapToDouble(OguFieldValue::getDoubleValue)
                    .summaryStatistics();
                
                System.out.printf("%s: 最小=%.2f, 最大=%.2f, 平均=%.2f, 总和=%.2f%n",
                    field.getName(),
                    stats.getMin(),
                    stats.getMax(),
                    stats.getAverage(),
                    stats.getSum());
            }
        }
        
        // 几何范围
        System.out.println("\n=== 空间范围 ===");
        double minX = Double.MAX_VALUE, minY = Double.MAX_VALUE;
        double maxX = Double.MIN_VALUE, maxY = Double.MIN_VALUE;
        
        for (OguFeature feature : layer.getFeatures()) {
            if (feature.getWkt() != null) {
                Geometry geom = GeometryUtil.wkt2Geometry(feature.getWkt());
                Envelope env = geom.getEnvelopeInternal();
                minX = Math.min(minX, env.getMinX());
                minY = Math.min(minY, env.getMinY());
                maxX = Math.max(maxX, env.getMaxX());
                maxY = Math.max(maxY, env.getMaxY());
            }
        }
        
        System.out.printf("范围: (%.4f, %.4f) - (%.4f, %.4f)%n",
            minX, minY, maxX, maxY);
    }
}

← 上一章:核心架构解析 | 下一章:双引擎架构设计 →

posted @ 2025-12-02 10:30  我才是银古  阅读(5)  评论(0)    收藏  举报