我們都知道投影就是將球面通過一定的規則展開成平面,方便瀏覽和計算,投影就會產生變化,無論是角度、面積還是長度。在實際工作中,經常要計算圖斑面積,這里簡單總結一下常用的計算方法。
面積量算
先來看一下ArcMap中不同坐標系統通過面積量算得到的結果。
情況一:無空間參考,在空白地圖中加載一個沒有定義坐標系統的圖斑(雖然沒有坐標系統,但有坐標值,只不過坐標單位是未知單位),在加入時會彈出"未知的空間參考"的警告。
使用測量工具能夠量算距離和面積,雖然量測值,但是量測單位為未知,當然也就不能切換距離或面積單位了。
情況二:地理坐標。我們將上述圖斑文件定義正確的地理坐標,重新打開一個空白地圖添加定義空間參考后的圖斑文件,發現可以測量距離,坐標單位可以由度(數據本身的單位)切換成平面單位,但無法量測面積。
情況三:投影坐標。我們將上述定義了地理坐標的文件投影成合適的投影坐標(38帶),就可以正常量取距離和面積了。
情況四:不同投影坐標。我們再將上述定義了地理坐標的文件投影另外一個投影帶(30帶),對比可看出它們二者的形變。
通過計算幾何,可看到它們的面積差距是有差距的。
計算幾何和通過!shape.Area!計算的結果都一樣,都是投影面積。
一般地,采用高斯3度投影,相鄰的兩個投影帶計算的面積差距可能幾十到幾百平方不等。因此,這個面積只能是一個粗略值,在一些對面積精度要求比較高的項目中(如承包地)則不能采用投影面積。
橢球面積
那么,更准確一點的就是橢球面積,這里不講橢球面積的計算公式,在二調項目時,國土資源部下發了《關於統一圖幅理論面積與圖斑橢球面積計算要求》的通知,對圖幅理論面積與圖斑橢球面積計算公式進行了細化,明確了面積計算方法,統一了公式中的有關參數,有興趣的可以自行查詢和編程實現。
在ArcMap使用!shape.geodesicArea!即可計算,可以看出,面積1(38帶)更接近橢球面積,而面積2(30帶)則差距很大,因此選擇一個正確的投影非常重要。
值得注意的:
(1)同一個數據,在其地理坐標系統和投影坐標系統下計算的橢球面積有細微差距,原因是投影坐標計算橢球面積時,要先將投影轉換成地理坐標模型,這個轉換會有誤差。
(2)如果需要生成指定單位的橢球面積,可以在后面@單位,如!shape.geodesicArea@SQUAREMETERS!,表示的單位是平方米,如果不定,則是坐標系統的默認單位。
(3)未定義任何坐標系統的數據無法計算橢球面積。
代碼實現
使用Python代碼,利用ArcPy計算:
# 投影面積計算 arcpy.CalculateField_management(fc,"ProjectArea","!shape.Area!","PYTHON_9.3") # 橢球面積計算 arcpy.CalculateField_management(fc,"GeoArea","!shape.geodesicArea@SQUAREKILOMETERS!","PYTHON_9.3")
使用C#代碼,利用ArcObject接口計算:
線接口:IPolycurveGeodetic.LengthGeodetic
面接口:IAreaGeodetic.AreaGeodetic
private void GetArea(IFeatureClass featureClass) { IFeatureCursor featureCursor = featureClass.Search(null, true); IFeature feature = featureCursor.NextFeature(); Console.WriteLine($@"序號 投影面積 正截面 測地線 等角航線 大橢圓面積"); while (feature != null) { IArea area = (IArea)feature.Shape; IAreaGeodetic areaGeodetic = (IAreaGeodetic)feature.Shape; ILinearUnit linearUnit = new LinearUnitClass(); double geodeticArea1 = areaGeodetic.AreaGeodetic[esriGeodeticType.esriGeodeticTypeNormalSection, linearUnit]; double geodeticArea2 = areaGeodetic.AreaGeodetic[esriGeodeticType.esriGeodeticTypeGeodesic, linearUnit]; double geodeticArea3 = areaGeodetic.AreaGeodetic[esriGeodeticType.esriGeodeticTypeLoxodrome, linearUnit]; double geodeticArea4 = areaGeodetic.AreaGeodetic[esriGeodeticType.esriGeodeticTypeGreatElliptic, linearUnit]; Console.WriteLine($@"{feature.OID} {area.Area} {geodeticArea1} {geodeticArea2} {geodeticArea3} {geodeticArea4}"); feature = featureCursor.NextFeature(); } }