GIS奮闘記

現役GISエンジニアの技術紹介ブログ。主にPythonを使用。

【PythonとGIS】ArcPyでラインの端点の角度を取得する

さて、本日はラインの端点の角度を取得しようと思います。ラインの端点にはシンボルを置くことが多いので、端点の角度を取得して、そこにのっかるポイントに角度を与える場合などに使えるかと思います。

環境

Windows7 64bit
ArcGIS10.2
Python2.7.3

事前準備

  1. 対象GDBの作成(今回はGeneralize.gdbを作成しました)
  2. フィーチャクラスの作成(今回はLineを作成しました)

プログラムで取得できる値

対象のフィーチャクラスにおいて、端点の角度を含む以下情報をListで返します。端点以外の頂点の情報は格納しません。

[0]:OBJECTID
[1]:X
[2]:Y
[3]:頂点区分 1:始点 2:終点
[4]:角度

対象データ

以下のようなサンプルデータを作成しました。
f:id:sanvarie:20160322151530p:plain

左から順に作図しました。
f:id:sanvarie:20160322151650p:plain

サンプル

■calcangle.py

# -*- coding: utf-8 -*-
import arcpy
import math

class CalcAngle(object):

    def __init__(self,workspace,in_feature):
        arcpy.env.workspace = workspace
        self.in_feature = in_feature
        self.generalize_list = list()

    def calc_angle(self):
        """各頂点の角度を計算する関数

        self.generalize_list --ラインの始点終点などの情報
                         [0]:OBJECTID
                         [1]:X
                         [2]:Y
                         [3]:頂点区分 1:始点,2:終点
                         [4]:角度
        """

        for i,pt in enumerate(self.generalize_list):

            #始点の場合
            if pt[3] == 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(abs(math.degrees(result)))

                else:

                    self.generalize_list[i].append(abs(math.degrees(result) - 360))

            #終点の場合
            elif pt[3] == 2:

                #角度を計算
                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(abs(math.degrees(result)))

                else:

                    self.generalize_list[i].append(abs(math.degrees(result) -360))

            else:
                self.generalize_list[i].append(0)

    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:
                    #始点の場合
                    if part.X == line[1].firstPoint.X and part.Y == line[1].firstPoint.Y:
                        self.generalize_list.append([line[0],part.X,part.Y,1])
                    #終点の場合
                    elif part.X == line[1].lastPoint.X and part.Y == line[1].lastPoint.Y:
                        self.generalize_list.append([line[0],part.X,part.Y,2])

    def calc_point_distance(self):
        """各種関数を呼び出し、self.generalize_listに要素を追加していく"""

        #始点終点の情報を取得
        self.get_point_coord()

        #頂点の角度の計算
        self.calc_angle()

        return self.generalize_list

if __name__ == '__main__':

    #対象のgdb
    workspace = r"C:\ArcPySample\Generalize.gdb"

    #対象のフィーチャクラス名
    in_feature = "Line"

    #インスタンス化
    generalize = CalcAngle(workspace,in_feature)

    #角度計算
    angle_list = generalize.calc_point_distance()

    print angle_list

実行結果はこのようになりました。
f:id:sanvarie:20160322152039p:plain

OBJECTIDが1のデータで確認すると始点(以下画像の緑丸)の角度=156.1363677663898、終点(以下画像の赤丸)の角度=336.1363677663898 で問題なさそうですね。
f:id:sanvarie:20160322152247p:plain

これを使用すれば端点の角度を利用してそこに接するポイントに角度を付与することができるかと思います。また、これを応用して、各頂点ごとの角度などを取得してもおもしろそうですね。

簡単ではありますが、本日は以上です。