久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Python和ArcGIS自動(dòng)化制圖完全指南(三):分配模板 v3

 GIS薈 2021-09-19
前言:在《指南》第二章中,,我們制作了3種不同尺寸的 mxd 模板,就是為了適配不同的制圖單位,,比如適配自貢市的 mxd 模板就不適用于廣元市(廣元市面積大),。而如何讓計(jì)算機(jī)給不同制圖單位分配大小合適的模板就是本章需要解決的問題 。



1.模板信息標(biāo)準(zhǔn)化

根據(jù)第二章制作的 mxd 模板文件的名字生成標(biāo)準(zhǔn)化的匹配信息,,該信息可以輔助程序?qū)γ恳粋€(gè)制圖單位匹配大小合適的 mxd 模板,。

為什么要將模板信息標(biāo)準(zhǔn)化?
因?yàn)槌绦驘o法知道你做的 mxd 模板的大小是多少,,也不知道不同的模板對(duì)應(yīng)的是哪個(gè)大小,。
所以我們要將模板信息存進(jìn)程序中,讓程序知道有這么一個(gè)模板,。
你可以在程序運(yùn)行前輸入每一個(gè)模板的名稱及其對(duì)應(yīng)的大小,,但是這太麻煩了,如果有很多模板呢,?如果你輸入錯(cuò)誤呢,?
所以我們要讓電腦自己知道模板的大小,這就需要我們嚴(yán)格按照我們第二章的規(guī)定:mxd 模板命名按 寬x高.mxd 來,。
比如:1080x700.mxd,、1080x1300.mxd,、1180x900.mxd(單位是毫米),。
程序會(huì)自動(dòng)識(shí)別、收集寬度和高度數(shù)據(jù),,減少人工操作,。

之后收集到的信息樣式如下,它表示 pagesize1 這個(gè)英文字符表示大小1080和700,;pagesize2 表示1080和1300,;pagesize3 表示1180和900。

{
   "pagesize1":(1080,700),
   "pagesize2":(1080,1300),
   "pagesize3":(1180,900)
}
Note: 有 Python 編程基礎(chǔ)的讀者看到這里就不會(huì)陌生啦,,這里的匹配信息就是 Python中 的一種數(shù)據(jù)結(jié)構(gòu):字典,。

根據(jù)輸入文件夾中的模板名稱,來生成上述標(biāo)準(zhǔn)匹配信息的代碼 C1 (../main/part1.py)如下:
# -*- coding:utf-8 -*-
# ----------------------------------------------------------
# Author: LiaoChenchen
# Created on: 2021/1/29 17:34
# ----------------------------------------------------------
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
import arcpy
import os
from os.path import splitext as st
from os import listdir as ld

def size_creator(path):
   """
  根據(jù)輸入的模板文件地址生成標(biāo)準(zhǔn)格式的字典,。
  :param path: {String} mxd file path
  :return:
  """
   print("請(qǐng)確保模板文件夾中不存在無關(guān)文件,!")
   m_dict = {}
   counter = 1
   for m_name in [st(x)[0] for x in ld(path) if ".mxd" or ".MXD" in x]:
       width, height = m_name.split("x")
       name = "pagesize{}".format(counter)
       m_dict[name] = (int(width), int(height))
       counter+=1
   return m_dict

最后返回的 m_dict 就是標(biāo)準(zhǔn)化后的匹配信息,程序后面會(huì)用到,。



2.最小邊界幾何

現(xiàn)在我們知道了模板的大小,,接下來肯定是獲取制圖單位的大小,。這樣才能互相適配。
比如下圖有17個(gè)地級(jí)市,,也是17個(gè)制圖單位,,如何知道它們的寬邊和長(zhǎng)邊呢?


那么可以使用最小邊界幾何工具來幫助我們確定,。
最小邊界幾何——面積最小的情況下,,能完全覆蓋多邊形的封閉面。如下圖的所示:淺綠色框就是每一個(gè)制圖單位的最小矩形邊界幾何,。


生成最小邊界幾何可以直接計(jì)算出長(zhǎng)邊和短邊,,
通過調(diào)用 ArcPy 方法 arcpy.MinimumBoundingGeometry_management 可以計(jì)算生成最小邊界幾何圖層,該圖層自帶兩個(gè)字段,,即 MBG_Width 和 MBG_Length 字段,,前者表示短邊,后者表示長(zhǎng)邊,。

