Skip to content

Commit

Permalink
Extend node conflation to px traffic signals (#175)
Browse files Browse the repository at this point in the history
* conflate px with centreline nodes

* organize node-fetching functions in folders

* organize nearby node searches into folders

* put all conflation logic in one place

* get street names for `px`

* measure distance to conflated nodes

* use try block
  • Loading branch information
Nate-Wessel authored Jan 7, 2025
1 parent d15c6a6 commit 4d3bbba
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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:
Expand All @@ -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
10 changes: 3 additions & 7 deletions backend/app/get_here_node.py → backend/app/nodes/byID/here.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
35 changes: 35 additions & 0 deletions backend/app/nodes/byID/px.py
Original file line number Diff line number Diff line change
@@ -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
43 changes: 43 additions & 0 deletions backend/app/nodes/conflation.py
Original file line number Diff line number Diff line change
@@ -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
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
8 changes: 4 additions & 4 deletions backend/app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ pandas==2.2.2
psycopg==3.1.18
python-dotenv==0.15.0
numpy==1.26.0
git+ssh://[email protected]/Toronto-Big-Data-Innovation-Team/[email protected]
git+ssh://[email protected]/Toronto-Big-Data-Innovation-Team/[email protected]
haversine==2.9.0

0 comments on commit 4d3bbba

Please sign in to comment.