diff --git a/backend/app/get_centreline_node.py b/backend/app/nodes/byID/centreline.py similarity index 63% rename from backend/app/get_centreline_node.py rename to backend/app/nodes/byID/centreline.py index 2cefb85..1b4d732 100644 --- a/backend/app/get_centreline_node.py +++ b/backend/app/nodes/byID/centreline.py @@ -1,6 +1,6 @@ import json from app.db import getConnection -from app.get_nearest_here_nodes import get_here_nodes_within +from app.nodes.conflation import add_conflated_nodes SQL = ''' SELECT @@ -9,10 +9,9 @@ FROM gis_core.intersection_latest WHERE intersection_id = %(node_id)s GROUP BY geom; - ''' -def get_centreline_node(node_id, conflate_with_here=False): +def get_centreline_node(node_id, doConflation=False): """fetch a specific centreline node by it's ID""" node = {} with getConnection() as connection: @@ -27,14 +26,7 @@ def get_centreline_node(node_id, conflate_with_here=False): 'street_names': street_names, 'geometry': json.loads(geojson) } - if conflate_with_here: - lon = node['geometry']['coordinates'][0] - lat = node['geometry']['coordinates'][1] - try: - node['conflated'] = { - 'here': get_here_nodes_within(50, lon, lat, 1)[0] - } - except: - pass connection.close() + if doConflation: + node = add_conflated_nodes(node) return node diff --git a/backend/app/get_here_node.py b/backend/app/nodes/byID/here.py similarity index 75% rename from backend/app/get_here_node.py rename to backend/app/nodes/byID/here.py index 43400e7..096bb5a 100644 --- a/backend/app/get_here_node.py +++ b/backend/app/nodes/byID/here.py @@ -2,7 +2,7 @@ import json from app.db import getConnection -from app.get_nearest_centreline_node import get_nearest_centreline_node +from app.nodes.conflation import add_conflated_nodes SQL = ''' SELECT @@ -32,11 +32,7 @@ def get_here_node(node_id, conflate_with_centreline=False): 'street_names': street_names, 'geometry': json.loads(geojson) } - if conflate_with_centreline: - lon = node['geometry']['coordinates'][0] - lat = node['geometry']['coordinates'][1] - node['conflated'] = { - 'centreline': get_nearest_centreline_node(lon, lat) - } connection.close() + if conflate_with_centreline: + node = add_conflated_nodes(node) return node diff --git a/backend/app/nodes/byID/px.py b/backend/app/nodes/byID/px.py new file mode 100644 index 0000000..e830de0 --- /dev/null +++ b/backend/app/nodes/byID/px.py @@ -0,0 +1,35 @@ +import json +from app.db import getConnection + +SQL = ''' +SELECT + tts.px, + ST_AsGeoJSON(tts.geom) AS geojson, + array_remove( + ARRAY[ + InitCap(gts.main_street), + InitCap(gts.side1_street), + InitCap(gts.side2_street) + ], + NULL + ) AS street_names +FROM traffic.traffic_signal AS tts +JOIN gis.traffic_signal AS gts ON tts.px = gts.px::int +WHERE tts."centrelineId" = %(centreline_id)s; +''' + +def get_px_node(centreline_id): + node = {} + with getConnection() as connection: + with connection.cursor() as cursor: + cursor.execute(SQL, {"centreline_id": centreline_id}) + if cursor.rowcount != 1: + return None + px, geojson, street_names = cursor.fetchone() + node = { + 'node_id': px, + 'network': 'px', + 'street_names': street_names, + 'geometry': json.loads(geojson) + } + return node \ No newline at end of file diff --git a/backend/app/nodes/conflation.py b/backend/app/nodes/conflation.py new file mode 100644 index 0000000..ac7ddba --- /dev/null +++ b/backend/app/nodes/conflation.py @@ -0,0 +1,43 @@ +from app.nodes.nearby.here import get_here_nodes_within +from app.nodes.byID.px import get_px_node +from app.nodes.nearby.centreline import get_nearest_centreline_node +from haversine import haversine + +def add_conflated_nodes(node): + """adds "conflated" field to node objects""" + + node['conflated'] = {} + lon = node['geometry']['coordinates'][0] + lat = node['geometry']['coordinates'][1] + + if node['network'] == 'centreline': + # adds px and here nodes + # px search is based on the centreline_id + node['conflated']['px'] = get_px_node(node['node_id']) + try: + # here search is based on distance + node['conflated']['here'] = get_here_nodes_within(50, lon, lat, 1)[0] + except: + pass + elif node['network'] == 'here': + # adds centreline and px nodes + # get centreline by nearest + node['conflated']['centreline'] = get_nearest_centreline_node(lon, lat) + # get px from Id of nearest centreline + node['conflated']['px'] = get_px_node(node['conflated']['centreline']['node_id']) + + # now get distances between selected and conflated points + for network, conflatedNode in node['conflated'].items(): + try: + conflatedNode['distance'] = haversine( + (lat, lon), + ( + conflatedNode['geometry']['coordinates'][1], + conflatedNode['geometry']['coordinates'][0] + ), + unit='m' + ) + except: + pass + + return node \ No newline at end of file diff --git a/backend/app/get_nearest_centreline_node.py b/backend/app/nodes/nearby/centreline.py similarity index 100% rename from backend/app/get_nearest_centreline_node.py rename to backend/app/nodes/nearby/centreline.py diff --git a/backend/app/get_nearest_here_nodes.py b/backend/app/nodes/nearby/here.py similarity index 91% rename from backend/app/get_nearest_here_nodes.py rename to backend/app/nodes/nearby/here.py index 37b282f..624b485 100644 --- a/backend/app/get_nearest_here_nodes.py +++ b/backend/app/nodes/nearby/here.py @@ -18,7 +18,11 @@ ''' def get_here_nodes_within(meters, longitude, latitude, limit=20): - """Return intersection(s) near a provided coordinate""" + """ + Return intersection(s) near a provided coordinate + + will only give nodes on the congestion network + """ with getConnection() as connection: with connection.cursor() as cursor: cursor.execute(SQL, {"latitude": latitude, "longitude": longitude, 'limit': limit}) diff --git a/backend/app/routes.py b/backend/app/routes.py index 79de6ef..880757d 100644 --- a/backend/app/routes.py +++ b/backend/app/routes.py @@ -3,9 +3,9 @@ from flask import jsonify, request from app import app from app.db import getConnection -from app.get_nearest_here_nodes import get_here_nodes_within -from app.get_here_node import get_here_node -from app.get_centreline_node import get_centreline_node +from app.nodes.nearby.here import get_here_nodes_within +from app.nodes.byID.here import get_here_node +from app.nodes.byID.centreline import get_centreline_node from app.get_travel_time import get_travel_time from app.get_here_links import get_here_links from app.get_centreline_links import get_centreline_links @@ -67,7 +67,7 @@ def get_node(node_id): arguments: node_id (int): identifier of the node in the latest Here map version optional GET arg ?doConflation will also return the nearest node in the other - network as well as it's distance in meters from the selected node + networks as well as their distance in meters from the main selected node """ try: node_id = int(node_id) diff --git a/backend/requirements.txt b/backend/requirements.txt index 2177ad6..fda9c16 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -7,4 +7,5 @@ pandas==2.2.2 psycopg==3.1.18 python-dotenv==0.15.0 numpy==1.26.0 -git+ssh://git@github.com/Toronto-Big-Data-Innovation-Team/traveltimetools.git@v1.0.0 \ No newline at end of file +git+ssh://git@github.com/Toronto-Big-Data-Innovation-Team/traveltimetools.git@v1.0.0 +haversine==2.9.0 \ No newline at end of file