Note: 該工具位于 數(shù)據(jù)管理工具->要素->最小邊界幾何,;

官方在線文檔:
https://desktop./zh-cn/arcmap/10.3/tools/data-management-toolbox/minimum-bounding-geometry.htm

使用 MappingIndex 圖層生成最小邊界幾何及其相關(guān)操作的代碼 C2 (../main/part1.py)如下:
# -*- coding:utf-8 -*-
# ----------------------------------------------------------
# Author: LiaoChenchen
# Created on: 2021/1/29 17:34
# ----------------------------------------------------------
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
import arcpy
import os
from os.path import splitext as st
from os import listdir as ld

"""_______global_values_______"""
# 地址
mxd_template = "tempMXDS"  # 模板文件位置
output_dir = "out"  # 制圖輸出位置
gdb_path = "arcpy指南.gdb"  # 數(shù)據(jù)庫(kù)地址
# 重要常量
FIELD = "CITY" # 檢索字段
MI = "MappingIndex" # 制圖索引文件名稱
SCALE = 200000 # 制圖的比例尺
"""_______global_values_______"""

arcpy.env.overwriteOutput = True
arcpy.env.workspace = gdb_path

def check_field(layer, field):
   """
  檢查一個(gè)要素文件中是否存在field字段
  """
   fields = arcpy.ListFields(layer)
   return field in [_.name for _ in fields]


class PageSizeMatch(object):
   """
  適配頁(yè)面大小
  """
   def __init__(self, feature_name, field, mxd_template_d):
       """
      :param feature_name: {String} # 制圖索引圖層的名字
      :param field: {String} field = "CITY" # 檢索字段
      :param mxd_template_d: {Dict} 模板匹配信息(字典)
      """
       self.f = feature_name # 制圖索引圖層的名字
       self.field = field
       self.m_d = mxd_template_d
       self.minimum_bounding() # 制作最小幾何邊界圖層
       true_height = self.check_width_height() # 獲取真實(shí)的高度信息
       # 將高度信息更新入制圖索引圖層(MappingIndex)
       self.update_width_height(true_height)
       self.update_page_size(SCALE)
       
   
   def minimum_bounding(self):
       """
      1.make MinimumBoundingGeometry feature layer
      2.add PAGRSIZE field
      :return:
      """
       if not check_field(MI,"MBG_Width"): #?注釋1?
           #?注釋2?
           mbe = arcpy.MinimumBoundingGeometry_management
           mbe(self.f, "m_out", "ENVELOPE", "LIST", self.field, True)
           print("Complete MinimumBoundingGeometry")
           arcpy.Delete_management(self.f,"FeatureClass")#?注釋3?
           arcpy.Rename_management("m_out",self.f,"FeatureClass")
           
       if not check_field(self.f,"PAGESIZE"): #?注釋4?
           # 沒有計(jì)算過最小幾何邊界
           print('Add field PAGESIZE')
           arcpy.AddField_management(
               self.f, "PAGESIZE", "TEXT", field_length = 100)

由于該代碼是從完整代碼剪切下來的,所以有一部分暫時(shí)無關(guān)的代碼片段,。
我們先看 check_field minimum_bounding  方法。
前者位于上述代碼片段的前部分,,用于檢查一個(gè)矢量要素文件中是否存在某個(gè)字段,。
后者位于上述代碼片段的最后,用于計(jì)算生成最小邊界幾何及其相關(guān)操作,。

?注釋1?:
使用了自定義 check_field 方法檢查 MappingIndex (關(guān)于該圖層的來歷請(qǐng)看《指南》第二章) 是否有 MBG_Width 字段,,因?yàn)樯傻淖钚∵吔鐜缀螆D層會(huì)自動(dòng)創(chuàng)建 MBG_Width 字段。
所以能通過檢查字段來確認(rèn)是否已經(jīng)執(zhí)行了 minimum_bounding 方法,,生成了最小邊界幾何圖層,。

?注釋2?:
Python 中函數(shù)也是對(duì)象,,我們使用一個(gè)較簡(jiǎn)短的變量 mbe 來指向 arcpy.MinimumBoundingGeometry_management 方法的內(nèi)存地址,,然后使用 mbe () 來執(zhí)行該函數(shù),。
避免一行代碼寫的過長(zhǎng)。

