Skip to content

Instantly share code, notes, and snippets.

@sanvarie
Created March 25, 2016 01:07
Show Gist options
  • Save sanvarie/51bcdd9e1668081bde75 to your computer and use it in GitHub Desktop.
Save sanvarie/51bcdd9e1668081bde75 to your computer and use it in GitHub Desktop.
Basicライセンスでも使用できる頂点の間引き処理です
# -*- coding: utf-8 -*-
import arcpy
import math
class Generalize(object):
def __init__(self,workspace,in_feature,out_feature):
arcpy.env.workspace = workspace
self.workspace = workspace
self.in_feature = in_feature
self.out_feature = out_feature
self.generalize_list = list()
self.check_feature_class()
def check_feature_class(self):
"""out_featureに指定したフィーチャクラスが無い場合、作成します"""
exist_out_feature = arcpy.ListFeatureClasses(self.out_feature)
if len(exist_out_feature) == 0:
try:
print u"フィーチャクラスを作成します"
arcpy.CreateFeatureclass_management(self.workspace, self.out_feature, "POLYLINE")
except Exception:
u"フィーチャクラスの作成に失敗しました"
def set_generalize_list(self):
"""角度と距離から削除対象の頂点か判定してリストに格納する
self.generalize_list --ラインの始点終点などの情報
[0]:OBJECTID
[1]:X
[2]:Y
[3]:始点X
[4]:終点X
[5]:削除対象区分 0:削除対象,1:始点で削除非対称,2:終点で削除非対称
[6]:ポイントジオメトリ
[7]:角度
[8]:距離
"""
for i,pt in enumerate(self.generalize_list):
#削除対象のポイントの場合
if pt[5] == 0:
#角度計算用に対象の頂点とその前後の頂点の角度を取得する
angle_first = self.generalize_list[i-1][7]
angle_next = pt[7]
angle_last = self.generalize_list[i+1][7]
#対象の頂点とその前後のポイントの角度の差が1以下、かつ、対象の頂点間の長さが1以上の場合
if math.fabs(math.fabs(angle_first) - math.fabs(angle_next)) <= 1 \
and math.fabs(math.fabs(angle_next) - math.fabs(angle_last)) <= 1 and pt[8] >= 1:
self.generalize_list[i].append(1)
else:
self.generalize_list[i].append(0)
else:
self.generalize_list[i].append(0)
def calc_angle_length(self):
"""各頂点の角度や長さなどを計算する関数し、計算結果をリストに格納する関数
self.generalize_list --ラインの始点終点などの情報
[0]:OBJECTID
[1]:X
[2]:Y
[3]:始点X
[4]:終点X
[5]:削除対象区分 0:削除対象,1:始点で削除非対称,2:終点で削除非対称
[6]:ポイントジオメトリ
[7]:角度
[8]:距離
[9]:削除対象区分2 0:削除対象外,1:削除 ←[5]はこれを抽出する前段階のもの
"""
x2,y2,pg = float(),float(),object()
generalize_list2 = list()
for i,pt in enumerate(self.generalize_list):
#始点、終点でもない場合
if pt[5] == 0:
#角度を計算
result = math.atan2(pt[2]-y2,pt[1]-x2)
#角度をセット
self.generalize_list[i].append(math.degrees(result))
#距離をセット
self.generalize_list[i].append(pt[6].distanceTo(pg))
#始点の場合
elif pt[5] == 1:
#角度を計算
result = math.atan2(pt[2]-self.generalize_list[i+1][2],pt[1]-self.generalize_list[i+1][1])
#角度をセット
if math.degrees(result) < 0:
self.generalize_list[i].append(math.degrees(result) + 180)
else:
self.generalize_list[i].append(math.degrees(result) - 180)
#距離は0でOK
self.generalize_list[i].append(0)
#終点の場合
elif pt[5] == 2:
#角度を計算
result = math.atan2(pt[2]-generalize_list2[i-1][2],pt[1]-generalize_list2[i-1][1])
#角度をセット
if math.degrees(result) < 0:
self.generalize_list[i].append(math.degrees(result))
else:
self.generalize_list[i].append(math.degrees(result))
#距離は0でOK
self.generalize_list[i].append(0)
generalize_list2.append(self.generalize_list[i])
x2,y2,pg = pt[1],pt[2],pt[6]
#角度と距離から削除対象の頂点か判定
self.set_generalize_list()
def get_point_coord(self):
"""ラインの頂点ごとの情報をリストに格納する"""
lines = [row for row in arcpy.da.SearchCursor(self.in_feature, ["OID@","SHAPE@"])]
#頂点ごとにOID、X、Y、始点、終点の情報を格納する
for line in lines:
for parts in line[1]:
for part in parts:
self.generalize_list.append([line[0],part.X,part.Y,line[1].firstPoint.X,line[1].lastPoint.X])
def calc_first_last(self):
"""各頂点が始点なのか終点なのかそれ以外なのか(削除対象)を判定する関数 """
for i,pt in enumerate(self.generalize_list):
#対象のポイントのXが始点の場合
if pt[1] == pt[3]:
#始点で削除非対象
self.generalize_list[i].append(1)
elif pt[1] == pt[4]:
#終点で削除非対象
self.generalize_list[i].append(2)
else:
#削除対象
self.generalize_list[i].append(0)
def calc_point_distance(self):
"""各種関数を呼び出し、self.generalize_listに要素を追加していく"""
#ラインの頂点ごとの情報を取得
self.get_point_coord()
#各頂点の始点終点それ以外を判定
self.calc_first_last()
#頂点のジオメトリ情報を取得
self.create_point_geometry()
#頂点の角度と長さの計算
self.calc_angle_length()
#削除対象の頂点を間引いてラインを作図する
self.generalize_line()
def generalize_line(self):
"""頂点を間引いてラインを作図する関数
self.generalize_list --ラインの始点終点などの情報
[0]:OBJECTID
[1]:X
[2]:Y
[3]:始点X
[4]:終点X
[5]:削除対象区分 0:削除対象,1:始点で削除非対称,2:終点で削除非対称
[6]:ポイントジオメトリ
[7]:角度
[8]:距離
[9]:削除対象区分2 0:削除対象外,1:削除 ←[5]はこれを抽出する前段階のもの
"""
oid = int()
array = arcpy.Array()
with arcpy.da.InsertCursor(self.out_feature, ["OID@", "SHAPE@"]) as cur:
for i,pt in enumerate(self.generalize_list):
#OBJECTIDが次に行ったタイミングでラインを作図する。
if pt[0] != oid and i != 0:
cur.insertRow((oid,arcpy.Polyline(array)))
array = arcpy.Array()
array.add(arcpy.Point(pt[1], pt[2]))
else:
#削除対象の頂点ではない場合のみ頂点の情報を格納していく
if pt[9] != 1:
array.add(arcpy.Point(pt[1], pt[2]))
oid = pt[0]
cur.insertRow((oid,arcpy.Polyline(array)))
def create_point_geometry(self):
"""ポイントジオメトリを作成してリストに格納"""
point = arcpy.Point()
for i,pt in enumerate(self.generalize_list):
point.X = pt[1]
point.Y = pt[2]
self.generalize_list[i].append(arcpy.PointGeometry(point))
if __name__ == '__main__':
#対象のgdb
workspace = r"C:\ArcPySample\Generalize.gdb"
#間引き元のフィーチャクラス名
in_feature = "Line"
#間引き先のフィーチャクラス名
out_feature = "LineGeneralize"
#インスタンス化
generalize = Generalize(workspace,in_feature,out_feature)
#頂点を間引く
generalize.calc_point_distance()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment