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

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

4.1 模型体系概述

4.1.1 模型层次结构

OGU4Net定义了一套简洁而完整的GIS数据模型体系:

OguLayer (图层)
    ├── Fields: IList<OguField> (字段定义列表)
    ├── Features: IList<OguFeature> (要素列表)
    └── Metadata: OguLayerMetadata? (图层元数据)

OguFeature (要素)
    ├── Fid: int (要素ID)
    ├── Wkt: string? (几何信息,WKT格式)
    └── Attributes: Dictionary<string, OguFieldValue> (属性值)

OguField (字段定义)
    ├── Name: string (字段名)
    ├── Alias: string? (别名)
    ├── DataType: FieldDataType (数据类型)
    ├── Length: int? (字段长度)
    ├── Precision: int? (精度)
    ├── Scale: int? (小数位数)
    ├── IsNullable: bool (是否可空)
    └── DefaultValue: object? (默认值)

OguFieldValue (字段值)
    └── Value: object? (原始值)
    + 类型安全的转换方法

4.1.2 设计原则

  1. 独立性:模型不依赖任何底层GIS库
  2. 序列化友好:支持JSON序列化/反序列化
  3. 类型安全:OguFieldValue提供类型安全的访问方法
  4. 可验证:内置数据完整性验证
  5. 可克隆:支持深拷贝操作

4.2 OguLayer类详解

4.2.1 类定义

namespace OpenGIS.Utils.Engine.Model.Layer;

/// <summary>
/// 统一的GIS图层定义类
/// </summary>
public class OguLayer
{
    /// <summary>
    /// 图层名称
    /// </summary>
    public string Name { get; set; } = string.Empty;
    
    /// <summary>
    /// 坐标系WKID (Well-Known ID)
    /// </summary>
    public int? Wkid { get; set; }
    
    /// <summary>
    /// 几何类型
    /// </summary>
    public GeometryType GeometryType { get; set; }
    
    /// <summary>
    /// 字段定义列表
    /// </summary>
    public IList<OguField> Fields { get; set; }
    
    /// <summary>
    /// 要素集合
    /// </summary>
    public IList<OguFeature> Features { get; set; }
    
    /// <summary>
    /// 图层元数据
    /// </summary>
    public OguLayerMetadata? Metadata { get; set; }
    
    public OguLayer()
    {
        Fields = new List<OguField>();
        Features = new List<OguFeature>();
    }
}

4.2.2 核心方法

添加字段:

/// <summary>
/// 添加字段
/// </summary>
/// <exception cref="LayerValidationException">字段名重复时抛出</exception>
public void AddField(OguField field)
{
    if (Fields.Any(f => f.Name == field.Name))
        throw new LayerValidationException($"Field '{field.Name}' already exists");
    Fields.Add(field);
}

// 使用示例
layer.AddField(new OguField
{
    Name = "ID",
    DataType = FieldDataType.INTEGER
});

layer.AddField(new OguField
{
    Name = "Name",
    DataType = FieldDataType.STRING,
    Length = 100,
    IsNullable = false
});

获取字段:

/// <summary>
/// 根据字段名获取字段定义
/// </summary>
public OguField? GetField(string fieldName)
{
    return Fields.FirstOrDefault(f => f.Name == fieldName);
}

// 使用示例
var idField = layer.GetField("ID");
if (idField != null)
{
    Console.WriteLine($"ID字段类型: {idField.DataType}");
}

添加/移除要素:

/// <summary>
/// 添加要素
/// </summary>
public void AddFeature(OguFeature feature)
{
    Features.Add(feature);
}

/// <summary>
/// 移除要素
/// </summary>
/// <returns>是否成功移除</returns>
public bool RemoveFeature(int fid)
{
    var feature = Features.FirstOrDefault(f => f.Fid == fid);
    if (feature != null)
    {
        Features.Remove(feature);
        return true;
    }
    return false;
}

// 使用示例
var feature = new OguFeature { Fid = 1, Wkt = "POINT (0 0)" };
layer.AddFeature(feature);
layer.RemoveFeature(1);

过滤要素:

