Skip to content

Commit

Permalink
Merge pull request #351 from headwaymaps/mkirk/otp-bike
Browse files Browse the repository at this point in the history
Include better OTP results in walk/bike directions when available.
  • Loading branch information
michaelkirk authored May 9, 2024
2 parents 70f174f + 1709e24 commit fb250fb
Show file tree
Hide file tree
Showing 18 changed files with 1,499 additions and 838 deletions.
11 changes: 2 additions & 9 deletions services/frontend/www-app/src/components/SingleModeListItem.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
<template>
<q-item-label>
{{ $t('via_$place', { place: route.viaRoadsFormatted }) }}
<q-item-label v-if="trip.viaRoadsFormatted">
{{ $t('via_$place', { place: trip.viaRoadsFormatted }) }}
</q-item-label>
</template>

<script lang="ts">
import Route from 'src/models/Route';
import { defineComponent, PropType } from 'vue';
import Trip from 'src/models/Trip';
export default defineComponent({
name: 'SingleModeListItem',
data(): { route: Route } {
// this cast is safe because we know that it's a non-transit trip
const route = this.trip.nonTransitRoute() as Route;
console.assert(route);
return { route };
},
props: {
trip: {
type: Object as PropType<Trip>,
Expand Down
25 changes: 10 additions & 15 deletions services/frontend/www-app/src/components/SingleModeSteps.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<q-item
class="maneuver"
active-class="bg-blue-1"
v-for="maneuver in route.valhallaRoute.legs[0].maneuvers"
v-for="maneuver in nonTransitLeg.maneuvers"
clickable
v-on:click="clickedManeuver(maneuver)"
v-bind:key="JSON.stringify(maneuver)"
Expand All @@ -16,7 +16,7 @@
{{ maneuver.instruction }}
</q-item-label>
<q-item-label caption>
{{ maneuver.verbal_post_transition_instruction }}
{{ maneuver.verbalPostTransitionInstruction }}
</q-item-label>
</q-item-section>
</q-item>
Expand All @@ -32,14 +32,11 @@
</style>

<script lang="ts">
import Route from 'src/models/Route';
import { defineComponent, PropType } from 'vue';
import {
ValhallaRouteLegManeuver,
valhallaTypeToIcon,
} from 'src/services/ValhallaAPI';
import { valhallaTypeToIcon } from 'src/services/ValhallaAPI';
import { getBaseMap } from './BaseMap.vue';
import Trip from 'src/models/Trip';
import { NonTransitLeg, TravelmuxManeuver } from 'src/services/TravelmuxClient';
export default defineComponent({
name: 'SingleModeSteps',
Expand All @@ -51,22 +48,20 @@ export default defineComponent({
},
data(): {
geometry: GeoJSON.LineString;
route: Route;
nonTransitLeg: NonTransitLeg;
} {
// this cast is safe because we know that the trip is a non-transit trip
const route = this.trip.nonTransitRoute() as Route;
console.assert(route);
const nonTransitLeg = this.trip.legs[0]?.raw.nonTransitLeg as NonTransitLeg;
console.assert(nonTransitLeg);
return {
route,
nonTransitLeg,
geometry: this.trip.legs[0].geometry,
};
},
methods: {
valhallaTypeToIcon,
clickedManeuver: function (maneuver: ValhallaRouteLegManeuver) {
const location = this.geometry.coordinates[maneuver.begin_shape_index];
let coord: [number, number] = [location[0], location[1]];
getBaseMap()?.flyTo(coord, { zoom: 16 });
clickedManeuver: function (maneuver: TravelmuxManeuver) {
getBaseMap()?.flyTo(maneuver.startPoint, { zoom: 16 });
},
},
});
Expand Down
24 changes: 13 additions & 11 deletions services/frontend/www-app/src/models/Trip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { LineLayerSpecification, LngLat, LngLatBounds } from 'maplibre-gl';
import { DistanceUnits, TravelMode } from 'src/utils/models';
import { Result } from 'src/utils/Result';
import Itinerary from './Itinerary';
import Route from './Route';
import {
TravelmuxMode,
TravelmuxClient,
Expand All @@ -14,18 +13,19 @@ import {
} from 'src/services/TravelmuxClient';
import { formatDistance, formatDuration } from 'src/utils/format';
import { decodePolyline } from 'src/utils/decodePolyline';
import { i18n } from 'src/i18n/lang';

export default class Trip {
raw: TravelmuxItinerary;
inner: Route | Itinerary;
inner: Itinerary | null;
preferredDistanceUnits: DistanceUnits;
innerDistanceUnits: DistanceUnits;
legs: TripLeg[];

constructor(
raw: TravelmuxItinerary,
preferredDistanceUnits: DistanceUnits,
inner: Route | Itinerary,
inner: Itinerary | null,
innerDistanceUnits: DistanceUnits,
) {
this.raw = raw;
Expand All @@ -39,6 +39,16 @@ export default class Trip {
return formatDuration(this.raw.duration, 'shortform');
}

get viaRoadsFormatted(): string | null {
const names = this.raw.legs.flatMap((leg) => {
return leg.nonTransitLeg?.substantialStreetNames;
});
if (names.length == 0) {
return null;
}
return names.join(i18n.global.t('punctuation_list_seperator'));
}

get distanceFormatted(): string | undefined {
return formatDistance(
this.raw.distance,
Expand All @@ -62,14 +72,6 @@ export default class Trip {
return undefined;
}
}

nonTransitRoute(): Route | undefined {
if (this.mode != TravelMode.Transit) {
return this.inner as Route;
} else {
return undefined;
}
}
}

export class TripLeg {
Expand Down
72 changes: 30 additions & 42 deletions services/frontend/www-app/src/services/TravelmuxClient.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LngLat } from 'maplibre-gl';
import { LngLat, LngLatLike } from 'maplibre-gl';
import { DistanceUnits, TravelMode } from 'src/utils/models';
import { Ok, Err, Result } from 'src/utils/Result';
import Trip, { TripFetchError } from 'src/models/Trip';
Expand All @@ -7,13 +7,8 @@ import {
OTPItinerary,
OTPItineraryLeg,
} from './OpenTripPlannerAPI';
import {
ValhallaRouteResponse,
ValhallaRoute,
ValhallaErrorCode,
} from './ValhallaAPI';
import { ValhallaRouteResponse, ValhallaErrorCode } from './ValhallaAPI';
import Itinerary from 'src/models/Itinerary';
import Route from 'src/models/Route';
import { zipWith } from 'lodash';

export interface TravelmuxPlanResponse {
Expand All @@ -32,6 +27,20 @@ export interface TravelmuxLeg {
duration: number;
geometry: string;
transitLeg?: OTPItineraryLeg;
nonTransitLeg?: NonTransitLeg;
}

export interface NonTransitLeg {
maneuvers: [TravelmuxManeuver];
substantialStreetNames?: string[];
}

export interface TravelmuxManeuver {
instruction?: string;
verbalPostTransitionInstruction?: string;
startPoint: LngLatLike;
// same as valhalla's maneuver type
type: number;
}

export interface TravelmuxItinerary {
Expand Down Expand Up @@ -120,7 +129,7 @@ export class TravelmuxClient {

const query = new URLSearchParams(params).toString();

const response = await fetch('/travelmux/v4/plan?' + query);
const response = await fetch('/travelmux/v5/plan?' + query);

if (response.ok) {
const travelmuxResponseJson: TravelmuxPlanResponse =
Expand Down Expand Up @@ -149,42 +158,21 @@ export class TravelmuxClient {
},
);
return Ok(trips);
} else if (travelmuxResponseJson._valhalla) {
const routes: ValhallaRoute[] = [];
if (travelmuxResponseJson._valhalla.trip) {
routes.push(travelmuxResponseJson._valhalla.trip);
}
for (const route of travelmuxResponseJson._valhalla.alternates || []) {
if (route.trip) {
routes.push(route.trip);
}
}
const trips = zipWith(
tmxItineraries,
routes,
(tmxItinerary: TravelmuxItinerary, valhallaRoute: ValhallaRoute) => {
console.assert(tmxItinerary, 'expected tmxItinerary to be set');
console.assert(valhallaRoute, 'expected valhallaRoute to be set');
const route = Route.fromValhalla(
valhallaRoute,
travelModeFromTravelmuxMode(modes[0]),
preferredDistanceUnits,
);
console.assert(
preferredDistanceUnits == tmxItinerary.distanceUnits,
'expected preferredDistanceUnits to match tmxItinerary.distanceUnits for valhalla requests',
);
return new Trip(
tmxItinerary,
preferredDistanceUnits,
route,
tmxItinerary.distanceUnits,
);
},
} else {
console.assert(
travelmuxResponseJson._valhalla,
'expected valhalla in non-transit response',
);
const trips = tmxItineraries.map((tmxItinerary: TravelmuxItinerary) => {
console.assert(tmxItinerary, 'expected tmxItinerary to be set');
return new Trip(
tmxItinerary,
preferredDistanceUnits,
null,
tmxItinerary.distanceUnits,
);
});
return Ok(trips);
} else {
throw Error('missing routing backend');
}
} else {
const errorBody = await response.json();
Expand Down
2 changes: 1 addition & 1 deletion services/travelmux/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ mod app_state;
pub use app_state::AppState;

pub mod health;
pub mod v3;
pub mod v4;
pub mod v5;
1 change: 0 additions & 1 deletion services/travelmux/src/api/v3/mod.rs

This file was deleted.

Loading

0 comments on commit fb250fb

Please sign in to comment.