?注釋3?:
替換圖層。
先將原 MappingIndex 矢量文件刪除,,然后將生成的最小邊界幾何矢量數(shù)據(jù)重命名為 “MappingIndex”。以此實(shí)現(xiàn)對(duì) mxd 模板文件中 MappingIndex 圖層的替換(將其源文件換為最小邊界幾何圖層),。

?注釋4?:
添加字段 PAGESIZE,。


執(zhí)行完上述操作后,重新打開 MappingIndex 的屬性表1:
表1

Note:MBG_Width 和 MBG_Length 的單位為米,。



3.更新MBG_WidthMBG_Length 字段

——將 MBG_Width 和 MBG_Length 字段更新為寬和高的關(guān)系,!
經(jīng)過第二步,我們獲取了各個(gè)制圖單位的短邊(MBG_Width)和長(zhǎng)邊(MBG_Length),。從表1可以看到每一個(gè)制圖單位的 MBG_Width 都大于 MBG_Length,。
但是僅僅通過短邊、長(zhǎng)邊是無法完全區(qū)分出地圖形狀的,。
無法區(qū)分出橫臥狀和長(zhǎng)條狀,,如下所示。你能分出下面那個(gè)圖形是正確的嗎,?只根據(jù)短邊和長(zhǎng)邊信息的話,,下面兩種都是正確的。但是答案只有一個(gè),。
分不清這兩種情況的話,,自然也無法分配大小比例適合的 mxd 模板。


所以只有知道短邊是高還是寬的時(shí)候,,才能知道那個(gè)是正確的,。

如何得知短邊是高還是寬呢?
將面轉(zhuǎn)成點(diǎn)的時(shí)候,,一個(gè)矩形會(huì)生成5個(gè)點(diǎn),,五個(gè)點(diǎn)分別是 右下角點(diǎn)、右上角點(diǎn),、左上角點(diǎn),、左下角點(diǎn),、右下角點(diǎn)(和第一點(diǎn)重疊),。右下角點(diǎn)、右上角點(diǎn) 兩點(diǎn) y 坐標(biāo)的差值就是該矩形的高,。
如果該差值等于 MBG_Width 字段值,,那么短邊就是高,上圖第二種情況是正確的,。反之,,差值等于 MBG_Length 字段值,長(zhǎng)邊是高,那么第一種情況是正確的,。

要素折點(diǎn)轉(zhuǎn)點(diǎn)通過 ArcPy 中的 FeatureVerticesToPoints_management 方法實(shí)現(xiàn),。

識(shí)別出高和寬的代碼 C3 (../main/part1.py)如下:
# -*- coding:utf-8 -*-
# ----------------------------------------------------------
# Author: LiaoChenchen
# Created on: 2021/1/29 17:34
# ----------------------------------------------------------
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
import arcpy
import os
from os.path import splitext as st
from os import listdir as ld


class PageSizeMatch(object):
   
   """
  ... 省略部分代碼
  """

   def check_width_height(self): #?注釋1?
       # 使用 “要素折點(diǎn)轉(zhuǎn)點(diǎn)要素” 工具,將最小邊界幾何轉(zhuǎn)變成點(diǎn),;
       # 每個(gè)最小邊界幾何都會(huì)生成5個(gè)點(diǎn):左下,,左上,右上,,右下,,左下
       # 前兩個(gè)點(diǎn)的差值就是高度
       # 返回值為高度的字典:{地級(jí)市名稱:高度}
       fea_v = "feature_vertices" # feature name
       short_f = arcpy.FeatureVerticesToPoints_management
       short_f(self.f, fea_v, "ALL")
       cursor = arcpy.da.SearchCursor(fea_v, [self.field, "SHAPE@Y"])
       cursor2l = [(x[0],x[1]) for x in cursor] # 轉(zhuǎn)換成列表
       del cursor
       #?注釋2?
       cursor2l_1, cursor2l_2 = cursor2l[::5], cursor2l[1::5]
       height_info = {}
       for i in xrange(len(cursor2l_1)):#?注釋2?
           height = cursor2l_2[i][1] - cursor2l_1[i][1]
           height_info[cursor2l_2[i][0]] = abs(height)
       return height_info
   
   
   #?注釋4?
   def update_width_height(self, height_infomation):
       """
      該方法將 "MBG_Width","MBG_Length"兩字段更新為寬和高
      :param height_infomation: {Dict} 包含了制圖單位的高度信息
      :return:
      """
       _field = [self.field,"MBG_Width", "MBG_Length"]
       with arcpy.da.UpdateCursor(self.f, _field) as cursor:
           for row in cursor:
               name, width, height = row
               #?注釋5?
               if round(height_infomation[name], 2)==round(width, 2):
                   row[1] = height
                   row[2] = width
               cursor.updateRow(row)
       print("update width&height completly!")


