신호생성 repo (24. 1. 5 ~).
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

3180 lines
120 KiB

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np\n",
"import os, sys, copy, argparse, json, pickle\n",
"import sumolib, traci\n",
"from tqdm import tqdm\n",
"from datetime import datetime\n",
"path_root = os.path.dirname(os.path.dirname(os.path.abspath('.')))\n",
"# path_scr = os.path.join(path_root, 'scripts')\n",
"# sys.path.append(path_scr)\n",
"# from preprocess_daily import DailyPreprocessor\n",
"# from generate_signals import SignalGenerator"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class DailyPreprocessor:\n",
" pass\n",
"self = DailyPreprocessor()\n",
"self.config_name = 'test_0729'\n",
"self.file_net = 'new_sungnam_network_internal_target_0721.net.xml'"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# 루트폴더 지정\n",
"self.path_root = path_root\n",
"with open(os.path.join(self.path_root, 'configs', f'config_{self.config_name}.json'), 'r') as config_file:\n",
" config = json.load(config_file)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# 주요 폴더 경로 지정\n",
"self.paths = config['paths']\n",
"self.path_data = os.path.join(self.path_root, *self.paths['data'])\n",
"self.path_intermediates = os.path.join(self.path_root, *self.paths['intermediates'])\n",
"self.path_results = os.path.join(self.path_root, *self.paths['results'])\n",
"self.path_tables = os.path.join(self.path_root, *self.paths['tables'])\n",
"self.path_networks = os.path.join(self.path_root, *self.paths['networks'])\n",
"self.path_scripts = os.path.join(self.path_root, *self.paths['scripts'])\n",
"\n",
"# 이슈사항 목록\n",
"self.issues = []"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# 1-1. 네트워크 불러오기\n",
"self.net = sumolib.net.readNet(os.path.join(self.path_networks, self.file_net))"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['angle.csv',\n",
" 'coord.csv',\n",
" 'inter_info.csv',\n",
" 'inter_node.csv',\n",
" 'nema.csv',\n",
" 'plan.csv',\n",
" 'TC_IF_TOD_DAY_PLAN.csv',\n",
" 'TC_IF_TOD_HOLIDAY_PLAN.csv',\n",
" 'TC_IF_TOD_RED_YELLO.csv',\n",
" 'TC_IF_TOD_WEEK_PLAN.csv',\n",
" 'TL_IF_SIGL_CYCL.csv',\n",
" 'turn_type.csv',\n",
" 'turn_type_modified.csv',\n",
" 'uturn.csv',\n",
" 'u_condition.csv']"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"os.listdir(self.path_tables)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# cnames = []\n",
"# csv_names = list(os.listdir(self.path_tables))\n",
"# for csv_name in csv_names:\n",
"# print(csv_name)\n",
"# try:\n",
"# df = pd.read_csv(os.path.join(self.path_tables, csv_name))\n",
"# except UnicodeDecodeError as e:\n",
"# df = pd.read_csv(os.path.join(self.path_tables, csv_name), encoding='cp949')\n",
"# cnames.extend(list(df.columns))\n",
"# print(list(df.columns))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# 1-2. 테이블 불러오기\n",
"self.alphs = ['A', 'B']\n",
"\n",
"loading_dtype_1 = {'CRSRD_ID':int, 'CYCL':int, 'DAY':int,\n",
" 'FRI_PLAN_NO':int, 'HOUR':int, 'LAST_MDFCN_DT':str,\n",
" 'MIN':int, 'MNTH':int, 'MON_PLAN_NO':int,\n",
" 'OFFSET':int, 'PHASE':int, 'PLAN_NO':int,\n",
" 'RINGA_FLOW':int, 'RINGA_MIN_SEC':int, 'RINGA_RED_SEC':int,\n",
" 'RINGA_YELLO_SEC':int, 'RINGB_FLOW':int, 'RINGB_MIN_SEC':int,\n",
" 'RINGB_RED_SEC':int, 'RINGB_YELLO_SEC':int, 'SAT_PLAN_NO':int,\n",
" 'SUN_PLAN_NO':int, 'THU_PLAN_NO':int, 'TUE_PLAN_NO':int,\n",
" 'WED_PLAN_NO':int, 'adj_inc_edge_id':str, 'adj_out_edge_id':str,\n",
" 'angle_code':str, 'child_id':str, 'condition':str,\n",
" 'group_no':str, 'inc_dire':str, 'inc_edge_id':str,\n",
" 'inter_lat':float, 'inter_lon':float, 'inter_name':str,\n",
" 'inter_no':int, 'inter_type':str, 'main_phase_no':str,\n",
" 'move_no':int, 'node_id':str, 'out_dire':str,\n",
" 'out_edge_id':str, 'parent_id':str, 'phase_no':int,\n",
" 'ring_type':str, 'turn_type':str}\n",
"\n",
"loading_dtype_2 = {f'RING{alph}_PHASE{i}':int for alph in self.alphs for i in range(1,9)}\n",
"loading_dtype = {**loading_dtype_1, **loading_dtype_2}\n",
"\n",
"# 수작업으로 만든 테이블 불러오기\n",
"self.inter_node = pd.read_csv(os.path.join(self.path_tables, 'inter_node.csv'), dtype=loading_dtype)\n",
"self.inter_info = pd.read_csv(os.path.join(self.path_tables, 'inter_info.csv'), dtype=loading_dtype)\n",
"self.turn_type = pd.read_csv(os.path.join(self.path_tables, 'turn_type.csv'), dtype=loading_dtype)\n",
"self.uturn = pd.read_csv(os.path.join(self.path_tables, 'uturn.csv'), dtype=loading_dtype)\n",
"self.u_condition= pd.read_csv(os.path.join(self.path_tables, 'u_condition.csv'), dtype=loading_dtype)\n",
"self.coord = pd.read_csv(os.path.join(self.path_tables, 'coord.csv'), dtype=loading_dtype)\n",
"self.nema = pd.read_csv(os.path.join(self.path_tables, 'nema.csv'), dtype=loading_dtype, encoding='cp949')\n",
"self.angle = pd.read_csv(os.path.join(self.path_tables, 'angle.csv'), dtype=loading_dtype)\n",
"\n",
"# DB에서 fetch하는 테이블 불러오기\n",
"self.dayplan = pd.read_csv(os.path.join(self.path_tables, 'TC_IF_TOD_DAY_PLAN.csv'), dtype=loading_dtype)\n",
"self.holyplan = pd.read_csv(os.path.join(self.path_tables, 'TC_IF_TOD_HOLIDAY_PLAN.csv'), dtype=loading_dtype)\n",
"self.weekplan = pd.read_csv(os.path.join(self.path_tables, 'TC_IF_TOD_WEEK_PLAN.csv'), dtype=loading_dtype)\n",
"self.red_yel = pd.read_csv(os.path.join(self.path_tables, 'TC_IF_TOD_RED_YELLO.csv'), dtype=loading_dtype)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# 교차로목록, 노드목록 정의\n",
"self.inter_nos = [int(x) for x in sorted(self.inter_info.inter_no.unique())]\n",
"self.node_ids = sorted(self.inter_node.node_id.unique())"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# cnames = []\n",
"# csv_names = list(os.listdir(self.path_tables))\n",
"# for csv_name in csv_names:\n",
"# print(csv_name)\n",
"# try:\n",
"# df = pd.read_csv(os.path.join(self.path_tables, csv_name))\n",
"# except UnicodeDecodeError as e:\n",
"# df = pd.read_csv(os.path.join(self.path_tables, csv_name), encoding='cp949')\n",
"# cnames.extend(list(df.columns))\n",
"# print(list(df.columns))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['CRSRD_ID', 'PLAN_NO', 'HOUR', 'MIN', 'CYCL', 'OFFSET', 'RINGA_PHASE1', 'RINGA_PHASE2', 'RINGA_PHASE3', 'RINGA_PHASE4', 'RINGA_PHASE5', 'RINGA_PHASE6', 'RINGA_PHASE7', 'RINGA_PHASE8', 'RINGB_PHASE1', 'RINGB_PHASE2', 'RINGB_PHASE3', 'RINGB_PHASE4', 'RINGB_PHASE5', 'RINGB_PHASE6', 'RINGB_PHASE7', 'RINGB_PHASE8', 'LAST_MDFCN_DT']\n",
"['CRSRD_ID', 'MNTH', 'DAY', 'PLAN_NO', 'LAST_MDFCN_DT']\n",
"['CRSRD_ID', 'SUN_PLAN_NO', 'MON_PLAN_NO', 'TUE_PLAN_NO', 'WED_PLAN_NO', 'THU_PLAN_NO', 'FRI_PLAN_NO', 'SAT_PLAN_NO', 'LAST_MDFCN_DT']\n",
"['CRSRD_ID', 'PLAN_NO', 'PHASE', 'RINGA_FLOW', 'RINGA_RED_SEC', 'RINGA_YELLO_SEC', 'RINGA_MIN_SEC', 'RINGB_FLOW', 'RINGB_RED_SEC', 'RINGB_YELLO_SEC', 'RINGB_MIN_SEC', 'LAST_MDFCN_DT']\n"
]
}
],
"source": [
"cnames = []\n",
"tods = [self.dayplan, self.holyplan, self.weekplan, self.red_yel]\n",
"for tod in tods:\n",
" cnames.extend(list(tod.columns))\n",
" print(list(tod.columns))\n",
"cnames = sorted(set(cnames))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"# 1-5. 테이블 표준화\n",
"\n",
"# 컬럼명 변경\n",
"rename_cname_1 = {'CRSRD_ID':'inter_no', 'CYCL':'cycle', 'DAY':'DD',\n",
" 'HOUR':'hh', 'MIN':'mm', 'MNTH':'MM',\n",
" 'OFFSET':'offset', 'PHASE':'phase_no', 'PLAN_NO':'plan_no',\n",
" 'RINGA_RED_SEC':'red_A', 'RINGA_YELLO_SEC':'yel_A', 'RINGB_RED_SEC':'red_B',\n",
" 'RINGB_YELLO_SEC':'yel_B'}\n",
"\n",
"rename_cname_2 = {f'RING{alph}_PHASE{i}':f'dura_{alph}{i}' for alph in self.alphs for i in range(1,9)}\n",
"rename_cname = {**rename_cname_1, **rename_cname_2}\n",
"\n",
"# 컬럼명 변경 적용\n",
"self.dayplan = self.dayplan.rename(columns=rename_cname)\n",
"self.holyplan = self.holyplan.rename(columns=rename_cname)\n",
"self.weekplan = self.weekplan.rename(columns=rename_cname)\n",
"self.red_yel = self.red_yel.rename(columns=rename_cname)\n",
"\n",
"# 날짜 지정\n",
"DT = datetime(2024, 7, 25)\n",
"MM, DD = DT.month, DT.day # 월, 일\n",
"hplan = self.holyplan[(self.holyplan.MM==MM) & (self.holyplan.DD==DD)]\n",
"dow_number = DT.weekday() # 요일\n",
"dows = [dow for dow in self.weekplan.columns if dow.endswith('PLAN_NO')]\n",
"dows = dows[1:] + dows[0:1]\n",
"dow = dows[dow_number]\n",
"\n",
"# (신호교차로, 신호계획번호) 목록\n",
"if len(hplan):\n",
" inter_pnos = list(zip(hplan['inter_no'], hplan['plan_no']))\n",
"else:\n",
" inter_pnos = list(zip(self.weekplan.inter_no, self.weekplan[dow]))"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"# 신호테이블 통합\n",
"self.plan = self.dayplan.copy()\n",
"self.plan['inter_pno'] = list(zip(self.plan['inter_no'], self.plan['plan_no']))\n",
"self.plan = self.plan[(self.plan.inter_pno.isin(inter_pnos))]\n",
"self.plan = self.plan.drop(columns='inter_pno')\n",
"max_phase_no = int(self.red_yel.phase_no.max())\n",
"for j in range(1,max_phase_no+1):\n",
" RY = self.red_yel[self.red_yel.phase_no==j].iloc[0]\n",
" red_A = RY.red_A\n",
" red_B = RY.red_B\n",
" yel_A = RY.yel_A\n",
" yel_B = RY.yel_B\n",
" self.plan[f'red_A{j}'] = red_A\n",
" self.plan[f'red_B{j}'] = red_B\n",
" self.plan[f'yellow_A{j}'] = yel_A\n",
" self.plan[f'yellow_B{j}'] = yel_B"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"# 1-6. 주요 객체 (리스트, 딕셔너리) 저장\n",
"self.parent_ids = sorted(self.inter_node[self.inter_node.inter_type=='parent'].node_id.unique())\n",
"self.child_ids = sorted(self.inter_node[self.inter_node.inter_type=='child'].node_id.unique())\n",
"self.uturn_ids = sorted(self.uturn.child_id.unique())\n",
"self.coord_ids = sorted(self.coord.child_id.unique())\n",
"\n",
"# node2inter : node_id to inter_no\n",
"self.node2inter = dict(zip(self.inter_node['node_id'], self.inter_node['inter_no']))\n",
"\n",
"# inter2node : inter_no to node_id\n",
"inter_node1 = self.inter_node[self.inter_node.inter_type == 'parent'].drop('inter_type', axis=1)\n",
"inter_info1 = self.inter_info[['inter_no', 'inter_lat', 'inter_lon']]\n",
"inter = pd.merge(inter_node1, inter_info1, how='left', left_on=['inter_no'],\n",
" right_on=['inter_no']).drop_duplicates()\n",
"\n",
"self.inter2node = dict(zip(inter['inter_no'], inter['node_id']))\n",
"\n",
"# ch2pa : child to parent\n",
"self.ch2pa = {}\n",
"for child_id in self.child_ids:\n",
" parent_no = self.inter_node[self.inter_node.node_id==child_id].inter_no.iloc[0]\n",
" sub_inter_node = self.inter_node[self.inter_node.inter_no==parent_no]\n",
" self.ch2pa[child_id] = sub_inter_node[sub_inter_node.inter_type=='parent'].iloc[0].node_id\n",
"self.dires = ['북', '북동', '동', '남동', '남', '남서', '서', '북서'] # 정북기준 시계방향으로 8방향\n",
"\n",
"# ids\n",
"self.ids = {'node_ids' : self.node_ids,\n",
" 'parent_ids': self.parent_ids,\n",
" 'child_ids' : self.child_ids,\n",
" 'uturn_ids' : self.uturn_ids,\n",
" 'coord_ids' : self.coord_ids,\n",
" 'inter_nos' : self.inter_nos}\n",
"with open(os.path.join(self.path_intermediates, 'ids.json'), 'w') as file:\n",
" json.dump(self.ids, file)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>inter_no</th>\n",
" <th>phas_A</th>\n",
" <th>phas_B</th>\n",
" <th>move_A</th>\n",
" <th>move_B</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>436</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>5</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>436</td>\n",
" <td>2</td>\n",
" <td>2</td>\n",
" <td>8</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>436</td>\n",
" <td>3</td>\n",
" <td>3</td>\n",
" <td>7</td>\n",
" <td>4</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>436</td>\n",
" <td>4</td>\n",
" <td>4</td>\n",
" <td>6</td>\n",
" <td>1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>437</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>6</td>\n",
" <td>2</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" inter_no phas_A phas_B move_A move_B\n",
"0 436 1 1 5 2\n",
"1 436 2 2 8 3\n",
"2 436 3 3 7 4\n",
"3 436 4 4 6 1\n",
"4 437 1 1 6 2"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 2. 중간산출물 만들기\n",
"# 2-1 매칭테이블 생성\n",
"# 2-1-1\n",
"self.match1 = pd.read_csv(os.path.join(self.path_intermediates, 'match1.csv'))\n",
"self.match1.head()"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>inter_no</th>\n",
" <th>phase_no</th>\n",
" <th>ring_type</th>\n",
" <th>move_no</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>436</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" </tr>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>436</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>436</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>8</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>436</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>3</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>436</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" inter_no phase_no ring_type move_no\n",
"0 436 1 A 5\n",
"0 436 1 B 2\n",
"1 436 2 A 8\n",
"1 436 2 B 3\n",
"2 436 3 A 7"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 2-1-2\n",
"matchA = self.match1[['inter_no', 'phas_A', 'move_A']].copy()\n",
"matchA.columns = ['inter_no', 'phase_no', 'move_no']\n",
"matchA['ring_type'] = 'A'\n",
"matchB = self.match1[['inter_no', 'phas_B', 'move_B']].copy()\n",
"matchB.columns = ['inter_no', 'phase_no', 'move_no']\n",
"matchB['ring_type'] = 'B'\n",
"self.match2 = pd.concat([matchA, matchB]).drop_duplicates()\n",
"self.match2 = self.match2[['inter_no', 'phase_no', 'ring_type', 'move_no']]\n",
"self.match2 = self.match2.sort_values(by=list(self.match2.columns))\n",
"self.match2.head()"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>inter_no</th>\n",
" <th>phase_no</th>\n",
" <th>ring_type</th>\n",
" <th>move_no</th>\n",
" <th>inc_dire</th>\n",
" <th>out_dire</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>436</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>436</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>436</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>8</td>\n",
" <td>남</td>\n",
" <td>북</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>436</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>3</td>\n",
" <td>남</td>\n",
" <td>서</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>436</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" inter_no phase_no ring_type move_no inc_dire out_dire\n",
"0 436 1 A 5 서 북\n",
"1 436 1 B 2 서 동\n",
"2 436 2 A 8 남 북\n",
"3 436 2 B 3 남 서\n",
"4 436 3 A 7 북 동"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 2-1-3\n",
"# nema 정보 불러오기 및 병합\n",
"self.match3 = pd.merge(self.match2, self.nema, how='left', on='move_no').drop_duplicates()\n",
"self.match3.head()"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>inter_no</th>\n",
" <th>move_no</th>\n",
" <th>angle_code</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>438</td>\n",
" <td>6</td>\n",
" <td>100277</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>438</td>\n",
" <td>2</td>\n",
" <td>276098</td>\n",
" </tr>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>438</td>\n",
" <td>5</td>\n",
" <td>274342</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>438</td>\n",
" <td>1</td>\n",
" <td>101181</td>\n",
" </tr>\n",
" <tr>\n",
" <th>20</th>\n",
" <td>438</td>\n",
" <td>8</td>\n",
" <td>183340</td>\n",
" </tr>\n",
" <tr>\n",
" <th>21</th>\n",
" <td>438</td>\n",
" <td>3</td>\n",
" <td>182276</td>\n",
" </tr>\n",
" <tr>\n",
" <th>22</th>\n",
" <td>438</td>\n",
" <td>7</td>\n",
" <td>347099</td>\n",
" </tr>\n",
" <tr>\n",
" <th>23</th>\n",
" <td>438</td>\n",
" <td>4</td>\n",
" <td>348186</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" inter_no move_no angle_code\n",
"16 438 6 100277\n",
"17 438 2 276098\n",
"18 438 5 274342\n",
"19 438 1 101181\n",
"20 438 8 183340\n",
"21 438 3 182276\n",
"22 438 7 347099\n",
"23 438 4 348186"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"node_id = '106350'\n",
"inter_no = self.node2inter[node_id]\n",
"self.angle[self.angle.inter_no==inter_no]"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>inter_no</th>\n",
" <th>phase_no</th>\n",
" <th>ring_type</th>\n",
" <th>move_no</th>\n",
" <th>inc_dire</th>\n",
" <th>out_dire</th>\n",
" <th>inc_angle</th>\n",
" <th>out_angle</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>436</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>262</td>\n",
" <td>358</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>436</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>262</td>\n",
" <td>074</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>436</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>8</td>\n",
" <td>남</td>\n",
" <td>북</td>\n",
" <td>174</td>\n",
" <td>355</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>436</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>3</td>\n",
" <td>남</td>\n",
" <td>서</td>\n",
" <td>172</td>\n",
" <td>263</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>436</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>356</td>\n",
" <td>074</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" inter_no phase_no ring_type move_no inc_dire out_dire inc_angle out_angle\n",
"0 436 1 A 5 서 북 262 358\n",
"1 436 1 B 2 서 동 262 074\n",
"2 436 2 A 8 남 북 174 355\n",
"3 436 2 B 3 남 서 172 263\n",
"4 436 3 A 7 북 동 356 074"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 2-1-4\n",
"# helper dictionaries\n",
"im2inc_angle = dict() # a dictionary that maps (inter_no, move_no) to inc_angle\n",
"im2out_angle = dict() # a dictionary that maps (inter_no, move_no) to out_angle\n",
"self.angle = self.angle.dropna(subset=['move_no'])\n",
"self.angle['move_no'] = self.angle['move_no'].astype(int)\n",
"for row in self.angle.itertuples():\n",
" inter_no = row.inter_no\n",
" move_no = row.move_no\n",
" angle_code = row.angle_code\n",
" if isinstance(angle_code, str) and len(angle_code) == 6:\n",
" im2inc_angle[(inter_no, move_no)] = angle_code[:3]\n",
" im2out_angle[(inter_no, move_no)] = angle_code[3:]\n",
" else:\n",
" im2inc_angle[(inter_no, move_no)] = np.nan\n",
" im2out_angle[(inter_no, move_no)] = np.nan\n",
"for inter_no in self.inter_nos:\n",
" im2inc_angle[(inter_no, 17)] = np.nan\n",
" im2out_angle[(inter_no, 17)] = np.nan\n",
" im2inc_angle[(inter_no, 18)] = np.nan\n",
" im2out_angle[(inter_no, 18)] = np.nan\n",
"\n",
"# 진입, 진출 방위각 매칭\n",
"self.match4 = self.match3.copy()\n",
"for i, row in self.match4.iterrows():\n",
" inter_no = row.inter_no\n",
" move_no = row.move_no\n",
" self.match4.at[i, 'inc_angle'] = im2inc_angle[(inter_no, move_no)]\n",
" self.match4.at[i, 'out_angle'] = im2out_angle[(inter_no, move_no)]\n",
"self.match4.head()"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [],
"source": [
"# 2-1-5\n",
"self.match5 = self.match4.copy()\n",
"# 진입진출ID 매칭\n",
"for index, row in self.match5.iterrows():\n",
" node_id = self.inter2node[row.inter_no]\n",
" node = self.net.getNode(node_id)\n",
" # 교차로의 모든 (from / to) edges\n",
" inc_edges = [edge for edge in node.getIncoming() if edge.getFunction() == ''] # incoming edges\n",
" out_edges = [edge for edge in node.getOutgoing() if edge.getFunction() == ''] # outgoing edges\n",
" # 교차로의 모든 (from / to) unit vector\n",
" inc_vecs = []\n",
" for inc_edge in inc_edges:\n",
" start = inc_edge.getShape()[-1]\n",
" end = inc_edge.getShape()[-2]\n",
" inc_vec = np.array(end) - np.array(start)\n",
" inc_vec = inc_vec / (inc_vec ** 2).sum() ** 0.5\n",
" inc_vecs.append(inc_vec)\n",
" out_vecs = []\n",
" for out_edge in out_edges:\n",
" start = out_edge.getShape()[0]\n",
" end = out_edge.getShape()[1]\n",
" out_vec = np.array(end) - np.array(start)\n",
" out_vec = out_vec / (out_vec ** 2).sum() ** 0.5\n",
" out_vecs.append(out_vec)\n",
" # 진입각, 진출각 불러오기\n",
" if not pd.isna(row.inc_angle):\n",
" inc_angle = int(row.inc_angle)\n",
" out_angle = int(row.out_angle)\n",
" # 방위각을 일반각으로 가공, 라디안 변환, 단위벡터로 변환\n",
" inc_angle = (90 - inc_angle) % 360\n",
" inc_angle = inc_angle * np.pi / 180.\n",
" inc_vec_true = np.array([np.cos(inc_angle), np.sin(inc_angle)])\n",
" out_angle = (90 - out_angle) % 360\n",
" out_angle = out_angle * np.pi / 180.\n",
" out_vec_true = np.array([np.cos(out_angle), np.sin(out_angle)])\n",
" # 매칭 엣지 반환\n",
" inc_index = np.array([np.dot(inc_vec, inc_vec_true) for inc_vec in inc_vecs]).argmax()\n",
" out_index = np.array([np.dot(out_vec, out_vec_true) for out_vec in out_vecs]).argmax()\n",
" inc_edge_id = inc_edges[inc_index].getID()\n",
" out_edge_id = out_edges[out_index].getID()\n",
" self.match5.at[index, 'inc_edge_id'] = inc_edge_id\n",
" self.match5.at[index, 'out_edge_id'] = out_edge_id\n",
"\n",
"self.match5['node_id'] = self.match5['inter_no'].map(self.inter2node)\n",
"self.match5['node_type'] = 'normal'\n",
"self.match5 = self.match5.sort_values(by=['inter_no','phase_no','ring_type']).reset_index(drop=True)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"# n2io2turn : dictionary that maps node_id to io2turn\n",
"self.n2io2turn = dict()\n",
"for node_id in self.parent_ids:\n",
" turn = self.turn_type[self.turn_type.node_id==node_id]\n",
" io = list(zip(turn.inc_edge_id, turn.out_edge_id))\n",
" # io2turn : dictionary that maps (inc_edge_id, out_edge_id) to turn_type\n",
" io2turn = dict(zip(io, turn.turn_type))\n",
" self.n2io2turn[node_id] = io2turn"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"# turn_type 지정\n",
"for i, row in self.match5.iterrows():\n",
" node_id = row.node_id\n",
" inc_edge_id = row.inc_edge_id\n",
" out_edge_id = row.out_edge_id\n",
" if not (pd.isna(inc_edge_id) and pd.isna(out_edge_id)):\n",
" io2turn = self.n2io2turn[node_id]\n",
" if (inc_edge_id, out_edge_id) in io2turn:\n",
" turn_type = io2turn[(inc_edge_id, out_edge_id)]\n",
" self.match5.at[i, 'turn_type'] = turn_type"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"# 2-1-6\n",
"self.uturn = pd.merge(self.uturn, self.u_condition, on='child_id')\n",
"\n",
"# p2inc_edge2angle : node_id to inc_edge2angle\n",
"p2inc_edge2angle = dict()\n",
"# p2out_edge2angle : node_id to out_edge2angle\n",
"p2out_edge2angle = dict()\n",
"# p2inc_angle2edge : node_id to inc_angle2edge\n",
"p2inc_angle2edge = dict()\n",
"# p2out_angle2edge : node_id to out_angle2edge\n",
"p2out_angle2edge = dict()\n",
"for node_id in self.parent_ids:\n",
" m5 = self.match5[self.match5.node_id==node_id]\n",
" m5 = m5.dropna(subset=['inc_edge_id', 'out_edge_id'])\n",
" # inc_edge2angle : inc_edge_id to inc_angle\n",
" inc_edge2angle = dict(zip(m5.inc_edge_id, m5.inc_angle.astype(int)))\n",
" p2inc_edge2angle[node_id] = inc_edge2angle\n",
" # out_edge2angle : out_edge_id to out_angle\n",
" out_edge2angle = dict(zip(m5.out_edge_id, m5.out_angle.astype(int)))\n",
" p2out_edge2angle[node_id] = out_edge2angle\n",
" # inc_angle2edge : inc_angle to inc_edge_id\n",
" inc_angle2edge = dict(zip(m5.inc_angle.astype(int), m5.inc_edge_id))\n",
" p2inc_angle2edge[node_id] = inc_angle2edge\n",
" # out_angle2edge : out_angle to out_edge_id\n",
" out_angle2edge = dict(zip(m5.out_angle.astype(int), m5.out_edge_id))\n",
" p2out_angle2edge[node_id] = out_angle2edge"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519797' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519796' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519799' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519798' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519801' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519800' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519873' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519874' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '516929' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '517055' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519834' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"C:\\Users\\Uinetworks\\AppData\\Local\\Temp\\ipykernel_17420\\1413052539.py:73: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '519833' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n"
]
}
],
"source": [
"# 각 uturn node에 대하여 (inc_edge_id, out_edge_id) 부여\n",
"cmatches = []\n",
"for row in self.uturn.itertuples():\n",
" parent_id = row.parent_id\n",
" child_id = row.child_id\n",
" condition = row.condition\n",
" inc_edge_id = row.inc_edge_id\n",
" out_edge_id = row.out_edge_id\n",
" adj_inc_edge_id = row.adj_inc_edge_id\n",
" adj_out_edge_id = row.adj_out_edge_id\n",
" \n",
" # match5에서 부모노드id에 해당하는 행들을 가져옴 (cmatch)\n",
" cmatch = self.match5.copy()[self.match5.node_id==parent_id] # match dataframe for a child node\n",
" cmatch = cmatch.sort_values(by=['phase_no', 'ring_type']).reset_index(drop=True)\n",
" cmatch['node_id'] = child_id\n",
" cmatch['node_type'] = 'u_turn'\n",
"\n",
" # 진입엣지 각도\n",
" inc_angle = p2inc_edge2angle[parent_id][adj_inc_edge_id]\n",
"\n",
" # 이격각도\n",
" self.angle_separation = 10\n",
"\n",
" # 진입로 각도 목록\n",
" inc_angles = cmatch.dropna(subset=['inc_angle', 'out_angle']).inc_angle.astype(int).unique()\n",
" inc_angles = np.sort(inc_angles)\n",
" inc_angles = list(inc_angles - 360) + list(inc_angles) + list(inc_angles + 360)\n",
" inc_angles = np.array(inc_angles)\n",
"\n",
" # 보행신호시의 진입로 각도\n",
" inc_angles_left = inc_angles[inc_angles >= inc_angle + self.angle_separation]\n",
" inc_angle_pedes = np.sort(inc_angles_left)[0] % 360\n",
"\n",
" # 보행신호시의 진입로 엣지id\n",
" inc_angle2edge = p2inc_angle2edge[parent_id]\n",
" inc_edge_id_pedes = inc_angle2edge[inc_angle_pedes]\n",
"\n",
" # 진출로 각도 목록\n",
" out_angles = cmatch.dropna(subset=['inc_angle', 'out_angle']).out_angle.astype(int).unique()\n",
" out_angles = np.sort(out_angles)\n",
" out_angles = list(out_angles - 360) + list(out_angles) + list(out_angles + 360)\n",
" out_angles = np.array(out_angles)\n",
"\n",
" # 보행신호시의 진출로 각도\n",
" out_angles_right = out_angles[out_angles <= inc_angle - self.angle_separation]\n",
" out_angle_pedes = np.sort(out_angles_right)[-1] % 360\n",
"\n",
" # 보행신호시의 진출로 엣지id\n",
" out_angle2edge = p2out_angle2edge[parent_id]\n",
" out_edge_id_pedes = out_angle2edge[out_angle_pedes]\n",
"\n",
" # 진입엣지/진출엣지 포함 조건\n",
" inc_true = (cmatch.inc_edge_id==adj_inc_edge_id)\n",
" out_true = (cmatch.out_edge_id==adj_out_edge_id)\n",
"\n",
" # 보행신호시 조건\n",
" pedes_flag = (cmatch.inc_edge_id==inc_edge_id_pedes) & (cmatch.out_edge_id==out_edge_id_pedes)\n",
"\n",
" # 좌회전시 조건\n",
" right_flag = inc_true & (cmatch.turn_type=='left')\n",
"\n",
" # 보행신호이동류(17) 조건\n",
" crosswalk_on = (cmatch.move_no==17) & ~ out_true\n",
"\n",
" # 신호없음이동류(18) 조건\n",
" all_redsigns = (cmatch.move_no==18) & ~ out_true\n",
"\n",
" # 보행신호시/좌회전시 진입/진출 엣지id 배정\n",
" cmatch[['inc_edge_id', 'out_edge_id']] = np.nan\n",
" if condition == \"보행신호시\":\n",
" cmatch.loc[pedes_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
" elif condition == \"좌회전시\":\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
"\n",
" uturn_not_assigned = cmatch[['inc_edge_id','out_edge_id']].isna().any(axis=1).all()\n",
"\n",
" if uturn_not_assigned:\n",
" # 좌회전시\n",
" if right_flag.any():\n",
" cmatch.loc[right_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
" # 보행신호시\n",
" elif pedes_flag.any():\n",
" cmatch.loc[pedes_flag, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
" # 보행신호이동류(17) 발생시\n",
" elif crosswalk_on.any():\n",
" cmatch.loc[crosswalk_on, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
" # 신호없음이동류(18) 발생시\n",
" elif all_redsigns.any():\n",
" cmatch.loc[all_redsigns, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
" # 진출엣지 미포함시\n",
" elif out_true.any():\n",
" cmatch.loc[~ out_true, ['inc_edge_id', 'out_edge_id']] = [inc_edge_id, out_edge_id]\n",
" cmatches.append(cmatch)\n",
"\n",
"# 각 연등교차로(coordination node)에 대하여 (inc_edge_id, out_edge_id) 부여\n",
"self.coord['inter_no'] = self.coord['parent_id'].map(self.node2inter)\n",
"self.coord = self.coord.rename(columns={'child_id':'node_id'})\n",
"self.coord[['inc_dire', 'out_dire', 'inc_angle','out_angle']] = np.nan\n",
"self.coord['move_no'] = 20\n",
"self.coord = self.coord[['inter_no', 'phase_no', 'ring_type', 'move_no', 'inc_dire', 'out_dire', 'inc_angle','out_angle', 'inc_edge_id', 'out_edge_id', 'node_id']]\n",
"self.coord['node_type'] = 'coord'\n",
"\n",
"cmatches = pd.concat(cmatches)\n",
"self.match6 = pd.concat([self.match5, cmatches, self.coord]).drop_duplicates().sort_values(by=['inter_no', 'node_id', 'phase_no', 'ring_type'])\n",
"self.match6 = self.match6.reset_index(drop=True)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>inter_no</th>\n",
" <th>phase_no</th>\n",
" <th>ring_type</th>\n",
" <th>move_no</th>\n",
" <th>inc_dire</th>\n",
" <th>out_dire</th>\n",
" <th>inc_angle</th>\n",
" <th>out_angle</th>\n",
" <th>inc_edge_id</th>\n",
" <th>out_edge_id</th>\n",
" <th>node_id</th>\n",
" <th>node_type</th>\n",
" <th>turn_type</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>52</th>\n",
" <td>443</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>6</td>\n",
" <td>동</td>\n",
" <td>서</td>\n",
" <td>041</td>\n",
" <td>225</td>\n",
" <td>516916</td>\n",
" <td>513863</td>\n",
" <td>108769</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>53</th>\n",
" <td>443</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>221</td>\n",
" <td>043</td>\n",
" <td>513862</td>\n",
" <td>516917</td>\n",
" <td>108769</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>54</th>\n",
" <td>443</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>222</td>\n",
" <td>320</td>\n",
" <td>513862</td>\n",
" <td>518550</td>\n",
" <td>108769</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>55</th>\n",
" <td>443</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>221</td>\n",
" <td>043</td>\n",
" <td>513862</td>\n",
" <td>516917</td>\n",
" <td>108769</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>56</th>\n",
" <td>443</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>321</td>\n",
" <td>039</td>\n",
" <td>518549</td>\n",
" <td>516917</td>\n",
" <td>108769</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>57</th>\n",
" <td>443</td>\n",
" <td>3</td>\n",
" <td>B</td>\n",
" <td>18</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>108769</td>\n",
" <td>normal</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>58</th>\n",
" <td>443</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>6</td>\n",
" <td>동</td>\n",
" <td>서</td>\n",
" <td>041</td>\n",
" <td>225</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109333</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>59</th>\n",
" <td>443</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>221</td>\n",
" <td>043</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109333</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>60</th>\n",
" <td>443</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>222</td>\n",
" <td>320</td>\n",
" <td>519873</td>\n",
" <td>519874</td>\n",
" <td>109333</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>61</th>\n",
" <td>443</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>221</td>\n",
" <td>043</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109333</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>62</th>\n",
" <td>443</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>321</td>\n",
" <td>039</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109333</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>63</th>\n",
" <td>443</td>\n",
" <td>3</td>\n",
" <td>B</td>\n",
" <td>18</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109333</td>\n",
" <td>u_turn</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>64</th>\n",
" <td>455</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>6</td>\n",
" <td>동</td>\n",
" <td>서</td>\n",
" <td>073</td>\n",
" <td>257</td>\n",
" <td>513580</td>\n",
" <td>513581</td>\n",
" <td>109901</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>65</th>\n",
" <td>455</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>255</td>\n",
" <td>076</td>\n",
" <td>513582</td>\n",
" <td>513584</td>\n",
" <td>109901</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>66</th>\n",
" <td>456</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>257</td>\n",
" <td>043</td>\n",
" <td>513136</td>\n",
" <td>513139</td>\n",
" <td>106231</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>67</th>\n",
" <td>456</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>256</td>\n",
" <td>076</td>\n",
" <td>513136</td>\n",
" <td>513137</td>\n",
" <td>106231</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>68</th>\n",
" <td>456</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>6</td>\n",
" <td>동</td>\n",
" <td>서</td>\n",
" <td>074</td>\n",
" <td>258</td>\n",
" <td>513138</td>\n",
" <td>513135</td>\n",
" <td>106231</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>69</th>\n",
" <td>456</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>256</td>\n",
" <td>076</td>\n",
" <td>513136</td>\n",
" <td>513137</td>\n",
" <td>106231</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>70</th>\n",
" <td>456</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>040</td>\n",
" <td>077</td>\n",
" <td>513140</td>\n",
" <td>513137</td>\n",
" <td>106231</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>71</th>\n",
" <td>456</td>\n",
" <td>3</td>\n",
" <td>B</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>040</td>\n",
" <td>077</td>\n",
" <td>513140</td>\n",
" <td>513137</td>\n",
" <td>106231</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>72</th>\n",
" <td>456</td>\n",
" <td>4</td>\n",
" <td>A</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>106231</td>\n",
" <td>normal</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>73</th>\n",
" <td>456</td>\n",
" <td>4</td>\n",
" <td>B</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>106231</td>\n",
" <td>normal</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>74</th>\n",
" <td>456</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>257</td>\n",
" <td>043</td>\n",
" <td>519797</td>\n",
" <td>519796</td>\n",
" <td>109295</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75</th>\n",
" <td>456</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>256</td>\n",
" <td>076</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109295</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>76</th>\n",
" <td>456</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>6</td>\n",
" <td>동</td>\n",
" <td>서</td>\n",
" <td>074</td>\n",
" <td>258</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109295</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>77</th>\n",
" <td>456</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>256</td>\n",
" <td>076</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109295</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>78</th>\n",
" <td>456</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>040</td>\n",
" <td>077</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109295</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>79</th>\n",
" <td>456</td>\n",
" <td>3</td>\n",
" <td>B</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>040</td>\n",
" <td>077</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109295</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>80</th>\n",
" <td>456</td>\n",
" <td>4</td>\n",
" <td>A</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109295</td>\n",
" <td>u_turn</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>81</th>\n",
" <td>456</td>\n",
" <td>4</td>\n",
" <td>B</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109295</td>\n",
" <td>u_turn</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>82</th>\n",
" <td>457</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>6</td>\n",
" <td>동</td>\n",
" <td>서</td>\n",
" <td>076</td>\n",
" <td>260</td>\n",
" <td>513152</td>\n",
" <td>513155</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>83</th>\n",
" <td>457</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>257</td>\n",
" <td>075</td>\n",
" <td>513156</td>\n",
" <td>513151</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>84</th>\n",
" <td>457</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>257</td>\n",
" <td>347</td>\n",
" <td>513156</td>\n",
" <td>513157</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>85</th>\n",
" <td>457</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>1</td>\n",
" <td>동</td>\n",
" <td>남</td>\n",
" <td>075</td>\n",
" <td>166</td>\n",
" <td>513152</td>\n",
" <td>513153</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>86</th>\n",
" <td>457</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>87</th>\n",
" <td>457</td>\n",
" <td>3</td>\n",
" <td>B</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>88</th>\n",
" <td>457</td>\n",
" <td>4</td>\n",
" <td>A</td>\n",
" <td>8</td>\n",
" <td>남</td>\n",
" <td>북</td>\n",
" <td>163</td>\n",
" <td>346</td>\n",
" <td>513154</td>\n",
" <td>513157</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>89</th>\n",
" <td>457</td>\n",
" <td>4</td>\n",
" <td>B</td>\n",
" <td>3</td>\n",
" <td>남</td>\n",
" <td>서</td>\n",
" <td>162</td>\n",
" <td>258</td>\n",
" <td>513154</td>\n",
" <td>513155</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>90</th>\n",
" <td>457</td>\n",
" <td>5</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>343</td>\n",
" <td>079</td>\n",
" <td>513158</td>\n",
" <td>513151</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>91</th>\n",
" <td>457</td>\n",
" <td>5</td>\n",
" <td>B</td>\n",
" <td>4</td>\n",
" <td>북</td>\n",
" <td>남</td>\n",
" <td>344</td>\n",
" <td>164</td>\n",
" <td>513158</td>\n",
" <td>513153</td>\n",
" <td>106234</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>92</th>\n",
" <td>457</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>6</td>\n",
" <td>동</td>\n",
" <td>서</td>\n",
" <td>076</td>\n",
" <td>260</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>93</th>\n",
" <td>457</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>257</td>\n",
" <td>075</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>94</th>\n",
" <td>457</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>257</td>\n",
" <td>347</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>95</th>\n",
" <td>457</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>1</td>\n",
" <td>동</td>\n",
" <td>남</td>\n",
" <td>075</td>\n",
" <td>166</td>\n",
" <td>519799</td>\n",
" <td>519798</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96</th>\n",
" <td>457</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>97</th>\n",
" <td>457</td>\n",
" <td>3</td>\n",
" <td>B</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>98</th>\n",
" <td>457</td>\n",
" <td>4</td>\n",
" <td>A</td>\n",
" <td>8</td>\n",
" <td>남</td>\n",
" <td>북</td>\n",
" <td>163</td>\n",
" <td>346</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>99</th>\n",
" <td>457</td>\n",
" <td>4</td>\n",
" <td>B</td>\n",
" <td>3</td>\n",
" <td>남</td>\n",
" <td>서</td>\n",
" <td>162</td>\n",
" <td>258</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>100</th>\n",
" <td>457</td>\n",
" <td>5</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>343</td>\n",
" <td>079</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>101</th>\n",
" <td>457</td>\n",
" <td>5</td>\n",
" <td>B</td>\n",
" <td>4</td>\n",
" <td>북</td>\n",
" <td>남</td>\n",
" <td>344</td>\n",
" <td>164</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109296</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>102</th>\n",
" <td>457</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>6</td>\n",
" <td>동</td>\n",
" <td>서</td>\n",
" <td>076</td>\n",
" <td>260</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>103</th>\n",
" <td>457</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>257</td>\n",
" <td>075</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>104</th>\n",
" <td>457</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>257</td>\n",
" <td>347</td>\n",
" <td>519801</td>\n",
" <td>519800</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>105</th>\n",
" <td>457</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>1</td>\n",
" <td>동</td>\n",
" <td>남</td>\n",
" <td>075</td>\n",
" <td>166</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>106</th>\n",
" <td>457</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>107</th>\n",
" <td>457</td>\n",
" <td>3</td>\n",
" <td>B</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>108</th>\n",
" <td>457</td>\n",
" <td>4</td>\n",
" <td>A</td>\n",
" <td>8</td>\n",
" <td>남</td>\n",
" <td>북</td>\n",
" <td>163</td>\n",
" <td>346</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>109</th>\n",
" <td>457</td>\n",
" <td>4</td>\n",
" <td>B</td>\n",
" <td>3</td>\n",
" <td>남</td>\n",
" <td>서</td>\n",
" <td>162</td>\n",
" <td>258</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>110</th>\n",
" <td>457</td>\n",
" <td>5</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>343</td>\n",
" <td>079</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>111</th>\n",
" <td>457</td>\n",
" <td>5</td>\n",
" <td>B</td>\n",
" <td>4</td>\n",
" <td>북</td>\n",
" <td>남</td>\n",
" <td>344</td>\n",
" <td>164</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" inter_no phase_no ring_type move_no inc_dire out_dire inc_angle \\\n",
"52 443 1 A 6 동 서 041 \n",
"53 443 1 B 2 서 동 221 \n",
"54 443 2 A 5 서 북 222 \n",
"55 443 2 B 2 서 동 221 \n",
"56 443 3 A 7 북 동 321 \n",
"57 443 3 B 18 NaN NaN NaN \n",
"58 443 1 A 6 동 서 041 \n",
"59 443 1 B 2 서 동 221 \n",
"60 443 2 A 5 서 북 222 \n",
"61 443 2 B 2 서 동 221 \n",
"62 443 3 A 7 북 동 321 \n",
"63 443 3 B 18 NaN NaN NaN \n",
"64 455 1 A 6 동 서 073 \n",
"65 455 1 B 2 서 동 255 \n",
"66 456 1 A 5 서 북 257 \n",
"67 456 1 B 2 서 동 256 \n",
"68 456 2 A 6 동 서 074 \n",
"69 456 2 B 2 서 동 256 \n",
"70 456 3 A 7 북 동 040 \n",
"71 456 3 B 7 북 동 040 \n",
"72 456 4 A 17 NaN NaN NaN \n",
"73 456 4 B 17 NaN NaN NaN \n",
"74 456 1 A 5 서 북 257 \n",
"75 456 1 B 2 서 동 256 \n",
"76 456 2 A 6 동 서 074 \n",
"77 456 2 B 2 서 동 256 \n",
"78 456 3 A 7 북 동 040 \n",
"79 456 3 B 7 북 동 040 \n",
"80 456 4 A 17 NaN NaN NaN \n",
"81 456 4 B 17 NaN NaN NaN \n",
"82 457 1 A 6 동 서 076 \n",
"83 457 1 B 2 서 동 257 \n",
"84 457 2 A 5 서 북 257 \n",
"85 457 2 B 1 동 남 075 \n",
"86 457 3 A 17 NaN NaN NaN \n",
"87 457 3 B 17 NaN NaN NaN \n",
"88 457 4 A 8 남 북 163 \n",
"89 457 4 B 3 남 서 162 \n",
"90 457 5 A 7 북 동 343 \n",
"91 457 5 B 4 북 남 344 \n",
"92 457 1 A 6 동 서 076 \n",
"93 457 1 B 2 서 동 257 \n",
"94 457 2 A 5 서 북 257 \n",
"95 457 2 B 1 동 남 075 \n",
"96 457 3 A 17 NaN NaN NaN \n",
"97 457 3 B 17 NaN NaN NaN \n",
"98 457 4 A 8 남 북 163 \n",
"99 457 4 B 3 남 서 162 \n",
"100 457 5 A 7 북 동 343 \n",
"101 457 5 B 4 북 남 344 \n",
"102 457 1 A 6 동 서 076 \n",
"103 457 1 B 2 서 동 257 \n",
"104 457 2 A 5 서 북 257 \n",
"105 457 2 B 1 동 남 075 \n",
"106 457 3 A 17 NaN NaN NaN \n",
"107 457 3 B 17 NaN NaN NaN \n",
"108 457 4 A 8 남 북 163 \n",
"109 457 4 B 3 남 서 162 \n",
"110 457 5 A 7 북 동 343 \n",
"111 457 5 B 4 북 남 344 \n",
"\n",
" out_angle inc_edge_id out_edge_id node_id node_type turn_type \n",
"52 225 516916 513863 108769 normal straight \n",
"53 043 513862 516917 108769 normal straight \n",
"54 320 513862 518550 108769 normal left \n",
"55 043 513862 516917 108769 normal straight \n",
"56 039 518549 516917 108769 normal left \n",
"57 NaN NaN NaN 108769 normal NaN \n",
"58 225 NaN NaN 109333 u_turn straight \n",
"59 043 NaN NaN 109333 u_turn straight \n",
"60 320 519873 519874 109333 u_turn left \n",
"61 043 NaN NaN 109333 u_turn straight \n",
"62 039 NaN NaN 109333 u_turn left \n",
"63 NaN NaN NaN 109333 u_turn NaN \n",
"64 257 513580 513581 109901 normal straight \n",
"65 076 513582 513584 109901 normal straight \n",
"66 043 513136 513139 106231 normal left \n",
"67 076 513136 513137 106231 normal straight \n",
"68 258 513138 513135 106231 normal straight \n",
"69 076 513136 513137 106231 normal straight \n",
"70 077 513140 513137 106231 normal left \n",
"71 077 513140 513137 106231 normal left \n",
"72 NaN NaN NaN 106231 normal NaN \n",
"73 NaN NaN NaN 106231 normal NaN \n",
"74 043 519797 519796 109295 u_turn left \n",
"75 076 NaN NaN 109295 u_turn straight \n",
"76 258 NaN NaN 109295 u_turn straight \n",
"77 076 NaN NaN 109295 u_turn straight \n",
"78 077 NaN NaN 109295 u_turn left \n",
"79 077 NaN NaN 109295 u_turn left \n",
"80 NaN NaN NaN 109295 u_turn NaN \n",
"81 NaN NaN NaN 109295 u_turn NaN \n",
"82 260 513152 513155 106234 normal straight \n",
"83 075 513156 513151 106234 normal straight \n",
"84 347 513156 513157 106234 normal left \n",
"85 166 513152 513153 106234 normal left \n",
"86 NaN NaN NaN 106234 normal NaN \n",
"87 NaN NaN NaN 106234 normal NaN \n",
"88 346 513154 513157 106234 normal straight \n",
"89 258 513154 513155 106234 normal left \n",
"90 079 513158 513151 106234 normal left \n",
"91 164 513158 513153 106234 normal straight \n",
"92 260 NaN NaN 109296 u_turn straight \n",
"93 075 NaN NaN 109296 u_turn straight \n",
"94 347 NaN NaN 109296 u_turn left \n",
"95 166 519799 519798 109296 u_turn left \n",
"96 NaN NaN NaN 109296 u_turn NaN \n",
"97 NaN NaN NaN 109296 u_turn NaN \n",
"98 346 NaN NaN 109296 u_turn straight \n",
"99 258 NaN NaN 109296 u_turn left \n",
"100 079 NaN NaN 109296 u_turn left \n",
"101 164 NaN NaN 109296 u_turn straight \n",
"102 260 NaN NaN 109297 u_turn straight \n",
"103 075 NaN NaN 109297 u_turn straight \n",
"104 347 519801 519800 109297 u_turn left \n",
"105 166 NaN NaN 109297 u_turn left \n",
"106 NaN NaN NaN 109297 u_turn NaN \n",
"107 NaN NaN NaN 109297 u_turn NaN \n",
"108 346 NaN NaN 109297 u_turn straight \n",
"109 258 NaN NaN 109297 u_turn left \n",
"110 079 NaN NaN 109297 u_turn left \n",
"111 164 NaN NaN 109297 u_turn straight "
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"self.match6[52:52+60]"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"# 2-1-7\n",
"self.match7 = self.match6.copy()\n",
"self.match7 = self.match7[['inter_no', 'node_id', 'move_no', 'inc_angle', 'out_angle', 'inc_dire', 'out_dire', 'inc_edge_id', 'out_edge_id', 'node_type', 'turn_type']]\n",
"\n",
"# (1) 각 교차로별 방향 목록 : pdires (possible directions)\n",
"p2dires = {} # parent_id to directions\n",
"for parent_id in self.parent_ids:\n",
" dires = self.match7[self.match7.node_id == parent_id][['inc_dire','out_dire']].values.flatten()\n",
" dires = {dire for dire in dires if type(dire)==str}\n",
" p2dires[parent_id] = dires\n",
"\n",
"# (2) 각 (교차로, 진입방향) 별 진입id 목록 : inc2id (incoming direction to incoming edge_id)\n",
"inc2id = {}\n",
"for parent_id in self.parent_ids:\n",
" for inc_dire in p2dires[parent_id]:\n",
" df = self.match7[(self.match7.node_id==parent_id) & (self.match7.inc_dire==inc_dire)]\n",
" inc2id[(parent_id, inc_dire)] = df.inc_edge_id.iloc[0]\n",
"\n",
"# (3) 각 (교차로, 진출방향) 별 진출id 목록 : out2id (outgoing direction to outgoing edge_id)\n",
"out2id = {}\n",
"for parent_id in self.parent_ids:\n",
" for out_dire in p2dires[parent_id]:\n",
" df = self.match7[(self.match7.node_id==parent_id) & (self.match7.out_dire==out_dire)]\n",
" out2id[(parent_id, out_dire)] = df.out_edge_id.iloc[0]\n",
"\n",
"# (4) 각 parent_id별 이동류번호 목록\n",
"p2move = dict() # parent id to a list of aligned movement numbers\n",
"for parent_id in self.parent_ids:\n",
" pnema = self.nema[self.nema.inc_dire.isin(p2dires[parent_id]) & self.nema.out_dire.isin(p2dires[parent_id])]\n",
" p2move[parent_id] = list(pnema.move_no)\n",
"\n",
"# (5) 방위별 방향벡터\n",
"dire2vec = dict() # direction to unit vector\n",
"theta = np.pi/2\n",
"for dire in self.dires:\n",
" dire2vec[dire] = np.array([np.cos(theta), np.sin(theta)])\n",
" theta -= np.pi/4\n",
"\n",
"# (6) 각 parent_id별 : 각 이동류별 진입/진출 엣지 id\n",
"p2move2inc_edge_id = dict() # parent id to move2inc_edge_id\n",
"p2move2out_edge_id = dict() # parent id to move2out_edge_id\n",
"for parent_id in self.parent_ids:\n",
" move2inc_edge_id = dict() # plain movement to incoming edge id\n",
" move2out_edge_id = dict() # plain movement to outgoing edge id\n",
" for move_no in range(1,17):\n",
" row = self.nema[self.nema.move_no==move_no].iloc[0]\n",
" inc_dire = row.inc_dire\n",
" out_dire = row.out_dire\n",
" inc_vec_true = dire2vec[inc_dire]\n",
" out_vec_true = dire2vec[out_dire]\n",
"\n",
" node = self.net.getNode(parent_id)\n",
" # 교차로의 모든 (from / to) edges\n",
" inc_edges = [edge for edge in node.getIncoming() if edge.getFunction() == ''] # incoming edges\n",
" out_edges = [edge for edge in node.getOutgoing() if edge.getFunction() == ''] # outgoing edges\n",
" # 교차로의 모든 (from / to) unit vector\n",
" inc_vecs = []\n",
" for inc_edge in inc_edges:\n",
" start = inc_edge.getShape()[-1]\n",
" end = inc_edge.getShape()[-2]\n",
" inc_vec = np.array(end) - np.array(start)\n",
" inc_vec = inc_vec / (inc_vec ** 2).sum() ** 0.5\n",
" inc_vecs.append(inc_vec)\n",
" out_vecs = []\n",
" for out_edge in out_edges:\n",
" start = out_edge.getShape()[0]\n",
" end = out_edge.getShape()[1]\n",
" out_vec = np.array(end) - np.array(start)\n",
" out_vec = out_vec / (out_vec ** 2).sum() ** 0.5\n",
" out_vecs.append(out_vec)\n",
" # 매칭 엣지 반환\n",
" inc_index = np.array([np.dot(inc_vec, inc_vec_true) for inc_vec in inc_vecs]).argmax()\n",
" out_index = np.array([np.dot(out_vec, out_vec_true) for out_vec in out_vecs]).argmax()\n",
" inc_edge_id = inc_edges[inc_index].getID()\n",
" out_edge_id = out_edges[out_index].getID()\n",
" move2inc_edge_id[move_no] = inc_edge_id\n",
" move2out_edge_id[move_no] = out_edge_id\n",
" p2move2inc_edge_id[parent_id] = move2inc_edge_id\n",
" p2move2out_edge_id[parent_id] = move2out_edge_id\n",
"\n",
"# (7) 각 이동류별 진입/진출 방위\n",
"m2inc_dire = dict()\n",
"m2out_dire = dict()\n",
"for move_no in range(1,17):\n",
" row = self.nema[self.nema.move_no==move_no].iloc[0]\n",
" m2inc_dire[move_no] = row.inc_dire\n",
" m2out_dire[move_no] = row.out_dire\n",
"\n",
"# (8) 가능한 모든 이동류에 대하여 진입id, 진출id 배정 : matching\n",
"self.matching = []\n",
"for parent_id in self.parent_ids:\n",
" inter_no = self.node2inter[parent_id]\n",
" # 좌회전과 직진(1 ~ 16)\n",
" for move_no in range(1,17):\n",
" inc_dire = m2inc_dire[move_no]\n",
" out_dire = m2out_dire[move_no]\n",
" if move_no in p2move[parent_id]:\n",
" inc_edge_id = inc2id[(parent_id, inc_dire)]\n",
" out_edge_id = out2id[(parent_id, out_dire)]\n",
" else:\n",
" inc_edge_id = p2move2inc_edge_id[parent_id][move_no]\n",
" out_edge_id = p2move2out_edge_id[parent_id][move_no]\n",
" if (inc_edge_id, out_edge_id) in self.n2io2turn[parent_id]:\n",
" turn_type = self.n2io2turn[parent_id][inc_edge_id, out_edge_id]\n",
" else:\n",
" turn_type = 'left' if move_no % 2 else 'straight'\n",
" new_row = pd.DataFrame({'inter_no':[inter_no], 'node_id':[parent_id], 'move_no':[move_no],\n",
" 'inc_dire':[inc_dire], 'out_dire':[out_dire],\n",
" 'inc_edge_id':[inc_edge_id], 'out_edge_id':[out_edge_id],\n",
" 'turn_type': turn_type})\n",
" self.matching.append(new_row)\n",
"child_matching = self.match7[self.match7.node_id.isin(self.child_ids)]\n",
"child_matching = child_matching.drop(columns=['inc_angle', 'out_angle'])\n",
"self.matching = pd.concat(self.matching)\n",
"self.matching = self.matching.dropna(subset=['inc_edge_id', 'out_edge_id'])\\\n",
" .sort_values(by=['inter_no', 'node_id', 'move_no']).reset_index(drop=True)\n",
"self.matching['move_no'] = self.matching['move_no'].astype(int)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>inter_no</th>\n",
" <th>phase_no</th>\n",
" <th>ring_type</th>\n",
" <th>move_no</th>\n",
" <th>inc_dire</th>\n",
" <th>out_dire</th>\n",
" <th>inc_angle</th>\n",
" <th>out_angle</th>\n",
" <th>inc_edge_id</th>\n",
" <th>out_edge_id</th>\n",
" <th>node_id</th>\n",
" <th>node_type</th>\n",
" <th>turn_type</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>436</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>262</td>\n",
" <td>358</td>\n",
" <td>517505</td>\n",
" <td>517507</td>\n",
" <td>109836</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>436</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>262</td>\n",
" <td>074</td>\n",
" <td>517505</td>\n",
" <td>517004</td>\n",
" <td>109836</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>436</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>8</td>\n",
" <td>남</td>\n",
" <td>북</td>\n",
" <td>174</td>\n",
" <td>355</td>\n",
" <td>517509</td>\n",
" <td>517507</td>\n",
" <td>109836</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>436</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>3</td>\n",
" <td>남</td>\n",
" <td>서</td>\n",
" <td>172</td>\n",
" <td>263</td>\n",
" <td>517509</td>\n",
" <td>517504</td>\n",
" <td>109836</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>436</td>\n",
" <td>3</td>\n",
" <td>A</td>\n",
" <td>7</td>\n",
" <td>북</td>\n",
" <td>동</td>\n",
" <td>356</td>\n",
" <td>074</td>\n",
" <td>517002</td>\n",
" <td>517004</td>\n",
" <td>109836</td>\n",
" <td>normal</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>111</th>\n",
" <td>457</td>\n",
" <td>5</td>\n",
" <td>B</td>\n",
" <td>4</td>\n",
" <td>북</td>\n",
" <td>남</td>\n",
" <td>344</td>\n",
" <td>164</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>109297</td>\n",
" <td>u_turn</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>112</th>\n",
" <td>458</td>\n",
" <td>1</td>\n",
" <td>A</td>\n",
" <td>8</td>\n",
" <td>남</td>\n",
" <td>북</td>\n",
" <td>073</td>\n",
" <td>250</td>\n",
" <td>513193</td>\n",
" <td>513188</td>\n",
" <td>106238</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>113</th>\n",
" <td>458</td>\n",
" <td>1</td>\n",
" <td>B</td>\n",
" <td>4</td>\n",
" <td>북</td>\n",
" <td>남</td>\n",
" <td>249</td>\n",
" <td>072</td>\n",
" <td>513189</td>\n",
" <td>513192</td>\n",
" <td>106238</td>\n",
" <td>normal</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>114</th>\n",
" <td>458</td>\n",
" <td>2</td>\n",
" <td>A</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>106238</td>\n",
" <td>normal</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>115</th>\n",
" <td>458</td>\n",
" <td>2</td>\n",
" <td>B</td>\n",
" <td>17</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>106238</td>\n",
" <td>normal</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>116 rows × 13 columns</p>\n",
"</div>"
],
"text/plain": [
" inter_no phase_no ring_type move_no inc_dire out_dire inc_angle \\\n",
"0 436 1 A 5 서 북 262 \n",
"1 436 1 B 2 서 동 262 \n",
"2 436 2 A 8 남 북 174 \n",
"3 436 2 B 3 남 서 172 \n",
"4 436 3 A 7 북 동 356 \n",
".. ... ... ... ... ... ... ... \n",
"111 457 5 B 4 북 남 344 \n",
"112 458 1 A 8 남 북 073 \n",
"113 458 1 B 4 북 남 249 \n",
"114 458 2 A 17 NaN NaN NaN \n",
"115 458 2 B 17 NaN NaN NaN \n",
"\n",
" out_angle inc_edge_id out_edge_id node_id node_type turn_type \n",
"0 358 517505 517507 109836 normal left \n",
"1 074 517505 517004 109836 normal straight \n",
"2 355 517509 517507 109836 normal straight \n",
"3 263 517509 517504 109836 normal left \n",
"4 074 517002 517004 109836 normal left \n",
".. ... ... ... ... ... ... \n",
"111 164 NaN NaN 109297 u_turn straight \n",
"112 250 513193 513188 106238 normal straight \n",
"113 072 513189 513192 106238 normal straight \n",
"114 NaN NaN NaN 106238 normal NaN \n",
"115 NaN NaN NaN 106238 normal NaN \n",
"\n",
"[116 rows x 13 columns]"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"self.match6"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>inter_no</th>\n",
" <th>node_id</th>\n",
" <th>move_no</th>\n",
" <th>inc_dire</th>\n",
" <th>out_dire</th>\n",
" <th>inc_edge_id</th>\n",
" <th>out_edge_id</th>\n",
" <th>turn_type</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>436</td>\n",
" <td>109836</td>\n",
" <td>1</td>\n",
" <td>동</td>\n",
" <td>남</td>\n",
" <td>517003</td>\n",
" <td>517506</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>436</td>\n",
" <td>109836</td>\n",
" <td>2</td>\n",
" <td>서</td>\n",
" <td>동</td>\n",
" <td>517505</td>\n",
" <td>517004</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>436</td>\n",
" <td>109836</td>\n",
" <td>3</td>\n",
" <td>남</td>\n",
" <td>서</td>\n",
" <td>517509</td>\n",
" <td>517504</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>436</td>\n",
" <td>109836</td>\n",
" <td>4</td>\n",
" <td>북</td>\n",
" <td>남</td>\n",
" <td>517002</td>\n",
" <td>517506</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>436</td>\n",
" <td>109836</td>\n",
" <td>5</td>\n",
" <td>서</td>\n",
" <td>북</td>\n",
" <td>517505</td>\n",
" <td>517507</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>139</th>\n",
" <td>458</td>\n",
" <td>106238</td>\n",
" <td>12</td>\n",
" <td>북서</td>\n",
" <td>남동</td>\n",
" <td>513195</td>\n",
" <td>513190</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>140</th>\n",
" <td>458</td>\n",
" <td>106238</td>\n",
" <td>13</td>\n",
" <td>남서</td>\n",
" <td>북서</td>\n",
" <td>513189</td>\n",
" <td>513194</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>141</th>\n",
" <td>458</td>\n",
" <td>106238</td>\n",
" <td>14</td>\n",
" <td>북동</td>\n",
" <td>남서</td>\n",
" <td>513193</td>\n",
" <td>513188</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" <tr>\n",
" <th>142</th>\n",
" <td>458</td>\n",
" <td>106238</td>\n",
" <td>15</td>\n",
" <td>북서</td>\n",
" <td>북동</td>\n",
" <td>513195</td>\n",
" <td>513192</td>\n",
" <td>left</td>\n",
" </tr>\n",
" <tr>\n",
" <th>143</th>\n",
" <td>458</td>\n",
" <td>106238</td>\n",
" <td>16</td>\n",
" <td>남동</td>\n",
" <td>북서</td>\n",
" <td>513191</td>\n",
" <td>513194</td>\n",
" <td>straight</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>144 rows × 8 columns</p>\n",
"</div>"
],
"text/plain": [
" inter_no node_id move_no inc_dire out_dire inc_edge_id out_edge_id \\\n",
"0 436 109836 1 동 남 517003 517506 \n",
"1 436 109836 2 서 동 517505 517004 \n",
"2 436 109836 3 남 서 517509 517504 \n",
"3 436 109836 4 북 남 517002 517506 \n",
"4 436 109836 5 서 북 517505 517507 \n",
".. ... ... ... ... ... ... ... \n",
"139 458 106238 12 북서 남동 513195 513190 \n",
"140 458 106238 13 남서 북서 513189 513194 \n",
"141 458 106238 14 북동 남서 513193 513188 \n",
"142 458 106238 15 북서 북동 513195 513192 \n",
"143 458 106238 16 남동 북서 513191 513194 \n",
"\n",
" turn_type \n",
"0 left \n",
"1 straight \n",
"2 left \n",
"3 straight \n",
"4 left \n",
".. ... \n",
"139 straight \n",
"140 left \n",
"141 straight \n",
"142 left \n",
"143 straight \n",
"\n",
"[144 rows x 8 columns]"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"self.matching"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[(0, <sumolib.net.connection.Connection at 0x248f3615940>),\n",
" (1, <sumolib.net.connection.Connection at 0x248f36159a0>),\n",
" (2, <sumolib.net.connection.Connection at 0x248f3615a60>),\n",
" (3, <sumolib.net.connection.Connection at 0x248f3615ac0>)]"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"node_id = '109901'\n",
"node = self.net.getNode(node_id)\n",
"conns = node.getConnections()\n",
"[(c.getJunctionIndex(), c) for c in node.getConnections()]"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2-2. 초기화 신호가 지정되었습니다. (우회전 : g)\n"
]
}
],
"source": [
"# 2-2 신호 초기화\n",
"self.nodes = [self.net.getNode(node_id) for node_id in self.node_ids]\n",
"self.node2init = {}\n",
"# 유턴노드를 제외한 모든 노드 (우회전, 삼지교차로직진 : g, 그외 : r)\n",
"for node_id in sorted(set(self.node_ids) - set(self.uturn_ids)):\n",
" node = self.net.getNode(node_id)\n",
" conns = [(c.getJunctionIndex(), c) for c in node.getConnections()]\n",
" conns = [c for c in conns if c[0] >= 0]\n",
" conns = sorted(conns, key=lambda x: x[0])\n",
" # print(node_id, len(conns),sep='\\n')\n",
" state = []\n",
" for i, ci in conns: # i번째 connection : ci\n",
" # print(ci.getTLLinkIndex())\n",
" if ci.getTLLinkIndex() < 0:\n",
" continue\n",
" are_foes = False\n",
" # 합류지점이 다르면서 상충되는 cj가 존재하면 r, 그외에는 g\n",
" for j, cj in conns: # j번째 connection : cj\n",
" # ci, cj의 합류지점이 같으면 통과\n",
" if ci.getTo() == cj.getTo():\n",
" continue\n",
" # ci, cj가 상충되면 are_foes를 True로 지정.\n",
" if node.areFoes(i, j):\n",
" are_foes = True\n",
" break\n",
" state.append('r' if are_foes else 'g')\n",
" self.node2init[node_id] = state\n",
"\n",
"# 유턴노드 (유턴x : G, 유턴 : G)\n",
"for node_id in self.uturn_ids:\n",
" node = self.net.getNode(node_id)\n",
" conns = [(c.getJunctionIndex(), c) for c in node.getConnections()]\n",
" conns = [c for c in conns if c[0] >= 0]\n",
" conns = sorted(conns, key=lambda x: x[0])\n",
" state = []\n",
" for i, ci in conns:\n",
" if ci.getTLLinkIndex() < 0:\n",
" continue\n",
" state.append('G')\n",
" self.node2init[node_id] = state\n",
"\n",
"# 신호가 부여되어 있는 경우에는 r을 부여 (우회전 : g, 그외 : r / 유턴x : G, 유턴 : r)\n",
"for _, row in self.match6.dropna(subset=['inc_edge_id', 'out_edge_id']).iterrows():\n",
" node_id = row.node_id\n",
" inc_edge_id = row.inc_edge_id\n",
" out_edge_id = row.out_edge_id\n",
" inc_edge = self.net.getEdge(inc_edge_id)\n",
" out_edge = self.net.getEdge(out_edge_id)\n",
" for conn in inc_edge.getConnections(out_edge):\n",
" index = conn.getTLLinkIndex()\n",
" if index >= 0:\n",
" self.node2init[node_id][index] = 'r'\n",
"\n",
"# json 파일로 저장\n",
"with open(os.path.join(self.path_intermediates, 'node2init.json'), 'w') as file:\n",
" json.dump(self.node2init, file, indent=4)\n",
"print('2-2. 초기화 신호가 지정되었습니다. (우회전 : g)')"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [],
"source": [
"# 2-3 유턴 인덱스 / 비보호좌회전 인덱스 지정\n",
"self.u2uindex = dict() # uturn node id to uturn index\n",
"for row in self.uturn.itertuples():\n",
" child_id = row.child_id\n",
" inc_edge_id = row.inc_edge_id\n",
" out_edge_id = row.out_edge_id\n",
" # self.u2uindex 지정\n",
" inc_edge = self.net.getEdge(inc_edge_id)\n",
" out_edge = self.net.getEdge(out_edge_id)\n",
" uturn_conn = inc_edge.getConnections(out_edge)[0]\n",
" self.u2uindex[child_id] = uturn_conn.getTLLinkIndex()\n",
"\n",
"self.p2UPLindices2inc_edge_ids = dict() # parent id to unprotected left index to incoming_edge_ids\n",
"for parent_id in self.parent_ids:\n",
" init_state = self.node2init[parent_id]\n",
" # 우회전 이동류 인덱스\n",
" indices_right = [i for i in range(len(init_state)) if init_state[i]=='g']\n",
" # from-to가 지정된 이동류 인덱스\n",
" indices_assigned = []\n",
" m5 = self.match5[(self.match5.node_id==parent_id)].dropna(subset=['inc_edge_id', 'out_edge_id'])\n",
" for row in m5.itertuples():\n",
" inc_edge = self.net.getEdge(row.inc_edge_id)\n",
" out_edge = self.net.getEdge(row.out_edge_id)\n",
" conns = inc_edge.getConnections(out_edge)\n",
" indices = [conn for conn in conns if conn.getTLLinkIndex()>=0]\n",
" indices = [conn for conn in conns if conn.getJunctionIndex()>=0]\n",
" indices = [conn.getTLLinkIndex() for conn in conns]\n",
" indices_assigned.extend(indices)\n",
" # 좌회전 이동류 인덱스\n",
" indices_left = []\n",
" for row in self.turn_type[self.turn_type.turn_type=='left'].itertuples():\n",
" inc_edge = self.net.getEdge(row.inc_edge_id)\n",
" out_edge = self.net.getEdge(row.out_edge_id)\n",
" conns = inc_edge.getConnections(out_edge)\n",
" indices = [conn for conn in conns if conn.getTLLinkIndex()>=0]\n",
" indices = [conn for conn in conns if conn.getJunctionIndex()>=0]\n",
" indices = [conn.getTLLinkIndex() for conn in conns]\n",
" indices_left.extend(indices)\n",
" # 비보호좌회전 인덱스 (unprotected left index)\n",
" UPLindices2inc_edge_ids = list((set(range(len(init_state))) - set(indices_right) - set(indices_assigned)).intersection(indices_left))\n",
" self.p2UPLindices2inc_edge_ids[parent_id] = dict()\n",
" for UPLindex in UPLindices2inc_edge_ids:\n",
" node = self.net.getNode(parent_id)\n",
" conns = node.getConnections()\n",
" conns = [conn for conn in conns if conn.getTLLinkIndex() == UPLindex]\n",
" inc_edge_ids = [conn.getFrom().getID() for conn in conns]\n",
" self.p2UPLindices2inc_edge_ids[parent_id][UPLindex] = inc_edge_ids\n"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"# 2-4 신호배정\n",
"for i, row in self.matching.iterrows():\n",
" node_id = row.node_id\n",
" move_no = row.move_no\n",
" inc_edge_id = row.inc_edge_id\n",
" out_edge_id = row.out_edge_id\n",
" state_list = copy.deepcopy(self.node2init[node_id])\n",
" self.matching.at[i, 'state'] = ''.join(state_list)\n",
" if (pd.isna(inc_edge_id)) or (pd.isna(out_edge_id)):\n",
" continue\n",
" inc_edge = self.net.getEdge(inc_edge_id)\n",
" out_edge = self.net.getEdge(out_edge_id)\n",
" # 신호가 부여되어 있으면 (from, to가 존재하면) G 부여 (우회전 : g, 신호 : G, 그외 : r)\n",
" for conn in inc_edge.getConnections(out_edge):\n",
" index = conn.getTLLinkIndex()\n",
" if index >= 0:\n",
" state_list[index] = 'G'\n",
" self.matching.at[i, 'state'] = ''.join(state_list)\n",
"self.matching = self.matching.dropna(subset='state')\n",
"self.matching = self.matching.reset_index(drop=True)\n",
"self.matching = self.matching[['inter_no', 'node_id', 'move_no', 'inc_edge_id', 'out_edge_id', 'state', 'turn_type']]\n"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [],
"source": [
"# match6 : 신호 배정\n",
"for i, row in self.match6.iterrows():\n",
" node_id = row.node_id\n",
" move_no = row.move_no\n",
" inc_edge_id = row.inc_edge_id\n",
" out_edge_id = row.out_edge_id\n",
" state_list = copy.deepcopy(self.node2init[node_id])\n",
" self.match6.at[i, 'state'] = ''.join(state_list)\n",
" if (pd.isna(inc_edge_id)) or (pd.isna(out_edge_id)):\n",
" continue\n",
" inc_edge = self.net.getEdge(inc_edge_id)\n",
" out_edge = self.net.getEdge(out_edge_id)\n",
" # 신호가 부여되어 있으면 (from, to가 존재하면) G 부여 (우회전 : g, 신호 : G, 그외 : r)\n",
" for conn in inc_edge.getConnections(out_edge):\n",
" index = conn.getTLLinkIndex()\n",
" if index >= 0:\n",
" state_list[index] = 'G'\n",
" self.match6.at[i, 'state'] = ''.join(state_list)\n",
"\n",
"# match6 : 비보호좌회전 신호 배정\n",
"for i, row in self.match6[self.match6.node_id.isin(self.parent_ids)].iterrows():\n",
" parent_id = row.node_id\n",
" state = row.state\n",
" UPLindices2inc_edge_ids = self.p2UPLindices2inc_edge_ids[parent_id]\n",
" for UPLindex in UPLindices2inc_edge_ids:\n",
" # 비보호좌회전 이동류에 대한 진입엣지에 신호가 부여되어 있으면\n",
" inc_edge_ids = UPLindices2inc_edge_ids[UPLindex]\n",
" if inc_edge_ids:\n",
" if inc_edge_id in inc_edge_ids:\n",
" # 해당 비보호좌회전 인덱스(UPLindex)에, 해당 진입엣지의 직진신호가 있을 때 g를 부여\n",
" state = state[:UPLindex] + 'g' + state[UPLindex+1:]\n",
" self.match6.at[i, 'state'] = state\n",
" else: # 직진신호가 없는 비보호좌회전 발생시 멈춤 및 오류메시지 출력\n",
" raise Exception(\n",
" f\"비보호좌회전 신호를 부여할 수 없습니다. \\\n",
" 신호가 부여되어 있지 않은 직진 또는 좌회전 연결이 존재하는데\\\n",
" (node_id : {parent_id}, index : {UPLindex})\\\n",
" 이 연결의 진입엣지(inc_edge_id : {inc_edge_id})에 부여된 신호가 없습니다.\")\n",
"\n",
"\n",
"# match6 : 유턴 신호가 한번도 배정되지 않은 경우에 대해서는 유턴이동류의 신호를 항상 g로 배정\n",
"for node_id in self.uturn_ids:\n",
" m6 = self.match6[self.match6.node_id==node_id]\n",
" if not len(m6):\n",
" continue\n",
" state_list = copy.deepcopy(self.node2init[node_id])\n",
" state = ''.join(state_list)\n",
" uindex = self.u2uindex[node_id]\n",
" values_at_uindex = [state[uindex] for state in m6.state]\n",
" # 유턴신호가 한번도 배정되지 않았으면\n",
" uturn_assigned = ('G' in values_at_uindex)\n",
" if not uturn_assigned:\n",
" # 해당 유턴 인덱스(uindex)에 g를 항상 부여\n",
" state = state[:uindex] + 'g' + state[uindex+1:]\n",
" self.match6.loc[self.match6.node_id==node_id, 'state'] = state\n",
"\n",
"self.match6 = self.match6.dropna(subset='state')\n",
"self.match6 = self.match6.reset_index(drop=True)\n",
"self.match6 = self.match6[['inter_no', 'node_id', 'phase_no', 'ring_type', 'move_no', 'inc_edge_id', 'out_edge_id', 'state', 'turn_type']]\n",
"self.match6.to_csv(os.path.join(self.path_intermediates, 'match6.csv'), index=0)\n",
"self.matching.to_csv(os.path.join(self.path_intermediates, 'matching.csv'), index=0)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [],
"source": [
"# 신호계획 저장\n",
"self.plan.to_csv(os.path.join(self.path_tables, 'plan.csv'), index=0)\n",
"\n",
"# 노드별 주기 개수 저장\n",
"Aplan = self.plan.copy()[['inter_no'] + [f'dura_A{j}' for j in range(1,9)] + ['cycle']]\n",
"grouped = Aplan.groupby('inter_no')\n",
"df = grouped.agg({'cycle': 'min'}).reset_index()\n",
"df = df.rename(columns={'cycle': 'min_cycle'})\n",
"df['num_cycle'] = 300 // df['min_cycle'] + 2\n",
"inter2num_cycles = dict(zip(df['inter_no'], df['num_cycle']))\n",
"node2num_cycles = {node_id : inter2num_cycles[self.node2inter[node_id]] for node_id in self.node_ids}\n",
"with open(os.path.join(self.path_intermediates,'node2num_cycles.json'), 'w') as file:\n",
" json.dump(node2num_cycles, file, indent=4)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "siggen_env",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}