Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add endpoint for fetching centreline nodes by ID #174

Merged
merged 10 commits into from
Jan 3, 2025
40 changes: 40 additions & 0 deletions backend/app/get_centreline_node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import json
from app.db import getConnection
from app.get_nearest_here_nodes import get_here_nodes_within

SQL = '''
SELECT
ST_AsGeoJSON(geom) AS geojson,
ARRAY_AGG(DISTINCT linear_name_full_from) AS street_names
FROM gis_core.intersection_latest
WHERE intersection_id = %(node_id)s
GROUP BY geom;

'''

def get_centreline_node(node_id, conflate_with_here=False):
"""fetch a specific centreline node by it's ID"""
node = {}
with getConnection() as connection:
with connection.cursor() as cursor:
cursor.execute(SQL, {"node_id": node_id})
if cursor.rowcount != 1:
return None
geojson, street_names = cursor.fetchone()
node = {
'node_id': node_id,
'network': 'centreline',
'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()
return node
3 changes: 2 additions & 1 deletion backend/app/get_node.py → backend/app/get_here_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
here_nodes.geom;
'''

def get_node(node_id, conflate_with_centreline=False):
def get_here_node(node_id, conflate_with_centreline=False):
node = {}
with getConnection() as connection:
with connection.cursor() as cursor:
Expand All @@ -28,6 +28,7 @@ def get_node(node_id, conflate_with_centreline=False):
geojson, street_names = cursor.fetchone()
node = {
'node_id': node_id,
'network': 'here',
'street_names': street_names,
'geometry': json.loads(geojson)
}
Expand Down
4 changes: 3 additions & 1 deletion backend/app/get_nearest_centreline_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ def get_nearest_centreline_node(longitude, latitude):
cursor.execute(SQL, {'longitude': longitude, 'latitude': latitude})
centreline_id, geojson, distance, street_names = cursor.fetchone()
node = {
'centreline_id': centreline_id,
'centreline_id': centreline_id, # deprecated
'node_id': centreline_id,
'network': 'centreline',
'street_names': street_names,
'geometry': loadJSON(geojson),
'distance': distance
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"""Return intersection(s) near a provided coordinate"""

import json
from app.db import getConnection

Expand All @@ -16,18 +14,20 @@
cg_nodes.node_id,
cg_nodes.geom
ORDER BY distance
LIMIT 20;
LIMIT %(limit)s;
'''

def get_nodes_within(meters,longitude, latitude):
def get_here_nodes_within(meters, longitude, latitude, limit=20):
"""Return intersection(s) near a provided coordinate"""
with getConnection() as connection:
with connection.cursor() as cursor:
cursor.execute(SQL, {"latitude": latitude, "longitude": longitude})
cursor.execute(SQL, {"latitude": latitude, "longitude": longitude, 'limit': limit})
candidate_nodes = []
for node_id, geojson, distance, street_names in cursor.fetchall():
if distance <= meters:
candidate_nodes.append( {
'node_id': node_id,
'network': 'here',
'street_names': street_names,
'geometry': json.loads(geojson)
} )
Expand Down
36 changes: 22 additions & 14 deletions backend/app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from flask import jsonify, request
from app import app
from app.db import getConnection
from app.get_closest_nodes import get_nodes_within
from app.get_node import get_node
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.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 @@ -32,7 +33,7 @@ def version():
'git-HEAD': getGitHash()
})

# test URL /closest-node/-79.3400/43.6610
# test URL /nodes-within/50/-79.3400/43.6610
@app.route('/nodes-within/<meters>/<longitude>/<latitude>', methods=['GET'])
def closest_node(meters, longitude, latitude):
"""Return up to 20 nodes within a given radius (in meters) of a point.
Expand All @@ -50,28 +51,35 @@ def closest_node(meters, longitude, latitude):
meters = float(meters)
except:
return jsonify({'error': "all inputs must be decimal numbers"})
return jsonify(get_nodes_within(meters,longitude,latitude))

# test URL /node/30357505
@app.route('/node/<node_id>', methods=['GET'])
def node(node_id):
"""Returns information about a given node in the Here street network.

This uses the latest map version and may not recognize an older node_id.
return jsonify(get_here_nodes_within(meters,longitude,latitude))

# test URL /node/here/30357505
@app.route('/node/<node_id>', endpoint='generic') # will be deprecated
@app.route('/node/here/<node_id>', endpoint='here')
@app.route('/node/centreline/<node_id>', endpoint='centreline')
def get_node(node_id):
"""Returns information about a given node in the either the Here or
Centreline street networks.

This uses the latest version of either network and may not recognize an
older 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 centreline network
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
"""
try:
node_id = int(node_id)
except:
return jsonify({'error': "node_id should be an integer"})

doConflation = False
if request.args.get('doConflation') is not None:
doConflation = True
node = get_node(node_id, doConflation)
if request.endpoint == 'centreline':
node = get_centreline_node(node_id, doConflation)
else: # here network
node = get_here_node(node_id, doConflation)
return jsonify(node if node else {'error': 'node not found'})

# test URL /link-nodes/here/30421154/30421153
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/Sidebar/restoreStateFromFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export async function restoreStateFromFile(fileDropEvent,stateData,logActivity){
let corridor = stateData.createCorridor()
Promise.all(
[startNode,endNode].map(node_id => {
return fetch(`${domain}/node/${node_id}`)
return fetch(`${domain}/node/here/${node_id}`)
.then( resp => resp.json() )
.then( node => new Intersection( {
id: node.node_id,
Expand Down
Loading