省略了 PageSizeMatch 類中 C2 代碼部分。

?注釋1?:
check_width_height 使用 “要素折點(diǎn)轉(zhuǎn)點(diǎn)要素” 工具,,將最小邊界幾何轉(zhuǎn)變成點(diǎn),。
該方法完成要素折點(diǎn)轉(zhuǎn)點(diǎn)的工作,同時(shí)計(jì)算出每個(gè)制圖單元的高是多少,。

?注釋2?:
每個(gè)矩形都會(huì)生成5個(gè)按順序排列的點(diǎn),,cursor2l[::5] 使用切片每隔5個(gè)數(shù)取第一個(gè);cursor2l[1::5] 使用切片每隔5個(gè)數(shù)取第二個(gè),。

?注釋3?:
這個(gè) for 循環(huán)是將 y 軸差值和制圖單位名稱組合成字典,。

?注釋4?:
height_infomation 形參接收上面 check_width_height 方法的返回值。該方法會(huì)把 MappingIndex 圖層中的 MBG_Width 和 MBG_Length 的值分別更新為寬和高,。

?注釋5?:
如果短邊等于高度,,字段 MBG_Width 和 MBG_Length 的意義從原來的短邊和長(zhǎng)邊變成寬和高,那么原來 MBG_Width 和 MBG_Length 的值就需要互換,。


更新后的效果:
MappingIndex 圖層屬性表如下表所示:
表2

把表2和表1進(jìn)行比較,,可以發(fā)現(xiàn)不少城市的 MBG_Width 的 MBG_Length 都發(fā)生了互換。比如自貢市

自貢市邊界圖:自貢市明顯呈橫臥狀,,寬大于高



4.更新PAGESIZE

順利完成本章前3步后,,下一步就是更新 PAGESIZE 字段。


在第一部分,,我們獲得了 mxd 模板的信息,。
在二、三部分,,成功獲得了各個(gè)制圖單位的準(zhǔn)確寬,、高數(shù)據(jù)。
那么接下來就是將這兩套數(shù)據(jù)相比較,,給每個(gè)制圖單位分配大小合適的 mxd 模板,。
最后將匹配結(jié)果儲(chǔ)存到 PAGESIZE 字段。

實(shí)現(xiàn)匹配和 PAGESIZE 字段更新的代碼 C4 (../main/part1.py)如下:
# -*- coding:utf-8 -*-
# ----------------------------------------------------------
# Author: LiaoChenchen
# Created on: 2021/1/29 17:34
# ----------------------------------------------------------
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
import arcpy
import os
from os.path import splitext as st
from os import listdir as ld


def select_template_size(size, template_size):
   """
  :param size: 寬和高組成的列表
  such as:[659.8490915000066, 822.3146429999917]
  :param template_size: 制圖模板大小
  :return: 返回制圖模板大小的名稱(鍵),,
  如果找不到適合的制圖模板就返回 -1
  """
   
   map_w, map_h = size[0], size[1]
   map_div = map_w / map_h
   # 符合該制圖單位的模板大小的字典
   template_size_fit = {
       k:(v[0], v[1], v[0]*v[1], v[0]/v[1]) for k,v
       in template_size.items() if v[0]>map_w and v[1]>map_h
  } #?注釋6?
   d_len = len(template_size_fit)
   # 字典轉(zhuǎn)列表
   d2l = zip(template_size_fit.keys(), template_size_fit.values())
   # 按元組中第三個(gè)數(shù)大小排序(按面積大?。?/span>
   d2l_sorted = sorted(d2l, key=lambda x: x[1][2])
   if d_len > 2: #?注釋7?
       two_remaind = d2l_sorted[:2]
       # (u'pagesize3', (1380, 850, 1173000, 1.6235294117647059))
       res = min(two_remaind, key=lambda x: abs(x[1][3]-map_div))
       return res[0] # u'pagesize3'
   elif d_len==2:
       res = d2l_sorted[0]
       return res[0]
   elif d_len==1:
       return d2l_sorted[0][0]
   else:
       # info="存在超出頁(yè)面大小的制圖單位"
       return -1
   
   
