第03章 - 核心架构解析
第03章 - 核心架构解析
3.1 架构概览
3.1.1 分层架构
OGU4Net采用清晰的分层架构设计,自上而下分为四层:
┌─────────────────────────────────────────────────────────────────┐
│ 应用层 (Application) │
│ OguLayerUtil / GtTxtUtil / 业务代码 │
├─────────────────────────────────────────────────────────────────┤
│ 服务层 (Service) │
│ GisEngineFactory / GisEngine │
├─────────────────────────────────────────────────────────────────┤
│ 引擎层 (Engine) │
│ GdalEngine / GdalReader / GdalWriter │
├─────────────────────────────────────────────────────────────────┤
│ 基础层 (Foundation) │
│ MaxRev.Gdal.Universal (GDAL/OGR/OSR) │
└─────────────────────────────────────────────────────────────────┘
3.1.2 核心模块
OGU4Net由以下核心模块组成:
| 模块 | 命名空间 | 职责 |
|---|---|---|
| 配置模块 | Configuration | GDAL初始化和全局配置 |
| 数据源模块 | DataSource | 高层数据读写API |
| 引擎模块 | Engine | GIS引擎核心实现 |
| 模型模块 | Engine.Model | 统一数据模型定义 |
| 几何模块 | Geometry | 几何处理工具 |
| 异常模块 | Exception | 异常类型定义 |
| 工具模块 | Utils | 实用工具类 |
3.1.3 依赖关系图
┌───────────────┐
│ OguLayerUtil │
└───────┬───────┘
│
▼
┌───────────────┐
│GisEngineFactory│
└───────┬───────┘
│
▼
┌───────────────┐
│ GdalEngine │
└───────┬───────┘
│
┌─────────────┴─────────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ GdalReader │ │ GdalWriter │
└───────┬───────┘ └───────┬───────┘
│ │
└─────────────┬─────────────┘
▼
┌───────────────┐
│ GeometryUtil │
│ CrsUtil │
└───────┬───────┘
│
▼
┌─────────────────────────────┐
│ MaxRev.Gdal.Universal │
│ (OSGeo.OGR / OSGeo.OSR) │
└─────────────────────────────┘
3.2 配置模块
3.2.1 GdalConfiguration类
GdalConfiguration 是GDAL配置的核心类,负责初始化GDAL运行环境:
namespace OpenGIS.Utils.Configuration;
public static class GdalConfiguration
{
private static bool _isConfigured;
private static readonly object _lock = new();
/// <summary>
/// 配置GDAL - 线程安全,可多次调用
/// </summary>
public static void ConfigureGdal()
{
lock (_lock)
{
if (_isConfigured) return;
// 使用MaxRev.Gdal.Universal自动配置
GdalBase.ConfigureAll();
// 注册所有驱动
RegisterAllDrivers();
// 设置配置选项
SetConfigOptions();
_isConfigured = true;
}
}
/// <summary>
/// 获取GDAL版本
/// </summary>
public static string GetGdalVersion()
{
EnsureConfigured();
return Gdal.VersionInfo("RELEASE_NAME");
}
/// <summary>
/// 获取支持的驱动列表
/// </summary>
public static IList<string> GetSupportedDrivers()
{
EnsureConfigured();
var drivers = new List<string>();
for (int i = 0; i < Ogr.GetDriverCount(); i++)
{
var driver = Ogr.GetDriver(i);
if (driver != null)
drivers.Add(driver.GetName());
}
return drivers;
}
/// <summary>
/// 检查驱动是否可用
/// </summary>
public static bool IsDriverAvailable(string driverName)
{
EnsureConfigured();
return Ogr.GetDriverByName(driverName) != null;
}
}
设计要点:
- 单例模式:使用静态类确保全局唯一配置
- 线程安全:使用锁机制保证多线程安全
- 延迟初始化:首次使用时自动初始化
- 幂等性:多次调用不会重复初始化
3.2.2 配置选项
GDAL配置选项通过 SetConfigOptions 方法设置:
public static void SetConfigOptions()
{
// 设置文件名为UTF-8编码
Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
// 设置Shapefile默认编码
Gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8");
// 强制使用传统GIS坐标顺序 (longitude, latitude)
Gdal.SetConfigOption("OGR_CT_FORCE_TRADITIONAL_GIS_ORDER", "YES");
// 关闭调试信息
Gdal.SetConfigOption("CPL_DEBUG", "OFF");
}
3.2.3 LibrarySettings类
LibrarySettings 提供库级别的配置常量:
namespace OpenGIS.Utils.Configuration;
public static class LibrarySettings
{
/// <summary>
/// 默认容差值
/// </summary>
public const double DefaultTolerance = 0.001;
/// <summary>
/// 默认缓冲区分段数
/// </summary>
public const int DefaultBufferSegments = 30;
/// <summary>
/// 默认字段长度
/// </summary>
public const int DefaultFieldLength = 254;
}
3.3 引擎模块
3.3.1 引擎抽象设计
OGU4Net使用抽象工厂模式设计引擎层,便于扩展:
namespace OpenGIS.Utils.Engine;
/// <summary>
/// GIS引擎抽象基类
/// </summary>
public abstract class GisEngine
{
/// <summary>
/// 引擎类型
/// </summary>
public abstract GisEngineType EngineType { get; }
/// <summary>
/// 支持的格式列表
/// </summary>
public abstract IList<DataFormatType> SupportedFormats { get; }
/// <summary>
/// 创建读取器
/// </summary>
public abstract ILayerReader CreateReader();
/// <summary>
/// 创建写入器
/// </summary>
public abstract ILayerWriter CreateWriter();
/// <summary>
/// 检查是否支持指定格式
/// </summary>
public virtual bool SupportsFormat(DataFormatType format)
{
return SupportedFormats.Contains(format);
}
}
3.3.2 GisEngineFactory
工厂类负责创建和管理引擎实例:
namespace OpenGIS.Utils.Engine;
public static class GisEngineFactory
{
// 使用单例模式
private static readonly GdalEngine _gdalEngineInstance = new();
/// <summary>
/// 根据引擎类型获取引擎实例
/// </summary>
public static GisEngine GetEngine(GisEngineType engineType)
{
return engineType switch
{
GisEngineType.GDAL => _gdalEngineInstance,
GisEngineType.GEOTOOLS => _gdalEngineInstance, // 兼容性:重定向到GDAL
_ => throw new EngineNotSupportedException($"Engine {engineType} not supported")
};
}
/// <summary>
/// 根据数据格式自动选择引擎
/// </summary>
public static GisEngine GetEngine(DataFormatType format)
{
// 所有格式都使用GDAL引擎
return _gdalEngineInstance;
}
/// <summary>
/// 尝试获取引擎
/// </summary>
public static bool TryGetEngine(DataFormatType format, out GisEngine? engine)
{
engine = _gdalEngineInstance;
return true;
}
}
设计要点:
- 单例引擎:引擎实例全局唯一,避免重复创建
- 自动选择:根据数据格式自动选择合适的引擎
- 向后兼容:GEOTOOLS类型重定向到GDAL
3.3.3 GdalEngine实现
namespace OpenGIS.Utils.Engine;
public class GdalEngine : GisEngine
{
public override GisEngineType EngineType => GisEngineType.GDAL;
public override IList<DataFormatType> SupportedFormats => new List<DataFormatType>
{
DataFormatType.SHP,
DataFormatType.GEOJSON,
DataFormatType.FILEGDB,
DataFormatType.GEOPACKAGE,
DataFormatType.KML,
DataFormatType.DXF,
DataFormatType.POSTGIS
};
public override ILayerReader CreateReader()
{
return new GdalReader();
}
public override ILayerWriter CreateWriter()
{
return new GdalWriter();
}
}
3.4 读写器接口
3.4.1 ILayerReader接口
namespace OpenGIS.Utils.Engine.IO;
public interface ILayerReader
{
/// <summary>
/// 读取图层
/// </summary>
/// <param name="path">数据源路径</param>
/// <param name="layerName">图层名称,null则读取第一个图层</param>
/// <param name="attributeFilter">属性过滤条件(SQL WHERE子句)</param>
/// <param name="spatialFilterWkt">空间过滤几何(WKT格式)</param>
/// <param name="options">附加选项</param>
OguLayer Read(
string path,
string? layerName = null,
string? attributeFilter = null,
string? spatialFilterWkt = null,
Dictionary<string, object>? options = null);
/// <summary>
/// 获取图层名称列表
/// </summary>
IList<string> GetLayerNames(string path);
}
3.4.2 ILayerWriter接口
namespace OpenGIS.Utils.Engine.IO;
public interface ILayerWriter
{
/// <summary>
/// 写入图层
/// </summary>
/// <param name="layer">图层对象</param>
/// <param name="path">输出路径</param>
/// <param name="layerName">图层名称,null则使用layer.Name</param>
/// <param name="options">附加选项</param>
void Write(
OguLayer layer,
string path,
string? layerName = null,
Dictionary<string, object>? options = null);
/// <summary>
/// 追加要素到已存在的图层
/// </summary>
void Append(
OguLayer layer,
string path,
string? layerName = null,
Dictionary<string, object>? options = null);
}
3.4.3 GdalReader实现要点
public class GdalReader : ILayerReader
{
static GdalReader()
{
// 确保GDAL已初始化
GdalConfiguration.ConfigureGdal();
}
public OguLayer Read(string path, string? layerName = null, ...)
{
// 1. 打开数据源
using var dataSource = Ogr.Open(path, 0); // 0 = 只读
// 2. 获取图层
var ogrLayer = layerName != null
? dataSource.GetLayerByName(layerName)
: dataSource.GetLayerByIndex(0);
// 3. 读取并转换
return ReadOgrLayer(ogrLayer, attributeFilter, spatialFilterWkt);
}
private OguLayer ReadOgrLayer(Layer ogrLayer, ...)
{
var layer = new OguLayer { Name = ogrLayer.GetName() };
// 读取字段定义
var layerDefn = ogrLayer.GetLayerDefn();
for (int i = 0; i < layerDefn.GetFieldCount(); i++)
{
var fieldDefn = layerDefn.GetFieldDefn(i);
layer.AddField(new OguField
{
Name = fieldDefn.GetName(),
DataType = MapOgrFieldType(fieldDefn.GetFieldType()),
Length = fieldDefn.GetWidth(),
Precision = fieldDefn.GetPrecision()
});
}
// 读取几何类型
layer.GeometryType = MapOgrGeometryType(ogrLayer.GetGeomType());
// 应用过滤条件
if (!string.IsNullOrWhiteSpace(attributeFilter))
ogrLayer.SetAttributeFilter(attributeFilter);
// 读取要素
int fid = 1;
Feature? ogrFeature;
while ((ogrFeature = ogrLayer.GetNextFeature()) != null)
{
using (ogrFeature)
{
var feature = ReadOgrFeature(ogrFeature, layer.Fields, fid++);
layer.AddFeature(feature);
}
}
return layer;
}
}
关键设计:
- 资源管理:使用using确保DataSource正确释放
- 类型映射:OGR类型到OGU类型的映射
- 过滤支持:属性过滤和空间过滤
- 延迟读取:使用迭代器模式读取要素
3.5 数据源模块
3.5.1 OguLayerUtil设计
OguLayerUtil 是面向应用层的高级API,封装了引擎选择和读写操作:
namespace OpenGIS.Utils.DataSource;
public static class OguLayerUtil
{
/// <summary>
/// 读取图层
/// </summary>
public static OguLayer ReadLayer(
DataFormatType format,
string path,
string? layerName = null,
string? attributeFilter = null,
string? spatialFilterWkt = null,
GisEngineType? engineType = null,
Dictionary<string, object>? options = null)
{
// 参数验证
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException("Path cannot be null or empty", nameof(path));
// 获取引擎
var engine = engineType.HasValue
? GisEngineFactory.GetEngine(engineType.Value)
: GisEngineFactory.GetEngine(format);
// 创建读取器并读取
var reader = engine.CreateReader();
return reader.Read(path, layerName, attributeFilter, spatialFilterWkt, options);
}
/// <summary>
/// 异步读取图层
/// </summary>
public static Task<OguLayer> ReadLayerAsync(...)
{
return Task.Run(() => ReadLayer(...));
}
/// <summary>
/// 写入图层
/// </summary>
public static void WriteLayer(
DataFormatType format,
OguLayer layer,
string path,
string? layerName = null,
GisEngineType? engineType = null,
Dictionary<string, object>? options = null)
{
// 参数验证
if (layer == null)
throw new ArgumentNullException(nameof(layer));
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException("Path cannot be null or empty", nameof(path));
// 获取引擎
var engine = engineType.HasValue
? GisEngineFactory.GetEngine(engineType.Value)
: GisEngineFactory.GetEngine(format);
// 创建写入器并写入
var writer = engine.CreateWriter();
writer.Write(layer, path, layerName, options);
}
/// <summary>
/// 格式转换
/// </summary>
public static void ConvertFormat(
string inputPath,
DataFormatType inputFormat,
string outputPath,
DataFormatType outputFormat,
GisEngineType? engineType = null,
string? layerName = null)
{
// 读取
var layer = ReadLayer(inputFormat, inputPath, layerName, engineType: engineType);
// 写入
WriteLayer(outputFormat, layer, outputPath, layerName, engineType);
}
}
设计特点:
- 静态工具类:无状态,线程安全
- 参数灵活:支持可选参数,简化常见用法
- 异步支持:提供异步版本方法
- 格式转换:一键实现格式转换
3.6 类型映射系统
3.6.1 几何类型映射
// OGR几何类型 → OGU几何类型
private GeometryType MapOgrGeometryType(wkbGeometryType geomType)
{
// 移除Z/M维度标志
var flatType = wkbFlatten((int)geomType);
return flatType switch
{
wkbGeometryType.wkbPoint => GeometryType.POINT,
wkbGeometryType.wkbLineString => GeometryType.LINESTRING,
wkbGeometryType.wkbPolygon => GeometryType.POLYGON,
wkbGeometryType.wkbMultiPoint => GeometryType.MULTIPOINT,
wkbGeometryType.wkbMultiLineString => GeometryType.MULTILINESTRING,
wkbGeometryType.wkbMultiPolygon => GeometryType.MULTIPOLYGON,
wkbGeometryType.wkbGeometryCollection => GeometryType.GEOMETRYCOLLECTION,
_ => GeometryType.UNKNOWN
};
}
// OGU几何类型 → OGR几何类型
private wkbGeometryType MapToOgrGeometryType(GeometryType geomType)
{
return geomType switch
{
GeometryType.POINT => wkbGeometryType.wkbPoint,
GeometryType.LINESTRING => wkbGeometryType.wkbLineString,
GeometryType.POLYGON => wkbGeometryType.wkbPolygon,
GeometryType.MULTIPOINT => wkbGeometryType.wkbMultiPoint,
GeometryType.MULTILINESTRING => wkbGeometryType.wkbMultiLineString,
GeometryType.MULTIPOLYGON => wkbGeometryType.wkbMultiPolygon,
GeometryType.GEOMETRYCOLLECTION => wkbGeometryType.wkbGeometryCollection,
_ => wkbGeometryType.wkbUnknown
};
}
3.6.2 字段类型映射
// OGR字段类型 → OGU字段类型
private FieldDataType MapOgrFieldType(FieldType ogrType)
{
return ogrType switch
{
FieldType.OFTInteger => FieldDataType.INTEGER,
FieldType.OFTInteger64 => FieldDataType.LONG,
FieldType.OFTReal => FieldDataType.DOUBLE,
FieldType.OFTString => FieldDataType.STRING,
FieldType.OFTDate => FieldDataType.DATE,
FieldType.OFTDateTime => FieldDataType.DATETIME,
FieldType.OFTBinary => FieldDataType.BINARY,
_ => FieldDataType.STRING // 默认为字符串
};
}
// OGU字段类型 → OGR字段类型
private FieldType MapToOgrFieldType(FieldDataType dataType)
{
return dataType switch
{
FieldDataType.INTEGER => FieldType.OFTInteger,
FieldDataType.LONG => FieldType.OFTInteger64,
FieldDataType.DOUBLE => FieldType.OFTReal,
FieldDataType.FLOAT => FieldType.OFTReal,
FieldDataType.STRING => FieldType.OFTString,
FieldDataType.DATE => FieldType.OFTDate,
FieldDataType.DATETIME => FieldType.OFTDateTime,
FieldDataType.BINARY => FieldType.OFTBinary,
_ => FieldType.OFTString
};
}
3.6.3 驱动名称推断
private string InferDriverName(string path, Dictionary<string, object>? options)
{
// 优先从选项中获取
if (options?.TryGetValue("driver", out var driverObj) == true)
return driverObj.ToString() ?? "ESRI Shapefile";
// 根据扩展名推断
var extension = Path.GetExtension(path).ToLowerInvariant();
return extension switch
{
".shp" => "ESRI Shapefile",
".gdb" => "FileGDB",
".gpkg" => "GPKG",
".kml" => "KML",
".dxf" => "DXF",
".geojson" or ".json" => "GeoJSON",
_ => "ESRI Shapefile" // 默认
};
}
3.7 资源管理
3.7.1 GDAL对象生命周期
GDAL/OGR对象需要正确管理以避免内存泄漏:
// 正确的资源管理方式
public OguLayer Read(string path, ...)
{
OgrDataSource? dataSource = null;
try
{
dataSource = Ogr.Open(path, 0);
if (dataSource == null)
throw new DataSourceException($"Failed to open: {path}");
// 处理逻辑...
return layer;
}
finally
{
dataSource?.Dispose();
}
}
3.7.2 要素迭代模式
// 逐个处理要素,及时释放资源
Feature? ogrFeature;
while ((ogrFeature = ogrLayer.GetNextFeature()) != null)
{
using (ogrFeature) // 确保每个要素都被释放
{
var feature = ConvertFeature(ogrFeature);
layer.AddFeature(feature);
}
}
3.7.3 几何对象管理
public void Write(OguLayer layer, string path, ...)
{
foreach (var oguFeature in layer.Features)
{
Feature? ogrFeature = null;
OSGeo.OGR.Geometry? geometry = null;
try
{
ogrFeature = new Feature(layerDefn);
// 创建几何(需要单独管理)
geometry = OSGeo.OGR.Geometry.CreateFromWkt(oguFeature.Wkt);
if (geometry != null)
ogrFeature.SetGeometry(geometry);
// 写入要素
ogrLayer.CreateFeature(ogrFeature);
}
finally
{
geometry?.Dispose(); // 先释放几何
ogrFeature?.Dispose(); // 再释放要素
}
}
}
3.8 扩展点设计
3.8.1 添加新引擎
如需添加新的GIS引擎,可以:
- 继承
GisEngine抽象类 - 实现
ILayerReader和ILayerWriter接口 - 在
GisEngineFactory中注册
// 示例:添加新引擎
public class MyCustomEngine : GisEngine
{
public override GisEngineType EngineType => GisEngineType.CUSTOM;
public override IList<DataFormatType> SupportedFormats =>
new List<DataFormatType> { DataFormatType.CUSTOM };
public override ILayerReader CreateReader() => new MyCustomReader();
public override ILayerWriter CreateWriter() => new MyCustomWriter();
}
3.8.2 添加新数据格式
添加新格式支持:
- 在
DataFormatType枚举中添加新类型 - 在驱动名称推断逻辑中添加映射
- 确保GDAL支持该格式的驱动
3.9 小结
本章详细解析了OGU4Net的核心架构:
- 分层架构:应用层、服务层、引擎层、基础层清晰分离
- 配置模块:线程安全的GDAL初始化和配置管理
- 引擎模块:抽象工厂模式,支持扩展
- 读写器设计:接口驱动,职责单一
- 类型映射:OGR与OGU类型的双向映射
- 资源管理:正确管理GDAL对象生命周期
理解这些架构设计,有助于更好地使用和扩展OGU4Net框架。

浙公网安备 33010602011771号