/// <summary>
/// 过滤要素
/// </summary>
public IList<OguFeature> Filter(Func<OguFeature, bool> filter)
{
    return Features.Where(filter).ToList();
}

// 使用示例:查找人口超过1000万的城市
var bigCities = layer.Filter(f => 
{
    var pop = f.GetAttribute("Population")?.GetLongValue();
    return pop.HasValue && pop.Value > 10000000;
});

4.2.3 验证机制

/// <summary>
/// 验证图层数据完整性
/// </summary>
/// <exception cref="LayerValidationException">验证失败时抛出</exception>
public void Validate()
{
    // 1. 验证图层名称
    if (string.IsNullOrWhiteSpace(Name))
        throw new LayerValidationException("Layer name cannot be null or empty");
    
    // 2. 验证必须有字段
    if (Fields == null || Fields.Count == 0)
        throw new LayerValidationException("Layer must have at least one field");
    
    // 3. 验证字段名唯一性
    var fieldNameSet = new HashSet<string>();
    foreach (var field in Fields)
    {
        if (!fieldNameSet.Add(field.Name))
            throw new LayerValidationException($"Field name '{field.Name}' is duplicated");
    }
    
    // 4. 验证要素属性与字段定义一致
    foreach (var feature in Features)
    {
        foreach (var fieldName in feature.Attributes.Keys)
        {
            if (!fieldNameSet.Contains(fieldName))
                throw new LayerValidationException(
                    $"Feature contains attribute '{fieldName}' not defined in Fields");
        }
    }
}

// 使用示例
try
{
    layer.Validate();
    Console.WriteLine("Layer validation passed");
}
catch (LayerValidationException ex)
{
    Console.WriteLine($"Validation failed: {ex.Message}");
}

4.2.4 序列化支持

/// <summary>
/// 转换为JSON字符串
/// </summary>
public string ToJson()
{
    return JsonSerializer.Serialize(this, new JsonSerializerOptions 
    { 
        WriteIndented = true 
    });
}

/// <summary>
/// 从JSON创建图层
/// </summary>
public static OguLayer? FromJson(string json)
{
    return JsonSerializer.Deserialize<OguLayer>(json);
}

// 使用示例
string json = layer.ToJson();
Console.WriteLine(json);

OguLayer? restored = OguLayer.FromJson(json);

4.2.5 深拷贝

/// <summary>
/// 深拷贝
/// </summary>
public OguLayer Clone()
{
    var clone = new OguLayer
    {
        Name = Name,
        Wkid = Wkid,
        GeometryType = GeometryType
    };
    
    // 复制字段
    foreach (var field in Fields)
        clone.Fields.Add(field.Clone());
    
    // 复制要素
    foreach (var feature in Features)
        clone.Features.Add(feature.Clone());
    
    // 复制元数据
    if (Metadata != null)
    {
        clone.Metadata = new OguLayerMetadata
        {
            DataSource = Metadata.DataSource,
            CoordinateSystemName = Metadata.CoordinateSystemName,
            ZoneDivision = Metadata.ZoneDivision,
            ProjectionType = Metadata.ProjectionType,
            MeasureUnit = Metadata.MeasureUnit,
            CreateTime = Metadata.CreateTime,
            ModifyTime = Metadata.ModifyTime
        };
        
        foreach (var kvp in Metadata.ExtendedProperties)
            clone.Metadata.ExtendedProperties[kvp.Key] = kvp.Value;
    }
    
    return clone;
}

4.3 OguFeature类详解

4.3.1 类定义

namespace OpenGIS.Utils.Engine.Model.Layer;

/// <summary>
/// 统一的要素类
/// </summary>
public class OguFeature
{
    /// <summary>
    /// 要素ID
    /// </summary>
    public int Fid { get; set; }
    
    /// <summary>
    /// 几何信息(WKT格式)
    /// </summary>
    public string? Wkt { get; set; }
    
    /// <summary>
    /// 属性值字典
    /// </summary>
    public Dictionary<string, OguFieldValue> Attributes { get; set; }
    
    public OguFeature()
    {
        Attributes = new Dictionary<string, OguFieldValue>();
    }
}

4.3.2 属性操作

设置属性值:

/// <summary>
/// 设置属性值
/// </summary>
public void SetValue(string fieldName, object? value)
{
    if (Attributes.TryGetValue(fieldName, out var fieldValue))
        fieldValue.Value = value;
    else
        Attributes[fieldName] = new OguFieldValue(value);
}

// 使用示例
feature.SetValue("ID", 1);
feature.SetValue("Name", "北京");
feature.SetValue("Population", 21540000L);
feature.SetValue("Area", 16410.54);
feature.SetValue("CreateDate", DateTime.Now);

获取属性值:

/// <summary>
/// 获取属性原始值
/// </summary>
public object? GetValue(string fieldName)
{
    return Attributes.TryGetValue(fieldName, out var fieldValue) 
        ? fieldValue.Value 
        : null;
}

/// <summary>
/// 获取字段值对象
/// </summary>
public OguFieldValue? GetAttribute(string fieldName)
{
    return Attributes.TryGetValue(fieldName, out var fieldValue) 
        ? fieldValue 
        : null;
}

/// <summary>
/// 判断是否存在属性
/// </summary>
public bool HasAttribute(string fieldName)
{
    return Attributes.ContainsKey(fieldName);
}

// 使用示例
var name = feature.GetValue("Name");
Console.WriteLine($"城市名: {name}");

var popAttr = feature.GetAttribute("Population");
if (popAttr != null && !popAttr.IsNull)
{
    long? pop = popAttr.GetLongValue();
    Console.WriteLine($"人口: {pop:N0}");
}

if (feature.HasAttribute("Area"))
{
    Console.WriteLine("存在面积字段");
}

4.3.3 完整使用示例

// 创建要素
var feature = new OguFeature
{
    Fid = 1,
    Wkt = "POLYGON ((116.3 39.9, 116.5 39.9, 116.5 40.0, 116.3 40.0, 116.3 39.9))"
};

// 设置各类型属性
feature.SetValue("ID", 1);
feature.SetValue("Name", "北京朝阳区");
feature.SetValue("Population", 3650000L);
feature.SetValue("Area", 470.8);
feature.SetValue("IsCapital", true);
feature.SetValue("CreateTime", new DateTime(2024, 1, 1));

// 类型安全地获取属性
var popAttr = feature.GetAttribute("Population");
long population = popAttr?.GetLongValue() ?? 0;

var areaAttr = feature.GetAttribute("Area");
double area = areaAttr?.GetDoubleValue() ?? 0;

var isCapitalAttr = feature.GetAttribute("IsCapital");
bool isCapital = isCapitalAttr?.GetBoolValue() ?? false;

var timeAttr = feature.GetAttribute("CreateTime");
DateTime? createTime = timeAttr?.GetDateTimeValue();

Console.WriteLine($"人口: {population:N0}");
Console.WriteLine($"面积: {area:F2} 平方公里");
Console.WriteLine($"是否首都: {isCapital}");
Console.WriteLine($"创建时间: {createTime:yyyy-MM-dd}");

4.4 OguField类详解

4.4.1 类定义

namespace OpenGIS.Utils.Engine.Model.Layer;

/// <summary>
/// 统一的字段定义类
/// </summary>
public class OguField
{
    /// <summary>
    /// 字段名称
    /// </summary>
    public string Name { get; set; } = string.Empty;
    
    /// <summary>
    /// 字段别名
    /// </summary>
    public string? Alias { get; set; }
    
    /// <summary>
    /// 数据类型
    /// </summary>
    public FieldDataType DataType { get; set; }
    
    /// <summary>
    /// 字段长度(字符串类型)
    /// </summary>
    public int? Length { get; set; }
    
    /// <summary>
    /// 精度(数字类型总位数)
    /// </summary>
    public int? Precision { get; set; }
    
    /// <summary>
    /// 小数位数(数字类型)
    /// </summary>
    public int? Scale { get; set; }
    
    /// <summary>
    /// 是否可为空
    /// </summary>
    public bool IsNullable { get; set; } = true;
    
    /// <summary>
    /// 默认值
    /// </summary>
    public object? DefaultValue { get; set; }
}

4.4.2 字段数据类型

namespace OpenGIS.Utils.Engine.Enums;

