diff --git a/backend/app/get_centreline_node.py b/backend/app/get_centreline_node.py new file mode 100644 index 0000000..2cefb85 --- /dev/null +++ b/backend/app/get_centreline_node.py @@ -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 diff --git a/backend/app/get_node.py b/backend/app/get_here_node.py similarity index 93% rename from backend/app/get_node.py rename to backend/app/get_here_node.py index 0bf4eba..43400e7 100644 --- a/backend/app/get_node.py +++ b/backend/app/get_here_node.py @@ -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: @@ -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) } diff --git a/backend/app/get_nearest_centreline_node.py b/backend/app/get_nearest_centreline_node.py index c15bfa7..b28200a 100644 --- a/backend/app/get_nearest_centreline_node.py +++ b/backend/app/get_nearest_centreline_node.py @@ -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 diff --git a/backend/app/get_closest_nodes.py b/backend/app/get_nearest_here_nodes.py similarity index 84% rename from backend/app/get_closest_nodes.py rename to backend/app/get_nearest_here_nodes.py index a1add95..37b282f 100644 --- a/backend/app/get_closest_nodes.py +++ b/backend/app/get_nearest_here_nodes.py @@ -1,5 +1,3 @@ -"""Return intersection(s) near a provided coordinate""" - import json from app.db import getConnection @@ -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) } ) diff --git a/backend/app/routes.py b/backend/app/routes.py index c2b52b7..79de6ef 100644 --- a/backend/app/routes.py +++ b/backend/app/routes.py @@ -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 @@ -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///', methods=['GET']) def closest_node(meters, longitude, latitude): """Return up to 20 nodes within a given radius (in meters) of a point. @@ -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/', 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/', endpoint='generic') # will be deprecated +@app.route('/node/here/', endpoint='here') +@app.route('/node/centreline/', 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 diff --git a/frontend/src/Sidebar/restoreStateFromFile.js b/frontend/src/Sidebar/restoreStateFromFile.js index bf80744..9592f8e 100644 --- a/frontend/src/Sidebar/restoreStateFromFile.js +++ b/frontend/src/Sidebar/restoreStateFromFile.js @@ -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,