class PageSizeMatch(object):
   """
  ... 省略部分代碼
  """
   
   def update_page_size(self,scale):
       """
      更新填充字段 "PAGESIZE" 的值
      :param scale: {Int} 比例大小
      :return:
      """
       _field = ["MBG_Width", "MBG_Length", "PAGESIZE"]
       with arcpy.da.UpdateCursor(self.f, _field) as cursor:
           for row in cursor:
               row_p = [row[0], row[1]]
               new_row = [x/scale*1000 for x in row_p]
               # PAGESIZE1 or -1
               pgs_name = select_template_size(new_row, self.m_d)
               if pgs_name != -1:
                   p_size = self.m_d[pgs_name] # (1180, 900)
                   # update PAGESIZE field values 1180x900
                   #?注釋8?
                   row[2] = "{}x{}".format(p_size[0],p_size[1])
               else:
                   print("存在超出所有模板頁(yè)面大小的制圖單位")
               cursor.updateRow(row)
       print("update PAGESIZE completly!")

類方法 update_page_size 則用于更新 PAGESIZE 字段,。
具體的匹配方式是由 select_template_size 方法來實(shí)現(xiàn)。該方法接收兩個(gè)參數(shù),,一個(gè)寬和高組成的列表(單位毫米),,另一個(gè)參數(shù)就是第一步獲得的模板標(biāo)準(zhǔn)化信息(字典)。

其內(nèi)部的思路是:首先篩選出可以容下制圖單位的 mxd 模板,。
如果滿足條件的 mxd 模板大于三個(gè),,在?注釋7?中你可以看到,這時(shí)就會(huì)啟用 面積 指標(biāo),,按大小排序,,取最小的兩個(gè)模板。
再使用 寬高比例 指標(biāo),,從兩個(gè)模板中選出 寬高比例 最接近制圖單位的 mxd 模板,。

?注釋6?:
字典推導(dǎo)式,生成如這樣的字典:{... , "達(dá)州市" : (寬,, 高,,面積大小,寬高比例)  , ...},。
... v[0]>map_w and v[1]>map_h...  這段代碼做了初步的篩選,,篩選出滿足該制圖單位寬和高的 mxd模板。同時(shí)這里引入了 面積寬高比例,,這兩個(gè)指標(biāo)用于進(jìn)一步的判斷和篩選,。

?注釋8?:更新 PAGESIZE 字段,其形式如1180x900,。

更新后的 PAGESIZE 字段:

更新后的 PAGESIZE 字段值即是我們?yōu)槊總€(gè)制圖單位分配的模板大小,。


總結(jié)

該章節(jié)主要分為了4部分。

  • 獲取模板數(shù)據(jù)信息,。

  • 使用最小邊界幾何來確認(rèn)長(zhǎng)短邊,。

  • 識(shí)別長(zhǎng)短邊對(duì)應(yīng)的是高還是寬,最終確認(rèn)最小邊界幾何是長(zhǎng)條狀的還是橫臥狀的,。

  • 把每一個(gè)制圖單位寬高與模板標(biāo)準(zhǔn)信息進(jìn)行比較,,最終給每一個(gè)制圖單位選擇合適的模板,其結(jié)果就儲(chǔ)存在 MappingIndex 圖層的 PAGESIZE 字段中,。


那么下一章節(jié)進(jìn)入到使用 ArcPy 控制 mxd 自動(dòng)更新和出圖,。
Note:該章節(jié)完整詳細(xì)代碼見下載文件 ../main/part1.py



結(jié)束語(yǔ)

全套資源免費(fèi)下載:
  • 演示文件數(shù)據(jù)

  • 源代碼

  • 《指南》文檔小冊(cè)子,便于電腦查看

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章