/// <summary>
/// 字段数据类型枚举
/// </summary>
public enum FieldDataType
{
    STRING,      // 字符串
    INTEGER,     // 32位整数
    LONG,        // 64位整数
    DOUBLE,      // 双精度浮点
    FLOAT,       // 单精度浮点
    BOOLEAN,     // 布尔值
    DATE,        // 日期
    DATETIME,    // 日期时间
    BINARY,      // 二进制
    UNKNOWN      // 未知类型
}

4.4.3 创建各类型字段

// 整数字段
var idField = new OguField
{
    Name = "ID",
    DataType = FieldDataType.INTEGER,
    IsNullable = false
};

// 字符串字段(指定长度)
var nameField = new OguField
{
    Name = "Name",
    Alias = "名称",
    DataType = FieldDataType.STRING,
    Length = 100,
    IsNullable = false,
    DefaultValue = "未命名"
};

// 长整数字段
var populationField = new OguField
{
    Name = "Population",
    Alias = "人口",
    DataType = FieldDataType.LONG
};

// 双精度浮点字段(指定精度)
var areaField = new OguField
{
    Name = "Area",
    Alias = "面积",
    DataType = FieldDataType.DOUBLE,
    Precision = 15,
    Scale = 4
};

// 日期时间字段
var createTimeField = new OguField
{
    Name = "CreateTime",
    Alias = "创建时间",
    DataType = FieldDataType.DATETIME,
    DefaultValue = DateTime.Now
};

// 布尔字段
var isActiveField = new OguField
{
    Name = "IsActive",
    Alias = "是否激活",
    DataType = FieldDataType.BOOLEAN,
    DefaultValue = true
};

4.5 OguFieldValue类详解

4.5.1 类定义

namespace OpenGIS.Utils.Engine.Model.Layer;

/// <summary>
/// 字段值容器,提供类型安全的转换方法
/// </summary>
public class OguFieldValue
{
    /// <summary>
    /// 原始值
    /// </summary>
    public object? Value { get; set; }
    
    /// <summary>
    /// 是否为空
    /// </summary>
    public bool IsNull => Value == null;
    
    public OguFieldValue() { }
    
    public OguFieldValue(object? value)
    {
        Value = value;
    }
}

4.5.2 类型转换方法

/// <summary>
/// 转为字符串
/// </summary>
public string? GetStringValue()
{
    return Value?.ToString();
}

/// <summary>
/// 转为整数
/// </summary>
public int? GetIntValue()
{
    if (IsNull) return null;
    if (Value is int i) return i;
    if (int.TryParse(Value?.ToString(), out int result))
        return result;
    return null;
}

/// <summary>
/// 转为长整数
/// </summary>
public long? GetLongValue()
{
    if (IsNull) return null;
    if (Value is long l) return l;
    if (long.TryParse(Value?.ToString(), out long result))
        return result;
    return null;
}

/// <summary>
/// 转为双精度浮点
/// </summary>
public double? GetDoubleValue()
{
    if (IsNull) return null;
    if (Value is double d) return d;
    if (double.TryParse(Value?.ToString(), out double result))
        return result;
    return null;
}

/// <summary>
/// 转为单精度浮点
/// </summary>
public float? GetFloatValue()
{
    if (IsNull) return null;
    if (Value is float f) return f;
    if (float.TryParse(Value?.ToString(), out float result))
        return result;
    return null;
}

/// <summary>
/// 转为布尔值
/// </summary>
public bool? GetBoolValue()
{
    if (IsNull) return null;
    if (Value is bool b) return b;
    if (bool.TryParse(Value?.ToString(), out bool result))
        return result;
    return null;
}

/// <summary>
/// 转为日期时间
/// </summary>
public DateTime? GetDateTimeValue()
{
    if (IsNull) return null;
    if (Value is DateTime dt) return dt;
    if (DateTime.TryParse(Value?.ToString(), out DateTime result))
        return result;
    return null;
}

/// <summary>
/// 转为Decimal
/// </summary>
public decimal? GetDecimalValue()
{
    if (IsNull) return null;
    if (Value is decimal dec) return dec;
    if (decimal.TryParse(Value?.ToString(), out decimal result))
        return result;
    return null;
}

