From 23f5fa37d8f5432462fb0a387ea202df76e38635 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Mon, 10 Mar 2025 16:01:26 -0500 Subject: [PATCH 1/6] add dropdown menu and todos --- lib/editor/components/pattern/EditSettings.js | 26 +++++++++++++++++-- lib/editor/util/index.js | 5 ++++ lib/types/reducers.js | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/editor/components/pattern/EditSettings.js b/lib/editor/components/pattern/EditSettings.js index d353495fe..83d69122f 100644 --- a/lib/editor/components/pattern/EditSettings.js +++ b/lib/editor/components/pattern/EditSettings.js @@ -5,8 +5,8 @@ import {Alert, Checkbox, Form, FormControl, ControlLabel} from 'react-bootstrap' import Rcslider from 'rc-slider' import {updateEditSetting} from '../../actions/active' -import {CLICK_OPTIONS} from '../../util' -import toSentenceCase from '../../../common/util/to-sentence-case' +import {CLICK_OPTIONS, SNAP_TO_OPTIONS} from '../../util' +import toSentenceCase from '../../../common/util/text' import type {EditSettingsState} from '../../../types/reducers' type Props = { @@ -64,6 +64,7 @@ export default class EditSettings extends Component { stopInterval } = editSettings const SETTINGS = [ + // RAIL-TODO remove snap to streets {type: 'followStreets', label: 'Snap to streets'}, {type: 'avoidMotorways', label: 'Avoid highways in routing'}, {type: 'hideStopHandles', label: 'Hide stop handles'}, @@ -75,6 +76,27 @@ export default class EditSettings extends Component { const noSegmentIsActive = !patternSegment && patternSegment !== 0 return (
+ Snap to options + + {SNAP_TO_OPTIONS.map(v => { + // ADD_STOPS_AT_INTERSECTIONS only enabled for nysdot extenstion + // (due to custom r5 deployment) + // FIXME: Temporarily disable add stops at intersection entirely + // (needs to be fixed for sql editor). + const disabled = v === 'ADD_STOPS_AT_INTERSECTIONS' // && !isExtensionEnabled('nysdot') + return ( + + ) + })} + {SETTINGS.map((s, i) => ( = [ 'ADD_STOPS_AT_INTERVAL', 'ADD_STOPS_AT_INTERSECTIONS' ] +export const SNAP_TO_OPTIONS: Array = [ + 'NONE', + 'STREET', + 'RAIL' +] export const YEAR_FORMAT: string = 'YYYY-MM-DD' export const EXCEPTION_EXEMPLARS = { MONDAY: 0, diff --git a/lib/types/reducers.js b/lib/types/reducers.js index 010b8a233..c19011f7b 100644 --- a/lib/types/reducers.js +++ b/lib/types/reducers.js @@ -207,6 +207,7 @@ export type DataState = { } export type EditSettingsState = { + // RAIL-TODO add any types that are missing addStops: boolean, afterIntersection: boolean, avoidMotorways: boolean, From b809f44531021400c30fae0ba820f18849b6ceab Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Mon, 10 Mar 2025 16:45:00 -0500 Subject: [PATCH 2/6] use snap to option to calculate shape --- lib/editor/actions/map/index.js | 12 +-- lib/editor/actions/map/stopStrategies.js | 21 +++-- lib/editor/components/pattern/EditSettings.js | 18 +--- .../components/pattern/EditShapePanel.js | 4 +- lib/editor/reducers/settings.js | 9 +- lib/editor/util/map.js | 12 +-- lib/scenario-editor/utils/valhalla.js | 91 ++++++++++++++++--- lib/types/reducers.js | 3 +- 8 files changed, 114 insertions(+), 56 deletions(-) diff --git a/lib/editor/actions/map/index.js b/lib/editor/actions/map/index.js index f79304923..66ed08cee 100644 --- a/lib/editor/actions/map/index.js +++ b/lib/editor/actions/map/index.js @@ -162,17 +162,17 @@ export function handleControlPointDrag ( patternCoordinates: any ) { return function (dispatch: dispatchFn, getState: getStateFn) { - const {avoidMotorways, currentDragId, followStreets} = getState().editor.editSettings.present + const {avoidMotorways, currentDragId, snapToOption} = getState().editor.editSettings.present recalculateShape({ avoidMotorways, controlPoints, defaultToStraightLine: false, dragId: currentDragId, editType: 'update', - followStreets, index, newPoint: latlng, - patternCoordinates + patternCoordinates, + snapToOption }).then(result => { const {currentDragId} = getState().editor.editSettings.present // If there is a dragId in the store and it matches the result, the user @@ -204,17 +204,17 @@ export function handleControlPointDragEnd ( dispatch(controlPointDragOrEnd()) // recalculate shape for final position - const {avoidMotorways, followStreets} = getState().editor.editSettings.present + const {avoidMotorways, snapToOption} = getState().editor.editSettings.present recalculateShape({ avoidMotorways, controlPoints, defaultToStraightLine: false, editType: 'update', index, - followStreets, newPoint: latlng, patternCoordinates, - snapControlPointToNewSegment: true + snapControlPointToNewSegment: true, + snapToOption }).then(result => { // const {updatedShapePoints: shapePoints, updatedControlPoints} = result if (!result.coordinates) { diff --git a/lib/editor/actions/map/stopStrategies.js b/lib/editor/actions/map/stopStrategies.js index bc19e3236..831331320 100644 --- a/lib/editor/actions/map/stopStrategies.js +++ b/lib/editor/actions/map/stopStrategies.js @@ -220,9 +220,10 @@ export function addStopAtInterval (latlng: LatLng, activePattern: Pattern, contr } export function addStopToPattern (pattern: Pattern, stop: GtfsStop, index?: ?number) { + // eslint-disable-next-line complexity return async function (dispatch: dispatchFn, getState: getStateFn) { const {data, editSettings} = getState().editor - const {avoidMotorways, followStreets} = editSettings.present + const {avoidMotorways, snapToOption} = editSettings.present const {patternStops: currentPatternStops, shapePoints} = pattern const patternStops = clone(currentPatternStops) const {controlPoints, patternSegments} = getControlPoints(getState()) @@ -260,7 +261,7 @@ export function addStopToPattern (pattern: Pattern, stop: GtfsStop, index?: ?num } else { dispatch(updatePatternStops(pattern, patternStops)) // Otherwise, check if a shape ought to be created. Then, save. - if (patternStops.length === 2 && followStreets) { + if (patternStops.length === 2 && snapToOption) { // Create shape between stops the added stop is the second one and // followStreets is enabled. Otherwise, there is no need to create a // new shape because it would just be a straight line segment anyways. @@ -272,7 +273,7 @@ export function addStopToPattern (pattern: Pattern, stop: GtfsStop, index?: ?num } const points = [previousStop, stop] .map((stop, index) => ({lng: stop.stop_lon, lat: stop.stop_lat})) - const patternSegments = await getPolyline(points, true, avoidMotorways) + const patternSegments = await getPolyline(points, true, avoidMotorways, snapToOption) // Update pattern stops and geometry. const controlPoints = controlPointsFromSegments(patternStops, patternSegments) dispatch(updatePatternGeometry({controlPoints, patternSegments})) @@ -335,11 +336,11 @@ export function addStopToPattern (pattern: Pattern, stop: GtfsStop, index?: ?num controlPoints: clonedControlPoints, defaultToStraightLine: false, editType: 'update', - followStreets, index: spliceIndex, newPoint: {lng: stop.stop_lon, lat: stop.stop_lat}, snapControlPointToNewSegment: true, - patternCoordinates: clonedPatternSegments + patternCoordinates: clonedPatternSegments, + snapToOption }) } catch (err) { console.log(err) @@ -376,11 +377,11 @@ export function addStopToPattern (pattern: Pattern, stop: GtfsStop, index?: ?num controlPoints: clonedControlPoints, defaultToStraightLine: false, editType: 'update', - followStreets, index, newPoint: {lng: stop.stop_lon, lat: stop.stop_lat}, snapControlPointToNewSegment: true, - patternCoordinates: clonedPatternSegments + patternCoordinates: clonedPatternSegments, + snapToOption }) } catch (err) { console.log(err) @@ -406,12 +407,12 @@ export function addStopToPattern (pattern: Pattern, stop: GtfsStop, index?: ?num */ function extendPatternToPoint (pattern, endPoint, newEndPoint, stop = null, splitInterval = 0) { return async function (dispatch: dispatchFn, getState: getStateFn) { - const {avoidMotorways, followStreets} = getState().editor.editSettings.present + const {avoidMotorways, snapToOption} = getState().editor.editSettings.present const {controlPoints, patternSegments} = getControlPoints(getState()) const clonedControlPoints = clone(controlPoints) let newShape - if (followStreets) { - newShape = await getPolyline([endPoint, newEndPoint], false, avoidMotorways) + if (snapToOption) { + newShape = await getPolyline([endPoint, newEndPoint], false, avoidMotorways, snapToOption) } if (!newShape) { // Get single coordinate for straight line if polyline fails or if not diff --git a/lib/editor/components/pattern/EditSettings.js b/lib/editor/components/pattern/EditSettings.js index 83d69122f..4c247ed78 100644 --- a/lib/editor/components/pattern/EditSettings.js +++ b/lib/editor/components/pattern/EditSettings.js @@ -59,13 +59,11 @@ export default class EditSettings extends Component { const {editSettings, patternSegment, updateEditSetting} = this.props const { editGeometry, - followStreets, onMapClick, - stopInterval + stopInterval, + snapToOption } = editSettings const SETTINGS = [ - // RAIL-TODO remove snap to streets - {type: 'followStreets', label: 'Snap to streets'}, {type: 'avoidMotorways', label: 'Avoid highways in routing'}, {type: 'hideStopHandles', label: 'Hide stop handles'}, {type: 'hideInactiveSegments', label: 'Hide inactive segments'}, @@ -79,19 +77,13 @@ export default class EditSettings extends Component { Snap to options {SNAP_TO_OPTIONS.map(v => { - // ADD_STOPS_AT_INTERSECTIONS only enabled for nysdot extenstion - // (due to custom r5 deployment) - // FIXME: Temporarily disable add stops at intersection entirely - // (needs to be fixed for sql editor). - const disabled = v === 'ADD_STOPS_AT_INTERSECTIONS' // && !isExtensionEnabled('nysdot') return ( ) @@ -105,7 +97,7 @@ export default class EditSettings extends Component { // this state would cause the entire shape to disappear). disabled={ (s.type === 'hideInactiveSegments' && noSegmentIsActive) || - (s.type === 'avoidMotorways' && !followStreets) + (s.type === 'avoidMotorways' && snapToOption !== 'STREET') } name={s.type} style={{margin: '3px 0'}} diff --git a/lib/editor/components/pattern/EditShapePanel.js b/lib/editor/components/pattern/EditShapePanel.js index 9f72213de..a12da8a3b 100644 --- a/lib/editor/components/pattern/EditShapePanel.js +++ b/lib/editor/components/pattern/EditShapePanel.js @@ -51,8 +51,8 @@ export default class EditShapePanel extends Component { async drawPatternFromStops (pattern: Pattern, stopsCoordinates: Array, followStreets: boolean): Promise { const {editSettings, saveActiveGtfsEntity, setErrorMessage, updatePatternGeometry} = this.props let patternSegments = [] - if (followStreets) { - patternSegments = await getPolyline(stopsCoordinates, true, editSettings.present.avoidMotorways) + if (editSettings.present.snapToOption !== 'NONE') { + patternSegments = await getPolyline(stopsCoordinates, true, editSettings.present.avoidMotorways, editSettings.present.snapToOption) } else { // Construct straight-line segments using stop coordinates stopsCoordinates diff --git a/lib/editor/reducers/settings.js b/lib/editor/reducers/settings.js index 92d726367..63e44f098 100644 --- a/lib/editor/reducers/settings.js +++ b/lib/editor/reducers/settings.js @@ -20,7 +20,6 @@ export const defaultState = { currentDragId: null, distanceFromIntersection: 5, editGeometry: false, - followStreets: true, hideInactiveSegments: false, intersectionStep: 2, onMapClick: CLICK_OPTIONS[0], @@ -29,6 +28,7 @@ export const defaultState = { showStops: true, showTooltips: true, hideStopHandles: true, + snapToOption: 'NONE', stopInterval: 400 } @@ -96,6 +96,11 @@ export const reducers = { action: ActionType ): EditSettingsState { const {setting, value} = action.payload - return update(state, { [setting]: {$set: value} }) + // RAIL-TODO: make sure followStreet is properly set. + // RAIL-TODO: use in a lot of places, make sure nothing breaks???? + return update(state, { + [setting]: {$set: value}, + followStreets: {$set: value === 'STREET'} + }) } } diff --git a/lib/editor/util/map.js b/lib/editor/util/map.js index f11ae927a..2cdb2c1d6 100644 --- a/lib/editor/util/map.js +++ b/lib/editor/util/map.js @@ -263,22 +263,22 @@ export async function recalculateShape ({ defaultToStraightLine = true, dragId, editType, - followStreets, index, newPoint, patternCoordinates, - snapControlPointToNewSegment = false + snapControlPointToNewSegment = false, + snapToOption }: { avoidMotorways?: boolean, controlPoints: Array, defaultToStraightLine?: boolean, dragId?: null | string, editType: string, - followStreets: boolean, index: number, newPoint?: LatLng, patternCoordinates: Array, - snapControlPointToNewSegment?: boolean + snapControlPointToNewSegment?: boolean, + snapToOption: string }): Promise<{ coordinates: ?Array, dragId?: ?string, @@ -392,9 +392,9 @@ export async function recalculateShape ({ // calculate new segment (valhalla or straight line) const newSegment = await getSegment( pointsToRoute, - followStreets, defaultToStraightLine, - avoidMotorways + avoidMotorways, + snapToOption ) if (!newSegment || !newSegment.coordinates) { // If new segment calculation is unsuccessful, return null for coordinates and diff --git a/lib/scenario-editor/utils/valhalla.js b/lib/scenario-editor/utils/valhalla.js index c76a382c0..319e1cf32 100644 --- a/lib/scenario-editor/utils/valhalla.js +++ b/lib/scenario-editor/utils/valhalla.js @@ -1,6 +1,7 @@ // @flow import fetch from 'isomorphic-fetch' +import L from 'leaflet' import {decode as decodePolyline} from 'polyline' import {isEqual as coordinatesAreEqual} from '@conveyal/lonlat' import qs from 'qs' @@ -10,6 +11,7 @@ import lineString from 'turf-linestring' // debugging. // import {logCoordsToGeojsonio} from '../../editor/util/debug' +import { coordIsOutOfBounds } from '../../editor/util/map' import type { Coordinates, LatLng @@ -53,6 +55,13 @@ type GraphHopperResponse = { paths: Array } +type GraphHopperAlternateServer = { + BBOX: Array, + KEY?: string, + ROUTING_TYPE: string, + URL?: string +} + /** * Convert GraphHopper routing JSON response to polyline. */ @@ -106,7 +115,8 @@ function handleGraphHopperRouting (path: Path, individualLegs: boolean = false): export async function polyline ( points: Array, individualLegs?: boolean = false, - avoidMotorways?: boolean = false + avoidMotorways?: boolean = false, + snapToOption: string ): Promise { let json const geometry = [] @@ -126,7 +136,7 @@ export async function polyline ( const beginIndex = i + offset const endIndex = i + chunk + offset const chunkedPoints = points.slice(beginIndex, endIndex) - json = await routeWithGraphHopper(chunkedPoints, avoidMotorways) + json = await routeWithGraphHopper(chunkedPoints, avoidMotorways, snapToOption) const path = json && json.paths && json.paths[0] // Route between chunked list of points if (path) { @@ -148,21 +158,22 @@ export async function polyline ( export async function getSegment ( points: Coordinates, - followRoad: boolean, defaultToStraightLine: boolean = true, - avoidMotorways: boolean = false + avoidMotorways?: boolean = false, + snapToOption?: string ): Promise { // Store geometry to be returned here. let geometry - if (followRoad) { + if (snapToOption && snapToOption !== 'NONE') { // if snapping to streets, use routing service. const coordinates = await polyline( points.map(p => ({lng: p[0], lat: p[1]})), false, - avoidMotorways + avoidMotorways, + snapToOption ) if (!coordinates) { // If routing was unsuccessful, default to straight line (if desired by @@ -198,26 +209,64 @@ export async function getSegment ( * * Example URL: https://graphhopper.com/api/1/route?point=49.932707,11.588051&point=50.3404,11.64705&vehicle=car&debug=true&&type=json */ -export function routeWithGraphHopper (points: Array, avoidMotorways?: boolean): ?Promise { +export function routeWithGraphHopper ( + points: Array, + avoidMotorways?: boolean, + snapToOption: string +): ?Promise { if (points.length < 2) { console.warn('need at least two points to route with graphhopper', points) return null } - if (!process.env.GRAPH_HOPPER_KEY) { - throw new Error('GRAPH_HOPPER_KEY not set') - } + + let graphHopperUrl = '' + let graphHopperKey = '' + // Use custom url if it exists, otherwise default to the hosted service. - const GRAPH_HOPPER_URL = process.env.GRAPH_HOPPER_URL || 'https://graphhopper.com/api/1/' + if (process.env.GRAPH_HOPPER_ALTERNATES) { + // $FlowFixMe This is a bit of a hack and not how env variables are supposed to work, but the yaml loader supports it. + const alternates: Array = process.env.GRAPH_HOPPER_ALTERNATES + alternates.forEach(alternative => { + const { BBOX, ROUTING_TYPE, URL, KEY } = alternative + if (BBOX.length !== 4) { + console.warn('Invalid BBOX for GRAPH_HOPPER_ALTERNATIVE') + return + } + if (!URL) { + console.warn('No URL provided for alternative graphhopper server. Using open testing environment.') + } + + if (arePointsValid(points, BBOX)) { + if (snapToOption === 'RAIL') { + if (ROUTING_TYPE === 'RAIL' && URL) { + graphHopperUrl = URL + } else { // no URL or need default value so use openrailrouting test environment + graphHopperUrl = 'https://routing.openrailrouting.org/' + } + } else if (snapToOption === 'STREET') { + if (ROUTING_TYPE === 'STREET' && KEY && URL) { + graphHopperUrl = URL + graphHopperKey = KEY + } else { // no URL or need default value so use graphhopper test environment + graphHopperUrl = 'https://graphhopper.com/api/1/' + // include key here??? this will throw 401 i believe + } + } + // add more snapToOptions here if needed + } + }) + } + const params = { - key: process.env.GRAPH_HOPPER_KEY, + key: graphHopperKey, vehicle: 'car', debug: true, type: 'json' } const locations = points.map(p => (`point=${p.lat},${p.lng}`)).join('&') // Avoiding motorways requires a POST request with a formatted body - const graphHopperRequest = avoidMotorways - ? fetch(`${GRAPH_HOPPER_URL}route?key=${params.key}`, + const graphHopperRequest = avoidMotorways && snapToOption === 'STREET' + ? fetch(`${graphHopperUrl}route?key=${params.key}`, { body: JSON.stringify({ 'ch.disable': true, @@ -237,7 +286,19 @@ export function routeWithGraphHopper (points: Array, avoidMotorways?: bo }, method: 'POST' }) - : fetch(`${GRAPH_HOPPER_URL}route?${locations}&${qs.stringify(params)}`) + : fetch(`${graphHopperUrl}route?${locations}&${qs.stringify(params)}`) return graphHopperRequest.then(res => res.json()) } + +function arePointsValid (points, BBOX) { + return points.every( + (point) => !coordIsOutOfBounds( + point, + L.latLngBounds( + [BBOX[1], BBOX[0]], + [BBOX[3], BBOX[2]] + ) + ) + ) +} diff --git a/lib/types/reducers.js b/lib/types/reducers.js index c19011f7b..91a6f38c5 100644 --- a/lib/types/reducers.js +++ b/lib/types/reducers.js @@ -207,7 +207,6 @@ export type DataState = { } export type EditSettingsState = { - // RAIL-TODO add any types that are missing addStops: boolean, afterIntersection: boolean, avoidMotorways: boolean, @@ -215,7 +214,6 @@ export type EditSettingsState = { currentDragId: null | string, distanceFromIntersection: number, editGeometry: boolean, - followStreets: boolean, hideInactiveSegments: boolean, hideStopHandles: boolean, intersectionStep: number, @@ -224,6 +222,7 @@ export type EditSettingsState = { shapePoints: ?Array, showStops: boolean, showTooltips: boolean, + snapToOption: string, stopInterval: number } From 356c46e5fc497813cd669794469e0677c4f5f337 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Thu, 6 Mar 2025 13:39:34 -0600 Subject: [PATCH 3/6] remove uses of followStreets --- lib/editor/actions/map/index.js | 6 +++--- lib/editor/actions/map/stopStrategies.js | 6 +++--- lib/editor/components/pattern/EditShapePanel.js | 6 +++--- lib/editor/reducers/settings.js | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/editor/actions/map/index.js b/lib/editor/actions/map/index.js index 66ed08cee..51aaf4615 100644 --- a/lib/editor/actions/map/index.js +++ b/lib/editor/actions/map/index.js @@ -244,7 +244,7 @@ export function handleControlPointDragStart (controlPoint: ControlPoint) { export function removeControlPoint (controlPoints: Array, index: number, pattern: Pattern, patternCoordinates: any) { return async function (dispatch: dispatchFn, getState: getStateFn) { - const {avoidMotorways, followStreets} = getState().editor.editSettings.present + const {avoidMotorways, snapToOption} = getState().editor.editSettings.present const { coordinates, updatedControlPoints @@ -253,8 +253,8 @@ export function removeControlPoint (controlPoints: Array, index: n controlPoints, editType: 'delete', index, - followStreets, - patternCoordinates + patternCoordinates, + snapToOption }) // Update active pattern in store (does not save to server). dispatch(updatePatternGeometry({ diff --git a/lib/editor/actions/map/stopStrategies.js b/lib/editor/actions/map/stopStrategies.js index 831331320..b164f3850 100644 --- a/lib/editor/actions/map/stopStrategies.js +++ b/lib/editor/actions/map/stopStrategies.js @@ -504,7 +504,7 @@ export function removeStopFromPattern (pattern: Pattern, stop: GtfsStop, index: // If pattern has no shape points, don't attempt to refactor pattern shape console.log('pattern coordinates do not exist') } else { - const {avoidMotorways, followStreets} = getState().editor.editSettings.present + const {avoidMotorways, snapToOption} = getState().editor.editSettings.present let result try { result = await recalculateShape({ @@ -512,8 +512,8 @@ export function removeStopFromPattern (pattern: Pattern, stop: GtfsStop, index: controlPoints: clonedControlPoints, editType: 'delete', index: cpIndex, - followStreets, - patternCoordinates: clonedPatternSegments + patternCoordinates: clonedPatternSegments, + snapToOption }) } catch (err) { console.log(err) diff --git a/lib/editor/components/pattern/EditShapePanel.js b/lib/editor/components/pattern/EditShapePanel.js index a12da8a3b..1b1a18cfd 100644 --- a/lib/editor/components/pattern/EditShapePanel.js +++ b/lib/editor/components/pattern/EditShapePanel.js @@ -48,7 +48,7 @@ export default class EditShapePanel extends Component { /** * Construct new pattern geometry from the pattern stop locations. */ - async drawPatternFromStops (pattern: Pattern, stopsCoordinates: Array, followStreets: boolean): Promise { + async drawPatternFromStops (pattern: Pattern, stopsCoordinates: Array): Promise { const {editSettings, saveActiveGtfsEntity, setErrorMessage, updatePatternGeometry} = this.props let patternSegments = [] if (editSettings.present.snapToOption !== 'NONE') { @@ -92,7 +92,7 @@ export default class EditShapePanel extends Component { } _generateShapeFromStops = () => { - const {activePattern, editSettings, stops} = this.props + const {activePattern, stops} = this.props const stopLocations = stops && activePattern.patternStops && activePattern.patternStops.length ? activePattern.patternStops .map((s, index) => { @@ -104,7 +104,7 @@ export default class EditShapePanel extends Component { return {lng: stop.stop_lon, lat: stop.stop_lat} }) : [] - this.drawPatternFromStops(activePattern, stopLocations, editSettings.present.followStreets) + this.drawPatternFromStops(activePattern, stopLocations) } _confirmCreateFromStops = () => { diff --git a/lib/editor/reducers/settings.js b/lib/editor/reducers/settings.js index 63e44f098..b0b0a0cef 100644 --- a/lib/editor/reducers/settings.js +++ b/lib/editor/reducers/settings.js @@ -49,7 +49,7 @@ export const reducers = { ...defaultState, // Do not reset follow streets if exiting pattern editing. // TODO: Are there other edit settings that should not be overridden? - followStreets: state.followStreets + snapToOption: state.snapToOption } }, 'SETTING_ACTIVE_GTFS_ENTITY' ( From d69c4217d78e8f56196b2c57b9f4356686d364aa Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Fri, 7 Mar 2025 14:00:15 -0600 Subject: [PATCH 4/6] update params sent to rail router --- lib/scenario-editor/utils/valhalla.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/scenario-editor/utils/valhalla.js b/lib/scenario-editor/utils/valhalla.js index 319e1cf32..509a4786e 100644 --- a/lib/scenario-editor/utils/valhalla.js +++ b/lib/scenario-editor/utils/valhalla.js @@ -261,7 +261,12 @@ export function routeWithGraphHopper ( key: graphHopperKey, vehicle: 'car', debug: true, - type: 'json' + type: 'json', + profile: '' + } + if (snapToOption === 'RAIL') { + delete params.vehicle // vehicle is not supported in current open rail router version + params.profile = 'all_tracks' // this can be changed to return better results if needed } const locations = points.map(p => (`point=${p.lat},${p.lng}`)).join('&') // Avoiding motorways requires a POST request with a formatted body From ddb43520c8f0bf3391b272045a34a6dca441f894 Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Tue, 11 Mar 2025 14:20:10 -0500 Subject: [PATCH 5/6] use util functions from dev branch --- lib/common/util/text.js | 8 ++++++++ lib/editor/util/map.js | 15 ++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 lib/common/util/text.js diff --git a/lib/common/util/text.js b/lib/common/util/text.js new file mode 100644 index 000000000..2bb811e5f --- /dev/null +++ b/lib/common/util/text.js @@ -0,0 +1,8 @@ +// @flow + +import toLower from 'lodash/toLower' +import upperFirst from 'lodash/upperFirst' + +export default function toSentenceCase (s: string): string { + return upperFirst(toLower(s)) +} diff --git a/lib/editor/util/map.js b/lib/editor/util/map.js index 2cdb2c1d6..953cde447 100644 --- a/lib/editor/util/map.js +++ b/lib/editor/util/map.js @@ -44,11 +44,16 @@ type R5Response = { }> } -export const stopIsOutOfBounds = (stop: GtfsStop, bounds: any) => { - return stop.stop_lat > bounds.getNorth() || - stop.stop_lat < bounds.getSouth() || - stop.stop_lon > bounds.getEast() || - stop.stop_lon < bounds.getWest() +export const coordIsOutOfBounds = (coords: LatLng, bounds: Bounds) => { + if (!coords || !coords.lat || !coords.lng || !bounds) return true + + return coords.lat > bounds.getNorth() || + coords.lat < bounds.getSouth() || + coords.lng > bounds.getEast() || + coords.lng < bounds.getWest() +} +export const stopIsOutOfBounds = (stop: GtfsStop, bounds: Bounds) => { + return coordIsOutOfBounds({lat: stop.stop_lat, lng: stop.stop_lon}, bounds) } export const getStopIcon = ( From 69187fbef1e3a093b3a39449f6b6dd68ea7ff47b Mon Sep 17 00:00:00 2001 From: Josh Willis <168561922+josh-willis-arcadis@users.noreply.github.com> Date: Tue, 11 Mar 2025 14:48:10 -0500 Subject: [PATCH 6/6] use type from leaflet --- lib/editor/util/map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/editor/util/map.js b/lib/editor/util/map.js index 953cde447..e3846d6ee 100644 --- a/lib/editor/util/map.js +++ b/lib/editor/util/map.js @@ -1,7 +1,7 @@ // @flow import ll from '@conveyal/lonlat' -import {divIcon} from 'leaflet' +import {Bounds, divIcon} from 'leaflet' import clone from 'lodash/cloneDeep' import fetch from 'isomorphic-fetch' import distance from '@turf/distance'