• 【ArcGIS Pro二次开发】(76):面积平差工具


    之前做过一个【三调土地利用现状分类面积汇总】的工具,在流程中使用了面积平差的方法。

    考虑了在其它场合可能也需要进行面积平差,因此单独提取出来作为一个工具。

    平差实现的方法如下图:

    主要的计算过程如上图所示,算出总面积差值后,就开始平差计算。

    平差计算也分2步。

    第一步按比例分配。

    如果还有剩下的未分配值,则再进行第二步按面积由大到小排序分摊。


    一、要实现的功能

     

    如上图所示,在【数据处理】组—【要素综合】面板下,点击【平差工具】工具。

    在弹出的工具框中,分别输入参数:

    1、输入地块要素图层。

    2、输入用来计算面积平差计算字段。必须是可编辑的双精度字段

    3、输入范围图层。这个范围必须和图斑的范围一致,简单的验算方法,两个要素互相擦除得到的是空值。

    4,5,6、面积的几个参数设置。

    生成结果如下:

    汇总统计一下:

    对照一下范围要素计算出来的面积:

    完全一致,完美。


    二、实现流程

    直接上代码。

    代码中存在例如【Arcpy.FeatureToLine(area, area_line);】等代码块,这是预封装好的arcpy地理处理方法,具体写法可以参看:

    【ArcGIS Pro二次开发】(9):GeoProcessing工具和自定义工具的调用-CSDN博客

    1. // 裁剪平差计算
    2. public static string Adjustment(string yd, string area, string clipfc_sort, string area_type = "投影面积", string unit = "平方米", int digit = 2)
    3. {
    4. string def_gdb = Project.Current.DefaultGeodatabasePath;
    5. string area_line = def_gdb + @"\area_line";
    6. string clipfc = def_gdb + @"\clipfc";
    7. string clipfc_sta = def_gdb + @"\clipfc_sta";
    8. string clipfc_updata = def_gdb + @"\clipfc_updata";
    9. // 单位系数设置
    10. double unit_xs = 0;
    11. if (unit == "平方米") { unit_xs = 1; }
    12. else if (unit == "公顷") { unit_xs = 10000; }
    13. else if (unit == "平方公里") { unit_xs = 1000000; }
    14. else if (unit == "亩") { unit_xs = 666.66667; }
    15. // 计算图斑的投影面积和图斑面积
    16. Arcpy.Clip(yd, area, clipfc);
    17. Arcpy.AddField(clipfc, area_type, "DOUBLE");
    18. Arcpy.AddField(area, area_type, "DOUBLE");
    19. if (area_type == "投影面积")
    20. {
    21. Arcpy.CalculateField(clipfc, "投影面积", $"round(!shape_area!/{unit_xs},{digit})");
    22. Arcpy.Statistics(clipfc, clipfc_sta, area_type, ""); // 汇总
    23. // 计算范围的投影面积和图斑面积
    24. Arcpy.CalculateField(area, area_type, $"round(!shape_area!/{unit_xs},{digit})");
    25. }
    26. else if (area_type == "图斑面积")
    27. {
    28. Arcpy.CalculateField(clipfc, area_type, $"round(!shape.geodesicarea!/{unit_xs},{digit})");
    29. Arcpy.Statistics(clipfc, clipfc_sta, area_type, ""); // 汇总
    30. // 计算范围的投影面积和图斑面积
    31. Arcpy.CalculateField(area, area_type, $"round(!shape.geodesicarea!/{unit_xs},{digit})");
    32. }
    33. // 获取投影面积,图斑面积
    34. double mj_fc = double.Parse(GisTool.GetCellFromPath(clipfc_sta, $"SUM_{area_type}", ""));
    35. double mj_area = double.Parse(GisTool.GetCellFromPath(area, area_type, ""));
    36. // 面积差值
    37. double dif_mj = Math.Round(Math.Round(mj_area, digit) - Math.Round(mj_fc, digit), digit);
    38. // 空间连接,找出变化图斑(即需要平差的图斑)
    39. Arcpy.FeatureToLine(area, area_line);
    40. Arcpy.SpatialJoin(clipfc, area_line, clipfc_updata);
    41. Arcpy.AddField(clipfc_updata, "平差", "TEXT");
    42. Arcpy.CalculateField(clipfc_updata, "平差", "''");
    43. // 排序
    44. Arcpy.Sort(clipfc_updata, clipfc_sort, "Shape_Area DESCENDING", "UR");
    45. double area_total = 0;
    46. // 获取Table
    47. using Table table = clipfc_sort.TargetTable();
    48. // 汇总变化图斑的面积
    49. using (RowCursor rowCursor = table.Search())
    50. {
    51. while (rowCursor.MoveNext())
    52. {
    53. using (Row row = rowCursor.Current)
    54. {
    55. var va = int.Parse(row["Join_Count"].ToString());
    56. if (va == 1) // 如果是变化图斑
    57. {
    58. area_total += double.Parse(row[area_type].ToString());
    59. }
    60. }
    61. }
    62. }
    63. // 第一轮平差
    64. double area_pc_1 = 0;
    65. using (RowCursor rowCursor1 = table.Search())
    66. {
    67. while (rowCursor1.MoveNext())
    68. {
    69. using (Row row = rowCursor1.Current)
    70. {
    71. var va = int.Parse(row["Join_Count"].ToString());
    72. if (va == 1)
    73. {
    74. double area_1 = double.Parse(row[area_type].ToString());
    75. // 单个图斑需要平差的值
    76. double area_pc = Math.Round(area_1 / area_total * dif_mj, digit);
    77. area_pc_1 += area_pc;
    78. // 面积平差
    79. row[area_type] = area_1 + area_pc;
    80. }
    81. row.Store();
    82. }
    83. }
    84. }
    85. // 计算剩余平差面积,进行第二轮平差
    86. double area_total_next = Math.Round(dif_mj - area_pc_1, digit);
    87. using (RowCursor rowCursor2 = table.Search())
    88. {
    89. while (rowCursor2.MoveNext())
    90. {
    91. using (Row row = rowCursor2.Current)
    92. {
    93. // 最小平差值
    94. double diMin = Math.Round(Math.Pow(0.1, digit), digit);
    95. var va = int.Parse(row["Join_Count"].ToString());
    96. if (va == 1)
    97. {
    98. double area_2 = double.Parse(row[area_type].ToString());
    99. // 面积平差
    100. if (area_total_next > 0)
    101. {
    102. row[area_type] = area_2 + diMin;
    103. area_total_next -= diMin;
    104. }
    105. else if (area_total_next < 0)
    106. {
    107. row[area_type] = area_2 - diMin;
    108. area_total_next += diMin;
    109. }
    110. row.Store();
    111. }
    112. }
    113. }
    114. }
    115. // 删除中间要素
    116. List<string> all = new List<string>() { "area_line", "clipfc", "clipfc_sta", "clipfc_updata" };
    117. foreach (var item in all)
    118. {
    119. Arcpy.Delect(def_gdb + @"\" + item);
    120. }
    121. // 返回值
    122. return clipfc_sort;
    123. }

    除去前半部分的业务流程。重点在后面的两轮平差计算,需仔细阅读。


    三、工具文件分享

    我把工具都集合成工具箱,不再单独放单个工具,可以到这里下载完整工具箱,会不断更新:

    【ArcGIS Pro二次开发】:CC工具箱icon-default.png?t=N7T8https://blog.csdn.net/xcc34452366/article/details/131506345

  • 相关阅读:
    H - Hot Black Hot White(数论/取模运算)
    【Buildroot】工具包使用
    11-stream流-流水线编码、filter等中间方法、forEach等终止方法、collect获取返回结果方法、lambda练习
    【UOJ 284】快乐游戏鸡(贪心)(长链剖分)(线段树)
    为何开发需要更多地考虑运维便利性
    Linux学习
    java毕业设计房产交易系统Mybatis+系统+数据库+调试部署
    MySQL触发器
    11月VR大数据:SteamVR新增PICO 4串流数据统计
    基于Spring Boot的智能分析平台
  • 原文地址:https://blog.csdn.net/xcc34452366/article/details/134419179