4.5.3 类型转换示例

// 创建要素并设置属性
var feature = new OguFeature { Fid = 1 };
feature.SetValue("IntValue", 42);
feature.SetValue("StringValue", "Hello");
feature.SetValue("DoubleValue", 3.14159);
feature.SetValue("DateValue", DateTime.Now);
feature.SetValue("BoolValue", true);
feature.SetValue("NullValue", null);

// 类型安全的转换
var intAttr = feature.GetAttribute("IntValue");
int? intVal = intAttr?.GetIntValue();           // 42
string? strVal = intAttr?.GetStringValue();     // "42"

var doubleAttr = feature.GetAttribute("DoubleValue");
double? doubleVal = doubleAttr?.GetDoubleValue(); // 3.14159
int? intFromDouble = doubleAttr?.GetIntValue();   // null (转换失败)

var nullAttr = feature.GetAttribute("NullValue");
bool isNull = nullAttr?.IsNull ?? true;           // true
string? nullStr = nullAttr?.GetStringValue();     // null

// 安全获取值(带默认值)
long population = feature.GetAttribute("Population")?.GetLongValue() ?? 0;
string name = feature.GetAttribute("Name")?.GetStringValue() ?? "未知";
double area = feature.GetAttribute("Area")?.GetDoubleValue() ?? 0.0;

4.6 OguCoordinate类

4.6.1 类定义

namespace OpenGIS.Utils.Engine.Model.Layer;

/// <summary>
/// 坐标点类(支持2D/3D)
/// </summary>
public class OguCoordinate
{
    /// <summary>
    /// X坐标(经度)
    /// </summary>
    public double X { get; set; }
    
    /// <summary>
    /// Y坐标(纬度)
    /// </summary>
    public double Y { get; set; }
    
    /// <summary>
    /// Z坐标(高程,可选)
    /// </summary>
    public double? Z { get; set; }
    
    /// <summary>
    /// 点号(用于TXT格式)
    /// </summary>
    public string? PointNumber { get; set; }
    
    /// <summary>
    /// 圈号(用于TXT格式)
    /// </summary>
    public string? RingNumber { get; set; }
    
    /// <summary>
    /// 备注
    /// </summary>
    public string? Remark { get; set; }
}

4.6.2 WKT转换

/// <summary>
/// 转换为WKT
/// </summary>
public string ToWkt()
{
    if (Z.HasValue)
        return $"POINT Z ({X} {Y} {Z.Value})";
    return $"POINT ({X} {Y})";
}

/// <summary>
/// 从WKT创建
/// </summary>
public static OguCoordinate FromWkt(string wkt)
{
    // 解析 POINT (x y) 或 POINT Z (x y z) 格式
    var match = Regex.Match(wkt, @"POINT\s*Z?\s*\(\s*([\d.-]+)\s+([\d.-]+)\s*([\d.-]+)?\s*\)");
    if (!match.Success)
        throw new FormatException($"Invalid WKT: {wkt}");
    
    var coord = new OguCoordinate
    {
        X = double.Parse(match.Groups[1].Value),
        Y = double.Parse(match.Groups[2].Value)
    };
    
    if (!string.IsNullOrEmpty(match.Groups[3].Value))
        coord.Z = double.Parse(match.Groups[3].Value);
    
    return coord;
}

4.6.3 使用示例

// 创建2D坐标
var coord2d = new OguCoordinate
{
    X = 116.404,
    Y = 39.915
};
Console.WriteLine(coord2d.ToWkt()); // POINT (116.404 39.915)

// 创建3D坐标
var coord3d = new OguCoordinate
{
    X = 116.404,
    Y = 39.915,
    Z = 50.5
};
Console.WriteLine(coord3d.ToWkt()); // POINT Z (116.404 39.915 50.5)

// 创建带点号的坐标(用于国土TXT)
var coordWithNumber = new OguCoordinate
{
    X = 456789.123,
    Y = 4321098.456,
    PointNumber = "J1",
    RingNumber = "1",
    Remark = "界址点1"
};

