{ "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": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inter_nophas_Aphas_Bmove_Amove_B
04361152
14362283
24363374
34364461
44371162
\n", "
" ], "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": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inter_nophase_noring_typemove_no
04361A5
04361B2
14362A8
14362B3
24363A7
\n", "
" ], "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": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inter_nophase_noring_typemove_noinc_direout_dire
04361A5
14361B2
24362A8
34362B3
44363A7
\n", "
" ], "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": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inter_nomove_noangle_code
164386100277
174382276098
184385274342
194381101181
204388183340
214383182276
224387347099
234384348186
\n", "
" ], "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": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inter_nophase_noring_typemove_noinc_direout_direinc_angleout_angle
04361A5262358
14361B2262074
24362A8174355
34362B3172263
44363A7356074
\n", "
" ], "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": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inter_nophase_noring_typemove_noinc_direout_direinc_angleout_angleinc_edge_idout_edge_idnode_idnode_typeturn_type
524431A6041225516916513863108769normalstraight
534431B2221043513862516917108769normalstraight
544432A5222320513862518550108769normalleft
554432B2221043513862516917108769normalstraight
564433A7321039518549516917108769normalleft
574433B18NaNNaNNaNNaNNaNNaN108769normalNaN
584431A6041225NaNNaN109333u_turnstraight
594431B2221043NaNNaN109333u_turnstraight
604432A5222320519873519874109333u_turnleft
614432B2221043NaNNaN109333u_turnstraight
624433A7321039NaNNaN109333u_turnleft
634433B18NaNNaNNaNNaNNaNNaN109333u_turnNaN
644551A6073257513580513581109901normalstraight
654551B2255076513582513584109901normalstraight
664561A5257043513136513139106231normalleft
674561B2256076513136513137106231normalstraight
684562A6074258513138513135106231normalstraight
694562B2256076513136513137106231normalstraight
704563A7040077513140513137106231normalleft
714563B7040077513140513137106231normalleft
724564A17NaNNaNNaNNaNNaNNaN106231normalNaN
734564B17NaNNaNNaNNaNNaNNaN106231normalNaN
744561A5257043519797519796109295u_turnleft
754561B2256076NaNNaN109295u_turnstraight
764562A6074258NaNNaN109295u_turnstraight
774562B2256076NaNNaN109295u_turnstraight
784563A7040077NaNNaN109295u_turnleft
794563B7040077NaNNaN109295u_turnleft
804564A17NaNNaNNaNNaNNaNNaN109295u_turnNaN
814564B17NaNNaNNaNNaNNaNNaN109295u_turnNaN
824571A6076260513152513155106234normalstraight
834571B2257075513156513151106234normalstraight
844572A5257347513156513157106234normalleft
854572B1075166513152513153106234normalleft
864573A17NaNNaNNaNNaNNaNNaN106234normalNaN
874573B17NaNNaNNaNNaNNaNNaN106234normalNaN
884574A8163346513154513157106234normalstraight
894574B3162258513154513155106234normalleft
904575A7343079513158513151106234normalleft
914575B4344164513158513153106234normalstraight
924571A6076260NaNNaN109296u_turnstraight
934571B2257075NaNNaN109296u_turnstraight
944572A5257347NaNNaN109296u_turnleft
954572B1075166519799519798109296u_turnleft
964573A17NaNNaNNaNNaNNaNNaN109296u_turnNaN
974573B17NaNNaNNaNNaNNaNNaN109296u_turnNaN
984574A8163346NaNNaN109296u_turnstraight
994574B3162258NaNNaN109296u_turnleft
1004575A7343079NaNNaN109296u_turnleft
1014575B4344164NaNNaN109296u_turnstraight
1024571A6076260NaNNaN109297u_turnstraight
1034571B2257075NaNNaN109297u_turnstraight
1044572A5257347519801519800109297u_turnleft
1054572B1075166NaNNaN109297u_turnleft
1064573A17NaNNaNNaNNaNNaNNaN109297u_turnNaN
1074573B17NaNNaNNaNNaNNaNNaN109297u_turnNaN
1084574A8163346NaNNaN109297u_turnstraight
1094574B3162258NaNNaN109297u_turnleft
1104575A7343079NaNNaN109297u_turnleft
1114575B4344164NaNNaN109297u_turnstraight
\n", "
" ], "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": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inter_nophase_noring_typemove_noinc_direout_direinc_angleout_angleinc_edge_idout_edge_idnode_idnode_typeturn_type
04361A5262358517505517507109836normalleft
14361B2262074517505517004109836normalstraight
24362A8174355517509517507109836normalstraight
34362B3172263517509517504109836normalleft
44363A7356074517002517004109836normalleft
..........................................
1114575B4344164NaNNaN109297u_turnstraight
1124581A8073250513193513188106238normalstraight
1134581B4249072513189513192106238normalstraight
1144582A17NaNNaNNaNNaNNaNNaN106238normalNaN
1154582B17NaNNaNNaNNaNNaNNaN106238normalNaN
\n", "

116 rows × 13 columns

\n", "
" ], "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": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inter_nonode_idmove_noinc_direout_direinc_edge_idout_edge_idturn_type
04361098361517003517506left
14361098362517505517004straight
24361098363517509517504left
34361098364517002517506straight
44361098365517505517507left
...........................
13945810623812북서남동513195513190straight
14045810623813남서북서513189513194left
14145810623814북동남서513193513188straight
14245810623815북서북동513195513192left
14345810623816남동북서513191513194straight
\n", "

144 rows × 8 columns

\n", "
" ], "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, ),\n", " (1, ),\n", " (2, ),\n", " (3, )]" ] }, "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 }