08-空间参考系统
第八章:空间参考系统
8.1 概述
空间参考系统(Spatial Reference System,SRS)定义了几何对象的坐标如何对应到地球表面的位置。理解和正确使用空间参考是 GIS 开发的基础。
8.1.1 为什么需要空间参考
地球是一个不规则的椭球体,而地图是平面的。空间参考系统解决了以下问题:
- 定位:确定坐标的实际位置
- 测量:计算准确的距离和面积
- 转换:在不同坐标系之间转换数据
8.1.2 SpatialReference 类
public class SpatialReference
{
// 构造函数
public SpatialReference();
public SpatialReference(int wkid);
// 属性
public int? Wkid { get; set; } // Well-Known ID
public int? LatestWkid { get; set; } // 最新的 WKID
public string? Wkt { get; set; } // WKT 定义
// 工厂方法
public static SpatialReference Wgs84(); // EPSG:4326
public static SpatialReference WebMercator(); // EPSG:3857
}
8.2 常用坐标系
8.2.1 地理坐标系
地理坐标系使用经度和纬度来定位地球表面的位置。
WGS 84 (EPSG:4326)
全球定位系统(GPS)使用的标准坐标系。
using Esri.Geometry.Core.SpatialReference;
// 创建 WGS 84 空间参考
var wgs84 = SpatialReference.Wgs84();
Console.WriteLine($"WKID: {wgs84.Wkid}"); // 4326
// 或者手动创建
var wgs84Manual = new SpatialReference(4326);
// WGS 84 坐标范围
// 经度:-180 到 180
// 纬度:-90 到 90
特点:
- 单位:度(degrees)
- 使用:GPS 定位、全球数据
- 适合:数据存储、交换
8.2.2 投影坐标系
投影坐标系将地球表面投影到平面上。
Web Mercator (EPSG:3857)
Web 地图(Google Maps、OpenStreetMap、ArcGIS Online)使用的标准投影。
// 创建 Web Mercator 空间参考
var webMercator = SpatialReference.WebMercator();
Console.WriteLine($"WKID: {webMercator.Wkid}"); // 3857
// Web Mercator 坐标范围
// X:约 -20037508 到 20037508 米
// Y:约 -20037508 到 20037508 米
// 注意:纬度 85.05° 以外区域被裁剪
特点:
- 单位:米(meters)
- 使用:Web 地图显示
- 优点:方便瓦片切分
- 缺点:极地区域失真严重
8.2.3 其他常用坐标系
| EPSG | 名称 | 区域 | 用途 |
|---|---|---|---|
| 4326 | WGS 84 | 全球 | GPS、数据交换 |
| 3857 | Web Mercator | 全球 | Web 地图 |
| 4490 | CGCS2000 | 中国 | 中国官方坐标系 |
| 4549 | CGCS2000 / 3-degree Gauss-Kruger zone 39 | 中国 | 投影坐标 |
| 32650 | WGS 84 / UTM zone 50N | 东经 114°-120° | 高精度测量 |
8.3 使用空间参考
8.3.1 创建空间参考
using Esri.Geometry.Core.SpatialReference;
// 使用工厂方法
var wgs84 = SpatialReference.Wgs84();
var webMercator = SpatialReference.WebMercator();
// 使用 WKID
var utm50n = new SpatialReference(32650);
// 使用 WKT(对于自定义或不常见的坐标系)
var customSr = new SpatialReference
{
Wkt = @"GEOGCS[""GCS_WGS_1984"",DATUM[""D_WGS_1984"",
SPHEROID[""WGS_1984"",6378137.0,298.257223563]],
PRIMEM[""Greenwich"",0.0],UNIT[""Degree"",0.0174532925199433]]"
};
// 同时设置 WKID 和 LatestWkid
var sr = new SpatialReference
{
Wkid = 102100, // 旧的 WKID
LatestWkid = 3857 // 最新的 WKID
};
8.3.2 MapGeometry 与空间参考
using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;
using Esri.Geometry.Core.SpatialReference;
// 创建带空间参考的几何对象
var point = new Point(116.4074, 39.9042);
var wgs84 = SpatialReference.Wgs84();
var mapGeom = new MapGeometry(point, wgs84);
Console.WriteLine($"几何类型:{mapGeom.Geometry?.Type}");
Console.WriteLine($"空间参考:WKID {mapGeom.SpatialReference?.Wkid}");
// 比较空间参考
var mapGeom2 = new MapGeometry(new Point(121.4737, 31.2304), SpatialReference.Wgs84());
bool sameSR = mapGeom.SpatialReference?.Wkid == mapGeom2.SpatialReference?.Wkid;
Console.WriteLine($"相同空间参考:{sameSR}"); // true
8.3.3 导出时包含空间参考
using Esri.Geometry.Core.IO;
// Esri JSON 支持空间参考
var point = new Point(116.4074, 39.9042);
var sr = SpatialReference.Wgs84();
string json = EsriJsonExportOperator.Instance.Execute(point, sr);
Console.WriteLine(json);
// {"x":116.4074,"y":39.9042,"spatialReference":{"wkid":4326}}
8.4 大地测量计算
8.4.1 概念
当使用地理坐标系(如 WGS 84)时,需要使用大地测量方法来计算准确的距离和面积,因为地球是椭球体而非平面。
8.4.2 大地测量距离
using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;
using Esri.Geometry.Core.Operators;
// 使用 Vincenty 公式计算两点间的大地测量距离
var beijing = new Point(116.4074, 39.9042); // 北京
var shanghai = new Point(121.4737, 31.2304); // 上海
// 使用 GeometryEngine
double distance = GeometryEngine.GeodesicDistance(beijing, shanghai);
Console.WriteLine($"北京到上海:{distance:N0} 米"); // 约 1,067,890 米
// 使用操作符
double distance2 = GeodesicDistanceOperator.Instance.Execute(beijing, shanghai);
// 与简单欧几里得距离比较
double euclidean = GeometryEngine.Distance(beijing, shanghai);
Console.WriteLine($"欧几里得距离:{euclidean:F4} 度");
// 注意:度不能直接作为距离单位使用!
8.4.3 Vincenty 公式
GeodesicDistanceOperator 使用 Vincenty 公式计算 WGS 84 椭球上的精确距离:
// WGS 84 椭球参数
private const double WGS84_SEMI_MAJOR_AXIS = 6378137.0; // 长半轴(米)
private const double WGS84_SEMI_MINOR_AXIS = 6356752.314245; // 短半轴(米)
private const double WGS84_FLATTENING =
(WGS84_SEMI_MAJOR_AXIS - WGS84_SEMI_MINOR_AXIS) / WGS84_SEMI_MAJOR_AXIS;
// Vincenty 迭代计算
// 精度:约 0.5 毫米
// 适用范围:全球任意两点
8.4.4 大地测量面积
using Esri.Geometry.Core;
using Esri.Geometry.Core.Geometries;
using Esri.Geometry.Core.Operators;
// 创建一个区域(经纬度坐标)
var region = new Polygon();
region.AddRing(new List<Point>
{
new Point(116.0, 39.5),
new Point(117.0, 39.5),
new Point(117.0, 40.5),
new Point(116.0, 40.5),
new Point(116.0, 39.5)
});
// 计算大地测量面积
double geodesicArea = GeometryEngine.GeodesicArea(region);
Console.WriteLine($"大地测量面积:{geodesicArea:N0} 平方米");
// 与简单面积比较
double simpleArea = GeometryEngine.Area(region);
Console.WriteLine($"简单面积:{simpleArea} 平方度");
// 注意:平方度不是有效的面积单位!
8.4.5 距离单位转换
// 常用转换系数
const double METERS_PER_KILOMETER = 1000.0;
const double METERS_PER_MILE = 1609.344;
const double METERS_PER_NAUTICAL_MILE = 1852.0;
// 转换示例
double distanceMeters = GeometryEngine.GeodesicDistance(point1, point2);
double distanceKm = distanceMeters / METERS_PER_KILOMETER;
double distanceMiles = distanceMeters / METERS_PER_MILE;
double distanceNauticalMiles = distanceMeters / METERS_PER_NAUTICAL_MILE;
Console.WriteLine($"距离:{distanceKm:F2} 公里");
Console.WriteLine($"距离:{distanceMiles:F2} 英里");
Console.WriteLine($"距离:{distanceNauticalMiles:F2} 海里");
8.5 坐标转换基础
8.5.1 概念
几何数据经常需要在不同的空间参考之间转换。常见场景:
- GPS 数据(WGS 84)显示在 Web 地图(Web Mercator)上
- 合并来自不同源的数据
- 与特定应用程序集成
8.5.2 当前支持
geometry-api-net 当前提供空间参考的定义和存储,完整的投影转换需要外部库(如 ProjNet、DotSpatial)。
// 存储空间参考信息
var mapGeom = new MapGeometry(geometry, SpatialReference.Wgs84());
// 检查空间参考
if (mapGeom.SpatialReference?.Wkid == 4326)
{
// 这是 WGS 84 数据
Console.WriteLine("数据使用 WGS 84 坐标系");
}
8.5.3 手动转换示例
// WGS 84 到 Web Mercator 的简化转换
public static Point Wgs84ToWebMercator(Point wgs84Point)
{
const double EARTH_RADIUS = 6378137.0;
double x = wgs84Point.X * Math.PI / 180.0 * EARTH_RADIUS;
double y = Math.Log(Math.Tan((90.0 + wgs84Point.Y) * Math.PI / 360.0)) * EARTH_RADIUS;
return new Point(x, y);
}
// Web Mercator 到 WGS 84 的简化转换
public static Point WebMercatorToWgs84(Point webMercatorPoint)
{
const double EARTH_RADIUS = 6378137.0;
double lon = webMercatorPoint.X / EARTH_RADIUS * 180.0 / Math.PI;
double lat = 180.0 / Math.PI * (2.0 * Math.Atan(Math.Exp(webMercatorPoint.Y / EARTH_RADIUS)) - Math.PI / 2.0);
return new Point(lon, lat);
}
// 使用
var wgs84Point = new Point(116.4074, 39.9042); // 北京
var webMercatorPoint = Wgs84ToWebMercator(wgs84Point);
Console.WriteLine($"Web Mercator: ({webMercatorPoint.X:F2}, {webMercatorPoint.Y:F2})");
// 输出约:(12958174.31, 4852167.63)
var backToWgs84 = WebMercatorToWgs84(webMercatorPoint);
Console.WriteLine($"WGS 84: ({backToWgs84.X:F4}, {backToWgs84.Y:F4})");
8.6 实际应用
8.6.1 GPS 轨迹处理
// GPS 数据通常是 WGS 84
var gpsPoints = new List<Point>
{
new Point(116.4000, 39.9000),
new Point(116.4010, 39.9005),
new Point(116.4020, 39.9010),
new Point(116.4030, 39.9008)
};
// 计算轨迹总长度(使用大地测量距离)
double totalDistance = 0;
for (int i = 1; i < gpsPoints.Count; i++)
{
totalDistance += GeometryEngine.GeodesicDistance(gpsPoints[i - 1], gpsPoints[i]);
}
Console.WriteLine($"轨迹总长度:{totalDistance:F2} 米");
// 创建带空间参考的轨迹
var track = new Polyline();
track.AddPath(gpsPoints);
var mapTrack = new MapGeometry(track, SpatialReference.Wgs84());
8.6.2 服务区域分析
// 服务区域(WGS 84 坐标)
var serviceCenter = new Point(116.4074, 39.9042);
// 检查客户是否在服务范围内(5 公里)
var customers = new List<Point>
{
new Point(116.42, 39.91),
new Point(116.45, 39.95),
new Point(116.50, 40.00)
};
const double serviceRadius = 5000; // 5 公里
foreach (var customer in customers)
{
double distance = GeometryEngine.GeodesicDistance(serviceCenter, customer);
bool inService = distance <= serviceRadius;
Console.WriteLine($"客户 ({customer.X}, {customer.Y}): {distance:F0} 米, 服务范围内: {inService}");
}
8.6.3 地理围栏
// 定义地理围栏(WGS 84 坐标)
var geofence = new Polygon();
geofence.AddRing(new List<Point>
{
new Point(116.40, 39.90),
new Point(116.45, 39.90),
new Point(116.45, 39.95),
new Point(116.40, 39.95),
new Point(116.40, 39.90)
});
// 附加空间参考信息
var geofenceWithSR = new MapGeometry(geofence, SpatialReference.Wgs84());
// 检查设备位置
var deviceLocation = new Point(116.42, 39.92);
bool insideGeofence = GeometryEngine.Contains(geofence, deviceLocation);
if (insideGeofence)
{
Console.WriteLine("设备在围栏内");
}
else
{
Console.WriteLine("设备已离开围栏");
// 触发告警...
}
8.7 最佳实践
8.7.1 空间参考管理
// 1. 始终记录数据的空间参考
public class GeoData
{
public Geometry Geometry { get; set; }
public int Srid { get; set; } // 空间参考 ID
}
// 2. 使用 MapGeometry 捆绑几何和空间参考
var data = new MapGeometry(geometry, SpatialReference.Wgs84());
// 3. 在处理前验证空间参考
if (data1.SpatialReference?.Wkid != data2.SpatialReference?.Wkid)
{
throw new InvalidOperationException("空间参考不匹配");
}
8.7.2 距离和面积计算
// ✅ 对于地理坐标,使用大地测量方法
double correctDistance = GeometryEngine.GeodesicDistance(point1, point2); // 米
// ❌ 不要对地理坐标使用欧几里得距离
double wrongDistance = GeometryEngine.Distance(point1, point2); // 度!
// ✅ 对于投影坐标(米),可以使用欧几里得距离
// 假设 point1 和 point2 是 Web Mercator 坐标
double distanceInMeters = GeometryEngine.Distance(point1, point2);
8.7.3 坐标系统选择
| 场景 | 推荐坐标系 | 原因 |
|---|---|---|
| 数据存储 | WGS 84 (4326) | 通用标准 |
| Web 显示 | Web Mercator (3857) | 瓦片兼容 |
| 面积计算 | 等面积投影 | 保持面积 |
| 距离计算 | 等距投影或大地测量 | 保持距离 |
| 本地测量 | UTM 或本地投影 | 高精度 |
8.8 小结
本章介绍了 geometry-api-net 的空间参考系统支持:
- SpatialReference 类:使用 WKID 和 WKT 定义空间参考
- 常用坐标系:WGS 84 和 Web Mercator
- MapGeometry:将几何对象与空间参考捆绑
- 大地测量计算:准确的距离和面积计算
- 坐标转换基础:WGS 84 与 Web Mercator 之间的转换
关键要点:
- 始终记录数据的空间参考
- 对地理坐标使用大地测量方法计算距离和面积
- 合并数据前确保空间参考一致
在下一章中,我们将学*邻*分析与位置服务,了解如何查找最*的几何要素。

浙公网安备 33010602011771号