// 从WKT创建
var fromWkt = OguCoordinate.FromWkt("POINT (116.404 39.915)");
Console.WriteLine($"X: {fromWkt.X}, Y: {fromWkt.Y}");

4.7 OguLayerMetadata类

4.7.1 类定义

namespace OpenGIS.Utils.Engine.Model.Layer;

/// <summary>
/// 图层元数据
/// </summary>
public class OguLayerMetadata
{
    /// <summary>
    /// 数据来源
    /// </summary>
    public string? DataSource { get; set; }
    
    /// <summary>
    /// 坐标系名称
    /// </summary>
    public string? CoordinateSystemName { get; set; }
    
    /// <summary>
    /// 分带方式(3度带/6度带)
    /// </summary>
    public string? ZoneDivision { get; set; }
    
    /// <summary>
    /// 投影类型
    /// </summary>
    public string? ProjectionType { get; set; }
    
    /// <summary>
    /// 计量单位
    /// </summary>
    public string? MeasureUnit { get; set; }
    
    /// <summary>
    /// 创建时间
    /// </summary>
    public DateTime? CreateTime { get; set; }
    
    /// <summary>
    /// 修改时间
    /// </summary>
    public DateTime? ModifyTime { get; set; }
    
    /// <summary>
    /// 扩展属性
    /// </summary>
    public Dictionary<string, object> ExtendedProperties { get; set; } 
        = new Dictionary<string, object>();
}

4.7.2 使用示例

// 创建元数据
var metadata = new OguLayerMetadata
{
    DataSource = "自然资源部",
    CoordinateSystemName = "CGCS2000 / 3-degree Gauss-Kruger zone 39",
    ZoneDivision = "3度带",
    ProjectionType = "高斯-克吕格投影",
    MeasureUnit = "米",
    CreateTime = DateTime.Now
};

// 添加扩展属性
metadata.ExtendedProperties["Author"] = "张三";
metadata.ExtendedProperties["Version"] = "1.0";
metadata.ExtendedProperties["Quality"] = "A级";

// 关联到图层
layer.Metadata = metadata;

// 读取元数据
if (layer.Metadata != null)
{
    Console.WriteLine($"数据来源: {layer.Metadata.DataSource}");
    Console.WriteLine($"坐标系: {layer.Metadata.CoordinateSystemName}");
    
    if (layer.Metadata.ExtendedProperties.TryGetValue("Author", out var author))
    {
        Console.WriteLine($"作者: {author}");
    }
}

4.8 几何类型枚举

4.8.1 GeometryType定义

namespace OpenGIS.Utils.Engine.Enums;

/// <summary>
/// 几何类型枚举
/// </summary>
public enum GeometryType
{
    POINT,              // 点
    LINESTRING,         // 线
    POLYGON,            // 面
    MULTIPOINT,         // 多点
    MULTILINESTRING,    // 多线
    MULTIPOLYGON,       // 多面
    GEOMETRYCOLLECTION, // 几何集合
    UNKNOWN             // 未知类型
}

4.8.2 几何类型与WKT

GeometryType WKT示例
POINT POINT (0 0)
LINESTRING LINESTRING (0 0, 1 1, 2 0)
POLYGON POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))
MULTIPOINT MULTIPOINT ((0 0), (1 1))
MULTILINESTRING MULTILINESTRING ((0 0, 1 1), (2 2, 3 3))
MULTIPOLYGON MULTIPOLYGON (((0 0, 1 0, 1 1, 0 1, 0 0)))

4.9 实战示例

4.9.1 创建完整图层

using OpenGIS.Utils.Engine.Enums;
using OpenGIS.Utils.Engine.Model.Layer;

// 创建城市图层
var cityLayer = new OguLayer
{
    Name = "中国主要城市",
    GeometryType = GeometryType.POINT,
    Wkid = 4326
};

// 添加字段定义
cityLayer.AddField(new OguField
{
    Name = "ID",
    DataType = FieldDataType.INTEGER,
    IsNullable = false
});

cityLayer.AddField(new OguField
{
    Name = "Name",
    Alias = "城市名称",
    DataType = FieldDataType.STRING,
    Length = 50,
    IsNullable = false
});

