| name | opengis-utils-for-net |
| description | opengis-utils-for-net 是一个基于 GDAL/OGR 的 .NET GIS 工具包,提供图层读写、几何操作、双引擎架构和坐标参考系统管理等功能。 |
| tags | ["dotnet","csharp","gdal","ogr","geometry","vector","crs","cgcs2000"] |
项目地址: https://github.com/znlgis/opengis-utils-for-net
NuGet 包: OpenGIS.Utils
许可证: Apache-2.0
AI-friendly reference for developing with this library. Target: .NET Standard 2.0 | Engine: GDAL/OGR
Installation
dotnet add package OpenGIS.Utils
Build & Test
dotnet build OpenGIS.Utils.sln
dotnet test tests/OpenGIS.Utils.Tests/
Project Structure
src/OpenGIS.Utils/
├── Configuration/ # GdalConfiguration, LibrarySettings
├── DataSource/ # OguLayerUtil (high-level I/O), GtTxtUtil (National Land Survey TXT)
├── Engine/
│ ├── Enums/ # GeometryType, FieldDataType, DataFormatType, GisEngineType, TopologyValidationErrorType
│ ├── IO/ # ILayerReader, ILayerWriter
│ ├── Model/
│ │ └── Layer/ # OguLayer, OguFeature, OguField, OguFieldValue, OguCoordinate, OguLayerMetadata
│ ├── Util/ # CrsUtil, OgrUtil, ShpUtil, PostgisUtil, GdalCmdUtil
│ ├── GdalEngine.cs # GDAL implementation of GisEngine
│ ├── GdalReader.cs # ILayerReader implementation
│ ├── GdalWriter.cs # ILayerWriter implementation
│ ├── GisEngine.cs # Abstract base class
│ └── GisEngineFactory.cs
├── Exception/ # OguException, DataSourceException, FormatParseException, etc.
├── Geometry/ # GeometryUtil (50+ static methods)
└── Utils/ # EncodingUtil, NumUtil, SortUtil, ZipUtil
Namespaces
| Namespace | Key Classes |
|---|
OpenGIS.Utils.Configuration | GdalConfiguration, LibrarySettings |
OpenGIS.Utils.DataSource | OguLayerUtil, GtTxtUtil |
OpenGIS.Utils.Engine | GisEngine, GisEngineFactory, GdalEngine, GdalReader, GdalWriter |
OpenGIS.Utils.Engine.Enums | GeometryType, FieldDataType, DataFormatType, GisEngineType, TopologyValidationErrorType |
OpenGIS.Utils.Engine.IO | ILayerReader, ILayerWriter |
OpenGIS.Utils.Engine.Model | DbConnBaseModel, GdbGroupModel, TopologyValidationResult, SimpleGeometryResult |
OpenGIS.Utils.Engine.Model.Layer | OguLayer, OguFeature, OguField, OguFieldValue, OguCoordinate, OguLayerMetadata |
OpenGIS.Utils.Engine.Util | CrsUtil, OgrUtil, ShpUtil, PostgisUtil, GdalCmdUtil |
OpenGIS.Utils.Exception | OguException, DataSourceException, FormatParseException, EngineNotSupportedException, LayerValidationException, TopologyException |
OpenGIS.Utils.Geometry | GeometryUtil |
OpenGIS.Utils.Utils | EncodingUtil, NumUtil, SortUtil, ZipUtil |
Enums
GeometryType
POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION, UNKNOWN
FieldDataType
STRING, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, DATE, DATETIME, BINARY, UNKNOWN
DataFormatType
SHP, GEOJSON, FILEGDB, POSTGIS, TXT, GEOPACKAGE, KML, DXF, UNKNOWN
GisEngineType
GDAL
注意: .NET 版本仅支持 GDAL 引擎,与 Java 版本不同(Java 版本同时支持 GEOTOOLS 和 GDAL)。
TopologyValidationErrorType
ERROR, REPEATED_POINT, HOLE_OUTSIDE_SHELL, NESTED_HOLES, DISCONNECTED_INTERIOR,
SELF_INTERSECTION, RING_SELF_INTERSECTION, NESTED_SHELLS, DUPLICATE_RINGS,
TOO_FEW_POINTS, INVALID_COORDINATE, RING_NOT_CLOSED
Core Model Classes
OguLayer
using OpenGIS.Utils.Engine.Model.Layer;
using OpenGIS.Utils.Engine.Enums;
| Property | Type | Description |
|---|
Name | string | Layer name |
Wkid | int? | Coordinate system WKID (e.g. 4326 for WGS84) |
GeometryType | GeometryType | Geometry type |
Fields | IList<OguField> | Field definitions |
Features | IList<OguFeature> | Feature collection |
Metadata | OguLayerMetadata? | Optional metadata |
| Method | Returns | Description |
|---|
Validate() | void | Validates layer integrity; throws LayerValidationException |
Filter(Func<OguFeature, bool>) | IList<OguFeature> | Filters features by predicate |
GetFeatureCount() | int | Feature count |
ToJson() | string | Serializes to JSON |
FromJson(string json) | OguLayer? | static — Deserializes from JSON |
Clone() | OguLayer | Deep copy |
GetField(string fieldName) | OguField? | Gets field by name |
AddField(OguField field) | void | Adds a field definition |
AddFeature(OguFeature feature) | void | Adds a feature |
RemoveFeature(int fid) | bool | Removes feature by FID |
OguFeature
| Property | Type | Description |
|---|
Fid | int | Feature ID |
Wkt | string? | Geometry in WKT format |
Attributes | Dictionary<string, OguFieldValue> | Attribute values |
| Method | Returns | Description |
|---|
GetValue(string fieldName) | object? | Gets raw attribute value |
SetValue(string fieldName, object? value) | void | Sets attribute value |
GetAttribute(string fieldName) | OguFieldValue? | Gets field value object |
HasAttribute(string fieldName) | bool | Checks if attribute exists |
ToJson() | string | Serializes to JSON |
FromJson(string json) | OguFeature? | static — Deserializes from JSON |
Clone() | OguFeature | Deep copy |
OguField
| Property | Type | Description |
|---|
Name | string | Field name |
Alias | string? | Display alias |
DataType | FieldDataType | Data type |
Length | int? | String length |
Precision | int? | Numeric precision |
Scale | int? | Decimal places |
IsNullable | bool | Whether nullable |
DefaultValue | object? | Default value |
Methods: ToJson(), FromJson(string), Clone()
OguFieldValue
| Property | Type |
|---|
Value | object? |
IsNull | bool |
Type-safe getters: GetStringValue(), GetIntValue(), GetLongValue(), GetDoubleValue(), GetFloatValue(), GetBoolValue(), GetDateTimeValue(), GetDecimalValue()
OguCoordinate
| Property | Type | Description |
|---|
X | double | X coordinate (longitude) |
Y | double | Y coordinate (latitude) |
Z | double? | Z coordinate (elevation, optional) |
PointNumber | string? | Point number |
RingNumber | string? | Ring number |
Remark | string? | Remark text |
Methods: ToWkt() → string, FromWkt(string wkt) → OguCoordinate (static)
OguLayerMetadata
| Property | Type |
|---|
DataSource | string? |
CoordinateSystemName | string? |
ZoneDivision | string? |
ProjectionType | string? |
MeasureUnit | string? |
ExtendedProperties | Dictionary<string, object> |
CreateTime | DateTime? |
ModifyTime | DateTime? |
Data I/O — OguLayerUtil (Recommended Entry Point)
using OpenGIS.Utils.DataSource;
using OpenGIS.Utils.Engine.Enums;
Read
OguLayer layer = OguLayerUtil.ReadLayer(
DataFormatType.SHP,
"data/cities.shp",
layerName: null,
attributeFilter: "POP > 1000",
spatialFilterWkt: null,
engineType: null,
options: null
);
OguLayer layer = await OguLayerUtil.ReadLayerAsync(DataFormatType.GEOJSON, "data.geojson");
Write
OguLayerUtil.WriteLayer(
DataFormatType.GEOJSON,
layer,
"output/cities.geojson",
layerName: null,
engineType: null,
options: null
);
await OguLayerUtil.WriteLayerAsync(DataFormatType.SHP, layer, "output.shp");
Format Conversion
OguLayerUtil.ConvertFormat(
"input.shp", DataFormatType.SHP,
"output.geojson", DataFormatType.GEOJSON
);
await OguLayerUtil.ConvertFormatAsync(
"input.shp", DataFormatType.SHP,
"output.gpkg", DataFormatType.GEOPACKAGE
);
Utilities
IList<string> names = OguLayerUtil.GetLayerNames(DataFormatType.FILEGDB, "data.gdb");
Supported Format ↔ Driver
| DataFormatType | Driver Name | Extension |
|---|
SHP | ESRI Shapefile | .shp |
GEOJSON | GeoJSON | .geojson / .json |
FILEGDB | FileGDB | .gdb |
GEOPACKAGE | GPKG | .gpkg |
KML | KML | .kml |
DXF | DXF | .dxf |
POSTGIS | PostGIS | (database) |
TXT | Custom | .txt |
Geometry Operations — GeometryUtil
using OpenGIS.Utils.Geometry;
All methods are public static.
Format Conversion
OgrGeometry geom = GeometryUtil.Wkt2Geometry(string wkt);
string wkt = GeometryUtil.Geometry2Wkt(OgrGeometry geom);
string geojson = GeometryUtil.Wkt2Geojson(string wkt);
string geojson = GeometryUtil.Geometry2Geojson(OgrGeometry geom);
⚠️ Limitation: Geojson2Wkt(string) and Geojson2Geometry(string) throw NotSupportedException. To parse GeoJSON, load from file via GdalReader.
Spatial Relationships (OgrGeometry)
bool GeometryUtil.Intersects(OgrGeometry a, OgrGeometry b)
bool GeometryUtil.Contains(OgrGeometry a, OgrGeometry b)
bool GeometryUtil.Within(OgrGeometry a, OgrGeometry b)
bool GeometryUtil.Touches(OgrGeometry a, OgrGeometry b)
bool GeometryUtil.Crosses(OgrGeometry a, OgrGeometry b)
bool GeometryUtil.Overlaps(OgrGeometry a, OgrGeometry b)
bool GeometryUtil.Disjoint(OgrGeometry a, OgrGeometry b)
Spatial Relationships (WKT convenience)
bool GeometryUtil.IntersectsWkt(string wktA, string wktB)
bool GeometryUtil.ContainsWkt(string wktA, string wktB)
Spatial Analysis (OgrGeometry)
OgrGeometry GeometryUtil.Buffer(OgrGeometry geom, double distance)
OgrGeometry GeometryUtil.Intersection(OgrGeometry a, OgrGeometry b)
OgrGeometry GeometryUtil.Union(OgrGeometry a, OgrGeometry b)
OgrGeometry GeometryUtil.Union(IEnumerable<OgrGeometry> geometries)
OgrGeometry GeometryUtil.Difference(OgrGeometry a, OgrGeometry b)
OgrGeometry GeometryUtil.SymDifference(OgrGeometry a, OgrGeometry b)
Spatial Analysis (WKT convenience)
string GeometryUtil.BufferWkt(string wkt, double distance)
string GeometryUtil.IntersectionWkt(string wktA, string wktB)
string GeometryUtil.UnionWkt(IEnumerable<string> wktList)
Geometry Properties
double GeometryUtil.Area(OgrGeometry geom)
double GeometryUtil.Length(OgrGeometry geom)
OgrGeometry GeometryUtil.Centroid(OgrGeometry geom)
OgrGeometry GeometryUtil.InteriorPoint(OgrGeometry geom)
int GeometryUtil.Dimension(OgrGeometry geom)
int GeometryUtil.NumPoints(OgrGeometry geom)
GeometryType GeometryUtil.GetGeometryType(OgrGeometry geom)
bool GeometryUtil.IsEmpty(OgrGeometry geom)
Geometry Properties (WKT convenience)
double GeometryUtil.AreaWkt(string wkt)
double GeometryUtil.LengthWkt(string wkt)
string GeometryUtil.CentroidWkt(string wkt)
Geometry Operations
OgrGeometry GeometryUtil.Boundary(OgrGeometry geom)
OgrGeometry GeometryUtil.Envelope(OgrGeometry geom)
OgrGeometry GeometryUtil.ConvexHull(OgrGeometry geom)
OgrGeometry GeometryUtil.Simplify(OgrGeometry geom, double tolerance)
OgrGeometry GeometryUtil.Densify(OgrGeometry geom, double distanceTolerance)
string GeometryUtil.SimplifyWkt(string wkt, double tolerance)
Topology Validation
TopologyValidationResult GeometryUtil.IsValid(OgrGeometry geom)
SimpleGeometryResult GeometryUtil.IsSimple(OgrGeometry geom)
Equality & Distance
bool GeometryUtil.EqualsExact(OgrGeometry a, OgrGeometry b)
bool GeometryUtil.EqualsExactTolerance(OgrGeometry a, OgrGeometry b, double tolerance)
bool GeometryUtil.EqualsTopo(OgrGeometry a, OgrGeometry b)
double GeometryUtil.Distance(OgrGeometry a, OgrGeometry b)
bool GeometryUtil.IsWithinDistance(OgrGeometry a, OgrGeometry b, double maxDistance)
Coordinate Reference Systems — CrsUtil
using OpenGIS.Utils.Engine.Util;
string CrsUtil.Transform(string wkt, int sourceWkid, int targetWkid)
OgrGeometry CrsUtil.Transform(OgrGeometry geometry, int sourceWkid, int targetWkid)
int CrsUtil.GetDh(OgrGeometry geometry)
int CrsUtil.GetDh(double longitude)
int CrsUtil.GetDh6(double longitude)
int CrsUtil.GetDhFromWkid(int projectedWkid)
int CrsUtil.GetProjectedWkid(int zoneNumber)
int CrsUtil.GetProjectedWkid6(int zoneNumber)
double CrsUtil.GetTolerance(int wkid)
bool CrsUtil.IsProjectedCRS(int wkid)
Shapefile Utilities — ShpUtil
using OpenGIS.Utils.Engine.Util;
OguLayer ShpUtil.ReadShapefile(string shpPath, Encoding? encoding = null)
void ShpUtil.WriteShapefile(OguLayer layer, string shpPath, Encoding? encoding = null)
Encoding ShpUtil.GetShapefileEncoding(string shpPath)
void ShpUtil.CreateCpgFile(string shpPath, Encoding encoding)
Envelope? ShpUtil.GetShapefileBounds(string shpPath)
void ShpUtil.RepairShapefile(string shpPath)
PostGIS Utilities — PostgisUtil
using OpenGIS.Utils.Engine.Util;
OguLayer PostgisUtil.ReadPostGIS(string connectionString, string tableName, string? filter = null)
void PostgisUtil.WritePostGIS(OguLayer layer, string connectionString, string tableName)
bool PostgisUtil.TableExists(string connectionString, string tableName)
void PostgisUtil.CreateSpatialIndex(string connectionString, string tableName, string geomColumn = "geom")
National Land Survey TXT Format — GtTxtUtil
using OpenGIS.Utils.DataSource;
OguLayer GtTxtUtil.LoadTxt(string txtPath, Encoding? encoding = null)
void GtTxtUtil.SaveTxt(OguLayer layer, string txtPath, OguLayerMetadata? metadata = null, Encoding? encoding = null, int? zoneNumber = null)
OguCoordinate? GtTxtUtil.ParseTxtLine(string line)
string GtTxtUtil.FormatTxtLine(OguCoordinate coordinate, int zoneNumber)
GDAL Configuration
using OpenGIS.Utils.Configuration;
GdalConfiguration.ConfigureGdal()
GdalConfiguration.RegisterAllDrivers()
string GdalConfiguration.GetGdalVersion()
IList<string> GdalConfiguration.GetSupportedDrivers()
bool GdalConfiguration.IsDriverAvailable(string driverName)
LibrarySettings (Global Defaults)
| Property | Type | Default | Description |
|---|
DefaultTolerance | double | 0.0001 | Default geometry tolerance |
AutoCreateSpatialIndex | bool | true | Auto-create spatial index |
SpatialIndexThreshold | int | 1000 | Feature count threshold for index |
DefaultBufferSegments | int | 8 | Buffer curve segments |
UseGdalExceptions | bool | true | GDAL exception mode |
Engine Architecture
using OpenGIS.Utils.Engine;
public abstract class GisEngine
{
public abstract GisEngineType EngineType { get; }
public abstract IList<DataFormatType> SupportedFormats { get; }
public abstract ILayerReader CreateReader();
public abstract ILayerWriter CreateWriter();
public virtual bool SupportsFormat(DataFormatType format);
}
GisEngine engine = GisEngineFactory.GetEngine(GisEngineType.GDAL);
GisEngine engine = GisEngineFactory.GetEngine(DataFormatType.SHP);
bool ok = GisEngineFactory.TryGetEngine(DataFormatType.GEOJSON, out GisEngine? engine);
ILayerReader / ILayerWriter
public interface ILayerReader
{
OguLayer Read(string path, string? layerName = null, string? attributeFilter = null,
string? spatialFilterWkt = null, Dictionary<string, object>? options = null);
IList<string> GetLayerNames(string path);
}
public interface ILayerWriter
{
void Write(OguLayer layer, string path, string? layerName = null,
Dictionary<string, object>? options = null);
void Append(OguLayer layer, string path, string? layerName = null,
Dictionary<string, object>? options = null);
}
General Utilities
EncodingUtil
using OpenGIS.Utils.Utils;
Encoding EncodingUtil.GetFileEncoding(string filePath)
Encoding EncodingUtil.GetFileEncoding(Stream stream)
Encoding EncodingUtil.DetectEncoding(byte[] buffer)
Encoding EncodingUtil.DetectEncoding(byte[] buffer, int length)
void EncodingUtil.ConvertFileEncoding(string filePath, Encoding targetEncoding)
ZipUtil
void ZipUtil.Zip(string folderPath, string zipPath)
void ZipUtil.Zip(string folderPath, string zipPath, Encoding encoding)
void ZipUtil.Unzip(string zipPath, string destPath)
void ZipUtil.Unzip(string zipPath, string destPath, Encoding encoding)
void ZipUtil.CompressFiles(IEnumerable<string> filePaths, string zipPath)
SortUtil
int SortUtil.CompareString(string a, string b)
IOrderedEnumerable<T> SortUtil.NaturalSort<T>(IEnumerable<T> source, Func<T, string> keySelector)
NumUtil
string NumUtil.GetPlainString(double number)
string NumUtil.GetPlainString(decimal number)
double NumUtil.Round(double value, int decimals)
string NumUtil.FormatNumber(double value, int decimals)
Exception Hierarchy
System.Exception
└── OguException (ErrorCode, Context)
├── DataSourceException — Data source access errors
├── EngineNotSupportedException — Unsupported engine type
├── FormatParseException — Format parsing errors
├── LayerValidationException — Layer validation failures
└── TopologyException — Topology validation/operation errors
Result Models
TopologyValidationResult
| Property | Type |
|---|
IsValid | bool |
ErrorType | TopologyValidationErrorType? |
ErrorMessage | string? |
ErrorLocation | string? (WKT) |
SimpleGeometryResult
| Property | Type |
|---|
IsSimple | bool |
Reason | string? |
NonSimpleLocation | string? (WKT) |
DbConnBaseModel
Properties: Host, Port, Database, Username, Password, Schema, ConnectionString (all nullable)
GdbGroupModel
Properties: GdbPath (string?), LayerNames (List<string>)
Common Code Patterns
Create a Layer from Scratch
using OpenGIS.Utils.Engine.Model.Layer;
using OpenGIS.Utils.Engine.Enums;
var layer = new OguLayer
{
Name = "cities",
GeometryType = GeometryType.POINT,
Wkid = 4326
};
layer.AddField(new OguField { Name = "ID", DataType = FieldDataType.INTEGER });
layer.AddField(new OguField { Name = "Name", DataType = FieldDataType.STRING, Length = 100 });
layer.AddField(new OguField { Name = "Population", DataType = FieldDataType.LONG });
var feature = new OguFeature { Fid = 1, Wkt = "POINT (116.404 39.915)" };
feature.SetValue("ID", 1);
feature.SetValue("Name", "Beijing");
feature.SetValue("Population", 21540000L);
layer.AddFeature(feature);
layer.Validate();
Read → Process → Write
using OpenGIS.Utils.DataSource;
using OpenGIS.Utils.Engine.Enums;
using OpenGIS.Utils.Geometry;
var layer = OguLayerUtil.ReadLayer(DataFormatType.SHP, "input.shp");
var largeCities = layer.Filter(f =>
{
var pop = f.GetAttribute("Population")?.GetLongValue();
return pop.HasValue && pop.Value > 1000000;
});
foreach (var feature in layer.Features)
{
if (feature.Wkt != null)
{
feature.Wkt = GeometryUtil.BufferWkt(feature.Wkt, 0.01);
}
}
OguLayerUtil.WriteLayer(DataFormatType.GEOJSON, layer, "output.geojson");
Coordinate Transformation
using OpenGIS.Utils.Engine.Util;
string wktWgs84 = "POINT (116.404 39.915)";
string wktCgcs2000 = CrsUtil.Transform(wktWgs84, 4326, 4490);
int zone = CrsUtil.GetDh(116.404);
int wkid = CrsUtil.GetProjectedWkid(zone);
string projected = CrsUtil.Transform(wktWgs84, 4326, wkid);
Geometry Analysis
using OpenGIS.Utils.Geometry;
string polygon = "POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))";
string point = "POINT (5 5)";
bool contains = GeometryUtil.ContainsWkt(polygon, point);
double area = GeometryUtil.AreaWkt(polygon);
string center = GeometryUtil.CentroidWkt(polygon);
string buffer = GeometryUtil.BufferWkt(point, 1.0);
Format Conversion (One Line)
OguLayerUtil.ConvertFormat("input.shp", DataFormatType.SHP, "output.gpkg", DataFormatType.GEOPACKAGE);
JSON Serialization
string json = layer.ToJson();
OguLayer? restored = OguLayer.FromJson(json);
Shapefile with Encoding
using OpenGIS.Utils.Engine.Util;
using System.Text;
var layer = ShpUtil.ReadShapefile("data.shp", Encoding.GetEncoding("GBK"));
ShpUtil.WriteShapefile(layer, "output.shp", Encoding.UTF8);
Natural Sorting
using OpenGIS.Utils.Utils;
var files = new[] { "file1.txt", "file10.txt", "file2.txt" };
var sorted = SortUtil.NaturalSort(files, f => f);
AI 使用建议
推荐工作流
- 读取数据:使用
OguLayerUtil.ReadLayer() 统一入口读取各类矢量格式
- 几何运算:使用
GeometryUtil.Wkt2Geometry() 转换后操作,或直接用 *Wkt 后缀方法
- 坐标转换:使用
CrsUtil.Transform() 进行坐标系变换(CGCS2000 系列)
- 写出结果:使用
OguLayerUtil.WriteLayer() 写出为目标格式
- 格式转换:使用
OguLayerUtil.ConvertFormat() 一步完成
关键注意事项
- GDAL 自动初始化:无需手动调用
GdalConfiguration.ConfigureGdal()
- GeoJSON 字符串解析不支持:
Geojson2Wkt() 和 Geojson2Geometry() 抛出 NotSupportedException,需从文件加载
- 几何以 WKT 存储:
OguFeature.Wkt 存储 WKT 字符串;多数 GeometryUtil 方法有 *Wkt 变体
- .NET 仅支持 GDAL 引擎:与 Java 版本不同,无 GeoTools 引擎
- 线程安全:GDAL 初始化线程安全,但单个 GDAL 几何对象非线程安全
相关技能
Important Notes
- GDAL auto-initializes — No manual
GdalConfiguration.ConfigureGdal() call needed.
- GeoJSON string parsing not supported —
Geojson2Wkt() and Geojson2Geometry() throw NotSupportedException. Load GeoJSON from files via GdalReader or OguLayerUtil.ReadLayer(DataFormatType.GEOJSON, path).
- Geometry uses WKT strings —
OguFeature.Wkt stores geometry as WKT. Use GeometryUtil for conversions and operations.
- Thread safety — GDAL initialization is thread-safe. Individual GDAL geometry objects are NOT thread-safe.
- Cross-platform — .NET Standard 2.0: works on .NET Core 2.0+, .NET 5+, .NET Framework 4.6.1+.
- Encoding support —
EncodingUtil detects UTF-8, UTF-16 LE/BE, GBK, GB2312. Register CodePages with Encoding.RegisterProvider(CodePagesEncodingProvider.Instance) if needed.
- WKT convenience methods — Most
GeometryUtil methods have *Wkt variants that accept/return WKT strings directly, avoiding the need to manage OgrGeometry objects.