空间参考是
GIS
的基础,失去了空间参考信息,地理空间内所有的信息也就失去了存在的意义,因为它们是不准确的或是错误的。关于
ArcGIS
坐标系统文件,可以看看这篇文章
——
《
ArcGIS 坐标系统文件
》。
刻画Spatial Reference的精度
首先,我们主要讨论的是
ArcGIS
中
Spatial Reference
的各种精度,看到
resolution
、
tolerance
、
domain
、
scale factor
、
precision
,是否很熟悉?为了保证表达的准确性,所有这些关键字使用英文表述,不再译为中文。
Resolution
和
domain
范围决定了
Geometry
坐标的存储方式,
Resolution
和关联的坐标系使用相同的数量单位,如当空间参考使用以米为单位的投影参考时,
XY resolution
单位为米,默认情况下
resolution=0.0001m
,不管怎么样
resolution
值至少应该小于数据精度的
1/10
。当定位某一坐标到坐标格网时,我们依据如下公式:
Persisted coordinate = Round((map coordinate - minimum domain extent) / resolution)
在
ArcGIS 9.2
之前,
resolution=1/precision
,
ArcGIS 9.2
认为
resolution
和
precision
几乎相同,在
9.2
之前坐标的存储精度是
31
位,
9.2
中为
53
位,对于上面的公式而言,当
resolution
很小时,坐标系统表达数据会更精确,但在
9.2
之前的
ArcGIS
中
persisted coordinate
会受到限制。例如在
ArcGIS 9.2
之前,当
minimum domain value=0
,
resolution=1
时,
maximum domain value=231-2
,
resolution=0.0001
时,
maximum domain value="/(231-2)*0.0001=
214748.3647;在ArcGIS 9.2中,当minimum domain value=0,resolution=1时,maximum domain value=253-2,resolution=0.0001时,maximum domain value="/(253-2)*0.0001,很显然,ArcGIS 9.1中maximum domain value=
214748.3647已经不能满足UTM、State Plane等投影坐标系的要求,ArcGIS 9.2存储的数据可以拥有更高精度的空间参考。
默认情况下,ArcGIS 9.2为整数坐标采用53位空间存储,当然在编辑没有升级空间参考的空间数据库中的数据时,也可以保持向下兼容。新的COM接口已经可以用来判断数据采用的是低精度的各种空间参考,还是高精度的,同时有新的接口可以在低精度空间参考和高精度空间参考之间转换。
还是默认情况下,Tolerance=10*resolution,minimum tolerance=2*resolution=2.0/scale factor,tolerance决定在relational和topological操作中,两个坐标之间的最小距离,当小于该距离时,认为这两个坐标为相同的坐标。relational和topological操作采用不同的tolerance会得到不同的处理结果。9.2之前tolerance值受resolution的影响,9.2中必须要明确指定tolerance的值,在IRelationalOperator、ITopologicalOperator等对两个几何对象进行Geometry操作的接口中,使用第一个对象的tolerance来判断两几何体点点之间的关系,如果空间参考是未定义,或没有空间参考和几何体关联,将采用该格网所允许的最小tolerance取值。
//
使用SpatialReferenceEnvironment
private
void
PrintPreDefinedProjections()
{
ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass();
ISet projectionSet = spatialReferenceFactory.CreatePredefinedProjections();
System.Windows.Forms.MessageBox.Show("Number of predefined Projections = " + projectionSet.Count);
projectionSet.Reset();
for (int i = 0; i < projectionSet.Count; i++)
{
IProjection projection = projectionSet.Next() as IProjection;
System.Windows.Forms.MessageBox.Show(projection.Name);
}
}
//CreatePredefinedProjections返回AE中所有预定义的投影坐标,一共59个。ISpatialReferenceFactory的CreateESRISpatialReferenceFromPRJFile方法可以从已定义的PRJ文件获取坐标。
private
IProjectedCoordinateSystem LoadProjectedCoordinateSystem()
{
ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass();
IProjectedCoordinateSystem projectedCoordinateSystem = spatialReferenceFactory.CreateESRISpatialReferenceFromPRJFile("C:\\Program Files\\ArcGIS\\Coordinate Systems\\Projected Coordinate Systems\\World\\Mollweide (world).prj") as IProjectedCoordinateSystem;
return projectedCoordinateSystem;
}
除了ISpatialReferenceFactory接口,AE还提供ISpatialReferenceFactory3接口实现了创建垂直坐标系、构建高精度坐标系和低精度坐标系的系列方法。
private void ConstructCoordinateSystem(bool highPrecision)
{
ISpatialReferenceFactory3 spatialReferenceFactory = new SpatialReferenceEnvironmentClass();
ISpatialReference3 spatialReference = spatialReferenceFactory.CreateESRISpatialReferenceFromPRJFile("D:\\ArcGIS\\Coordinate Systems\\Geographic Coordinate Systems\\World\\WGS 1984.prj") as ISpatialReference3;
IControlPrecision2 controlPrecision = spatialReference as IControlPrecision2;
//Determines whether you are constructing a high or low.
controlPrecision.IsHighPrecision = highPrecision;
ISpatialReferenceResolution spatialReferenceResolution = spatialReference as ISpatialReferenceResolution;
//These three methods are the keys, construct horizon, then set the default x,y resolution and tolerance.
spatialReferenceResolution.ConstructFromHorizon();
//Set the default x,y resolution value.
spatialReferenceResolution.SetDefaultXYResolution();
//Set the default x,y tolerance value.
ISpatialReferenceTolerance spatialReferenceTolerance = spatialReference as ISpatialReferenceTolerance;
spatialReferenceTolerance.SetDefaultXYTolerance();
double xMin;
double xMax;
double yMin;
double yMax;
spatialReference.GetDomain(out xMin, out xMax, out yMin, out yMax);
System.Windows.Forms.MessageBox.Show("Domain : " + xMin + ", " + xMax + ", " + yMin + ", " + yMax);
}
IControlPrecision2.IsHighPrecision用来判断是否对数据采用高精度坐标,后面的设置空间参考的方法将根据这个判断来决定各种参数的精确程度。highPrecision等于true或false时,返回的Domain分别是:
highPrecision=true -400 9006799.25474099 -400 9006799.25474099
highPrecision=false -400 793.04646944444426 -400 793.04646944444426
可以看出两者之间精度差别的大小。
我们可以创建一个新的投影坐标系并保存为prj文件,同时可以利用这个prj生成一个新的投影坐标系。
private void ImportExportSR_Example()
{
//Instantiate a predefined spatial reference and set its coordinate grid information.
ISpatialReferenceFactory spatialReferenceFactory = new SpatialReferenceEnvironmentClass();
IProjectedCoordinateSystem projectedCoordinateSystem = spatialReferenceFactory.CreateProjectedCoordinateSystem((int)esriSRProjCSType.esriSRProjCS_WGS1984UTM_10N);
ISpatialReferenceResolution spatialReferenceResolution = projectedCoordinateSystem as ISpatialReferenceResolution;
ISpatialReferenceTolerance spatialReferenceTolerance = projectedCoordinateSystem as ISpatialReferenceTolerance;
spatialReferenceResolution.ConstructFromHorizon();
spatialReferenceTolerance.SetDefaultXYTolerance();
//Export the PCS to a .prj file.
String fileName = "c:\\temp\\utm10.prj";
spatialReferenceFactory.ExportESRISpatialReferenceToPRJFile(fileName, projectedCoordinateSystem);
//Rehydrate it as a new spatial reference object.
ISpatialReference projectedCoordinateSystem2 = spatialReferenceFactory.CreateESRISpatialReferenceFromPRJFile(fileName);
//See if they are equal.
IClone comparison = projectedCoordinateSystem as IClone;
//Should be true, but coordinate grid information has not been checked.
System.Windows.Forms.MessageBox.Show((comparison.IsEqual(projectedCoordinateSystem2 as IClone)).ToString());
ISpatialReference2 comparePrecisions = projectedCoordinateSystem as ISpatialReference2;
//Should be false, PRJ files do not persist coordinate grid information.
System.Windows.Forms.MessageBox.Show((comparePrecisions.IsXYPrecisionEqual(projectedCoordinateSystem2)).ToString());
}