cityLayer.AddField(new OguField
{
    Name = "Province",
    Alias = "所属省份",
    DataType = FieldDataType.STRING,
    Length = 50
});

cityLayer.AddField(new OguField
{
    Name = "Population",
    Alias = "人口(万)",
    DataType = FieldDataType.LONG
});

cityLayer.AddField(new OguField
{
    Name = "GDP",
    Alias = "GDP(亿元)",
    DataType = FieldDataType.DOUBLE,
    Precision = 15,
    Scale = 2
});

// 添加北京
var beijing = new OguFeature
{
    Fid = 1,
    Wkt = "POINT (116.404 39.915)"
};
beijing.SetValue("ID", 1);
beijing.SetValue("Name", "北京");
beijing.SetValue("Province", "北京市");
beijing.SetValue("Population", 2154L);
beijing.SetValue("GDP", 40269.6);
cityLayer.AddFeature(beijing);

// 添加上海
var shanghai = new OguFeature
{
    Fid = 2,
    Wkt = "POINT (121.473 31.230)"
};
shanghai.SetValue("ID", 2);
shanghai.SetValue("Name", "上海");
shanghai.SetValue("Province", "上海市");
shanghai.SetValue("Population", 2487L);
shanghai.SetValue("GDP", 43214.85);
cityLayer.AddFeature(shanghai);

// 添加广州
var guangzhou = new OguFeature
{
    Fid = 3,
    Wkt = "POINT (113.264 23.129)"
};
guangzhou.SetValue("ID", 3);
guangzhou.SetValue("Name", "广州");
guangzhou.SetValue("Province", "广东省");
guangzhou.SetValue("Population", 1867L);
guangzhou.SetValue("GDP", 28839.0);
cityLayer.AddFeature(guangzhou);

// 添加元数据
cityLayer.Metadata = new OguLayerMetadata
{
    DataSource = "国家统计局",
    CoordinateSystemName = "WGS 84",
    MeasureUnit = "度",
    CreateTime = DateTime.Now
};

// 验证图层
cityLayer.Validate();

Console.WriteLine($"图层创建完成: {cityLayer.Name}");
Console.WriteLine($"要素数量: {cityLayer.GetFeatureCount()}");

4.9.2 遍历和查询

// 遍历所有要素
Console.WriteLine("\n所有城市:");
foreach (var feature in cityLayer.Features)
{
    var name = feature.GetValue("Name");
    var pop = feature.GetAttribute("Population")?.GetLongValue();
    var gdp = feature.GetAttribute("GDP")?.GetDoubleValue();
    
    Console.WriteLine($"  {name}: 人口 {pop}万, GDP {gdp:N2}亿元");
}

// 查询GDP超过30000亿的城市
Console.WriteLine("\nGDP超过30000亿的城市:");
var richCities = cityLayer.Filter(f =>
{
    var gdp = f.GetAttribute("GDP")?.GetDoubleValue();
    return gdp.HasValue && gdp.Value > 30000;
});

foreach (var city in richCities)
{
    Console.WriteLine($"  {city.GetValue("Name")}");
}

// 按人口排序
Console.WriteLine("\n按人口排序:");
var sortedByPop = cityLayer.Features
    .OrderByDescending(f => f.GetAttribute("Population")?.GetLongValue() ?? 0)
    .ToList();

foreach (var city in sortedByPop)
{
    var name = city.GetValue("Name");
    var pop = city.GetAttribute("Population")?.GetLongValue();
    Console.WriteLine($"  {name}: {pop}万人");
}

4.10 小结

本章详细介绍了OGU4Net的统一图层模型:

  1. OguLayer:图层容器,包含字段定义、要素集合、元数据
  2. OguFeature:要素类,包含几何(WKT)和属性
  3. OguField:字段定义,支持多种数据类型
  4. OguFieldValue:类型安全的字段值容器
  5. OguCoordinate:坐标点,支持2D/3D和点号
  6. OguLayerMetadata:图层元数据

这套模型的优势:

  • 独立于底层GIS库
  • 支持JSON序列化
  • 类型安全
  • 可验证
  • 可克隆

掌握这些核心模型,是使用OGU4Net进行GIS开发的基础。

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