作者:Flyingis
空間參考是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());
}
兩個空間參考是否相等不能簡單通過一個方法來確定,IClone.isEqual只能比較坐標系相同,而不能確定坐標格網信息是否相同,因此最后一行代碼比較的結果是false(IsXYPrecisionEqual是ISpatialReference2接口中的方法)。最后,看看如何自定義一個完整的投影坐標參考系,地理坐標系和垂直坐標系定義方法類似。
private void SetProjectionParameters()


{
//Create a factory.
ISpatialReferenceFactory2 spatialReferenceFactory = new SpatialReferenceEnvironmentClass();

//Create a projection, GeographicCoordinateSystem, and unit using the factory.
IProjectionGEN projection = spatialReferenceFactory.CreateProjection((int)esriSRProjectionType.esriSRProjection_Sinusoidal) as IProjectionGEN;
IGeographicCoordinateSystem geographicCoordinateSystem = spatialReferenceFactory.CreateGeographicCoordinateSystem((int)
esriSRGeoCSType.esriSRGeoCS_WGS1984);
ILinearUnit unit = spatialReferenceFactory.CreateUnit((int)esriSRUnitType.esriSRUnit_Meter) as ILinearUnit;

//Get the default parameters from the projection.
IParameter[] parameters = projection.GetDefaultParameters();

//Iterate through the parameters and print out their name and value.
for (int i = 0; i < parameters.Length; i++)

{
IParameter currentParameter = parameters[i];
if (currentParameter != null)

{
System.Windows.Forms.MessageBox.Show(currentParameter.Name + ", " + currentParameter.Index + ", " + currentParameter.Value);
}
}

//Reset one of the parameter values.
IParameter parameter = parameters[2];
parameter.Value = 45;

//Create a projected coordinate system using the Define method.
IProjectedCoordinateSystemEdit projectedCoordinateSystemEdit = new ProjectedCoordinateSystemClass();
object name = "Newfoundland";
object alias = "NF_LAB";
object abbreviation = "NF";
object remarks = "Most Eastern Province in Canada";
object usage = "When making maps of Newfoundland";
object geographicCoordinateSystemObject = geographicCoordinateSystem as object;
object unitObject = unit as object;
object projectionObject = projection as object;
object parametersObject = parameters as object;

projectedCoordinateSystemEdit.Define(ref name,
ref alias,
ref abbreviation,
ref remarks,
ref usage,
ref geographicCoordinateSystemObject,
ref unitObject,
ref projectionObject,
ref parametersObject);

IProjectedCoordinateSystem4GEN projectedCoordinateSystem = projectedCoordinateSystemEdit as IProjectedCoordinateSystem4GEN;

//Get the parameters from your new projected coordinate system and verify
//that the parameter value was changed.
//Create an array of IParameters with 16 elements.
IParameter[] newParameters = new IParameter[16];

//Get the parameters.
projectedCoordinateSystem.GetParameters(ref newParameters);

//Iterate through the parameters and print out their name and value.
for (int i = 0; i < newParameters.Length; i++)

{
IParameter currentNewParameter = newParameters[i];
if (currentNewParameter != null)

{
System.Windows.Forms.MessageBox.Show(currentNewParameter.Name + ", " + currentNewParameter.Index + ", " + currentNewParameter.Value);
}
}
}
具體的可以設置每一個參數,精確定義空間參考。
可以看到,關于Spatial Reference編程與實現無非就是在幾個接口之間實現,了解了這幾個接口及它們之間的聯系(參考GeometryObjectModel.pdf文檔),也就了解了Spatial Reference編程的方法,當然基礎是地理空間參考的基本理論知識。