@opentripplanner/core-utils 9.0.0-alpha.3 → 9.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/itinerary.ts CHANGED
@@ -4,9 +4,10 @@ import {
4
4
  Config,
5
5
  ElevationProfile,
6
6
  FlexBookingInfo,
7
- Itinerary,
7
+ ItineraryOnlyLegsRequired,
8
8
  LatLngArray,
9
9
  Leg,
10
+ MassUnitOption,
10
11
  Money,
11
12
  Place,
12
13
  Step,
@@ -212,7 +213,9 @@ export function getCompanyFromLeg(leg: Leg): string {
212
213
  return null;
213
214
  }
214
215
 
215
- export function getItineraryBounds(itinerary: Itinerary): LatLngArray[] {
216
+ export function getItineraryBounds(
217
+ itinerary: ItineraryOnlyLegsRequired
218
+ ): LatLngArray[] {
216
219
  let coords = [];
217
220
  itinerary.legs.forEach(leg => {
218
221
  const legCoords = polyline
@@ -407,7 +410,7 @@ export function getTNCLocation(leg: Leg, type: string): string {
407
410
  }
408
411
 
409
412
  export function calculatePhysicalActivity(
410
- itinerary: Itinerary
413
+ itinerary: ItineraryOnlyLegsRequired
411
414
  ): {
412
415
  bikeDuration: number;
413
416
  caloriesBurned: number;
@@ -433,7 +436,9 @@ export function calculatePhysicalActivity(
433
436
  * these values and currency info.
434
437
  * It is assumed that the same currency is used for all TNC legs.
435
438
  */
436
- export function calculateTncFares(itinerary: Itinerary): TncFare {
439
+ export function calculateTncFares(
440
+ itinerary: ItineraryOnlyLegsRequired
441
+ ): TncFare {
437
442
  return itinerary.legs
438
443
  .filter(leg => leg.mode === "CAR" && leg.hailedCar && leg.tncData)
439
444
  .reduce(
@@ -501,15 +506,16 @@ const CARBON_INTENSITY_DEFAULTS = {
501
506
  };
502
507
 
503
508
  /**
504
- * @param {itinerary} itinerary OTP trip itinierary
505
- * @param {carbonIntensity} carbonIntensity carbon intensity by mode in grams/meter
509
+ * @param {itinerary} itinerary OTP trip itinierary, only legs is required.
510
+ * @param {carbonIntensity} carbonIntensity carbon intensity by mode in grams/meter
506
511
  * @param {units} units units to be used in return value
507
512
  * @return Amount of carbon in chosen unit
508
513
  */
509
514
  export function calculateEmissions(
510
- itinerary: Itinerary,
515
+ // This type makes all the properties from Itinerary optional except legs.
516
+ itinerary: ItineraryOnlyLegsRequired,
511
517
  carbonIntensity: Record<string, number> = {},
512
- units?: string
518
+ units?: MassUnitOption
513
519
  ): number {
514
520
  // Apply defaults for any values that we don't have.
515
521
  const carbonIntensityWithDefaults = {
@@ -51,6 +51,12 @@ query PlanQuery(
51
51
  id
52
52
  timezone
53
53
  url
54
+ alerts {
55
+ alertHeaderText
56
+ alertDescriptionText
57
+ alertUrl
58
+ effectiveStartDate
59
+ }
54
60
  }
55
61
  legGeometry {
56
62
  length
@@ -70,6 +76,12 @@ query PlanQuery(
70
76
  textColor
71
77
  id
72
78
  type
79
+ alerts {
80
+ alertHeaderText
81
+ alertDescriptionText
82
+ alertUrl
83
+ effectiveStartDate
84
+ }
73
85
  }
74
86
  from {
75
87
  lat
@@ -79,7 +91,12 @@ query PlanQuery(
79
91
  stop {
80
92
  id
81
93
  code
82
-
94
+ alerts {
95
+ alertHeaderText
96
+ alertDescriptionText
97
+ alertUrl
98
+ effectiveStartDate
99
+ }
83
100
  }
84
101
  }
85
102
  to {
@@ -90,12 +107,29 @@ query PlanQuery(
90
107
  stop {
91
108
  id
92
109
  code
110
+ alerts {
111
+ alertHeaderText
112
+ alertDescriptionText
113
+ alertUrl
114
+ effectiveStartDate
115
+ }
93
116
  }
94
117
  }
95
118
  steps {
96
119
  distance
97
120
  lat
98
121
  lon
122
+ relativeDirection
123
+ absoluteDirection
124
+ stayOn
125
+ streetName
126
+ area
127
+ alerts{
128
+ alertHeaderText
129
+ alertDescriptionText
130
+ alertUrl
131
+ effectiveStartDate
132
+ }
99
133
  elevationProfile {
100
134
  distance
101
135
  elevation
package/src/query-gen.ts CHANGED
@@ -9,12 +9,52 @@ import { LonLatOutput } from "@conveyal/lonlat";
9
9
  import PlanQuery from "./planQuery.graphql";
10
10
 
11
11
  type OTPQueryParams = {
12
- to: LonLatOutput;
13
- from: LonLatOutput;
12
+ to: LonLatOutput & { name?: string };
13
+ from: LonLatOutput & { name?: string };
14
14
  modes: Array<TransportMode>;
15
15
  modeSettings: ModeSetting[];
16
16
  };
17
17
 
18
+ type GraphQLQuery = {
19
+ query: string;
20
+ variables: Record<string, unknown>;
21
+ };
22
+
23
+ /**
24
+ * Mode Settings can contain additional modes to add to the query,
25
+ * this function extracts those additional modes from the settings
26
+ * and returns them in an array.
27
+ * @param modeSettings List of mode settings with values populated
28
+ * @returns Additional transport modes to add to query
29
+ */
30
+ export function extractAdditionalModes(
31
+ modeSettings: ModeSetting[],
32
+ enabledModes: TransportMode[]
33
+ ): Array<TransportMode> {
34
+ return modeSettings.reduce<TransportMode[]>((prev, cur) => {
35
+ // First, ensure that the mode associated with this setting is even enabled
36
+ if (!enabledModes.map(m => m.mode).includes(cur.applicableMode)) {
37
+ return prev;
38
+ }
39
+
40
+ // In checkboxes, mode must be enabled and have a transport mode in it
41
+ if (cur.type === "CHECKBOX" && cur.addTransportMode && cur.value) {
42
+ return [...prev, cur.addTransportMode];
43
+ }
44
+ if (cur.type === "DROPDOWN") {
45
+ const transportMode = cur.options.find(o => o.value === cur.value)
46
+ .addTransportMode;
47
+ if (transportMode) {
48
+ return [
49
+ ...prev,
50
+ cur.options.find(o => o.value === cur.value).addTransportMode
51
+ ];
52
+ }
53
+ }
54
+ return prev;
55
+ }, []);
56
+ }
57
+
18
58
  /**
19
59
  * Generates every possible mathematical subset of the input TransportModes.
20
60
  * Uses code from:
@@ -32,6 +72,7 @@ function combinations(array: TransportMode[]): TransportMode[][] {
32
72
  .map((e1, i) => array.filter((e2, j) => i & (1 << j)))
33
73
  );
34
74
  }
75
+
35
76
  export const SIMPLIFICATIONS = {
36
77
  AIRPLANE: "TRANSIT",
37
78
  BICYCLE: "PERSONAL",
@@ -57,6 +98,12 @@ export const TRANSIT_SUBMODES_AND_TRANSIT = Object.keys(SIMPLIFICATIONS).filter(
57
98
  mode => SIMPLIFICATIONS[mode] === "TRANSIT"
58
99
  );
59
100
 
101
+ /**
102
+ * Generates list of queries for OTP to get a comprehensive
103
+ * set of results based on the modes input.
104
+ * @param params OTP Query Params
105
+ * @returns Set of parameters to generate queries
106
+ */
60
107
  export function generateCombinations(params: OTPQueryParams): OTPQueryParams[] {
61
108
  const VALID_COMBOS = [
62
109
  ["WALK"],
@@ -70,56 +117,65 @@ export function generateCombinations(params: OTPQueryParams): OTPQueryParams[] {
70
117
 
71
118
  const BANNED_TOGETHER = ["SCOOTER", "BICYCLE"];
72
119
 
73
- // List of the transit submodes that are included in the input params
74
- const queryTransitSubmodes = params.modes
120
+ const completeModeList = [
121
+ ...extractAdditionalModes(params.modeSettings, params.modes),
122
+ ...params.modes
123
+ ];
124
+
125
+ // List of the transit *submodes* that are included in the input params
126
+ const queryTransitSubmodes = completeModeList
75
127
  .filter(mode => TRANSIT_SUBMODES.includes(mode.mode))
76
128
  .map(mode => mode.mode);
77
129
 
78
- return (
79
- combinations(params.modes)
80
- .filter(combo => {
81
- if (combo.length === 0) return false;
82
-
83
- // All current qualifiers currently simplify to "SHARED"
84
- const simplifiedModes = Array.from(
85
- new Set(
86
- combo.map(c => (c.qualifier ? "SHARED" : SIMPLIFICATIONS[c.mode]))
87
- )
88
- );
89
-
90
- // Ensure that if we have one transit mode, then we include ALL transit modes
91
- if (simplifiedModes.includes("TRANSIT")) {
92
- const flatModes = combo.map(m => m.mode);
93
- if (
94
- combo.reduce((prev, cur) => {
95
- if (queryTransitSubmodes.includes(cur.mode)) {
96
- return prev - 1;
97
- }
98
- return prev;
99
- }, queryTransitSubmodes.length) !== 0
100
- ) {
101
- return false;
102
- }
130
+ return combinations(completeModeList)
131
+ .filter(combo => {
132
+ if (combo.length === 0) return false;
133
+
134
+ // All current qualifiers currently simplify to "SHARED"
135
+ const simplifiedModes = Array.from(
136
+ new Set(
137
+ combo.map(c => (c.qualifier ? "SHARED" : SIMPLIFICATIONS[c.mode]))
138
+ )
139
+ );
140
+
141
+ // Ensure that if we have one transit mode, then we include ALL transit modes
142
+ if (simplifiedModes.includes("TRANSIT")) {
143
+ // Don't allow TRANSIT along with any other submodes
144
+ if (
145
+ queryTransitSubmodes.length &&
146
+ combo.find(c => c.mode === "TRANSIT")
147
+ ) {
148
+ return false;
103
149
  }
104
150
 
105
- // OTP doesn't support multiple non-walk modes
106
- if (BANNED_TOGETHER.every(m => combo.find(c => c.mode === m)))
151
+ if (
152
+ combo.reduce((prev, cur) => {
153
+ if (queryTransitSubmodes.includes(cur.mode)) {
154
+ return prev - 1;
155
+ }
156
+ return prev;
157
+ }, queryTransitSubmodes.length) !== 0
158
+ ) {
107
159
  return false;
160
+ }
161
+ // Continue to the other checks
162
+ }
108
163
 
109
- return !!VALID_COMBOS.find(
110
- vc =>
111
- simplifiedModes.every(m => vc.includes(m)) &&
112
- vc.every(m => simplifiedModes.includes(m))
113
- );
114
- })
115
- // create new filter that removes subTransit modes from appearing on their own
116
- // ONLY IF there's multiple of them!
117
- .map(combo => ({ ...params, modes: combo }))
118
- );
164
+ // OTP doesn't support multiple non-walk modes
165
+ if (BANNED_TOGETHER.every(m => combo.find(c => c.mode === m)))
166
+ return false;
167
+
168
+ return !!VALID_COMBOS.find(
169
+ vc =>
170
+ simplifiedModes.every(m => vc.includes(m)) &&
171
+ vc.every(m => simplifiedModes.includes(m))
172
+ );
173
+ })
174
+ .map(combo => ({ ...params, modes: combo }));
119
175
  }
120
176
 
121
177
  // eslint-disable-next-line import/prefer-default-export
122
- export function generateOtp2Query(params: OTPQueryParams): any {
178
+ export function generateOtp2Query(params: OTPQueryParams): GraphQLQuery {
123
179
  const { to, from, modeSettings } = params;
124
180
 
125
181
  // This extracts the values from the mode settings to key value pairs
@@ -132,17 +188,15 @@ export function generateOtp2Query(params: OTPQueryParams): any {
132
188
  walkReluctance,
133
189
  wheelchair,
134
190
  bikeReluctance,
135
- carReluctance,
136
- allowBikeRental
191
+ carReluctance
137
192
  } = modeSettingValues;
138
193
 
139
194
  return {
140
195
  query: print(PlanQuery),
141
196
  variables: {
142
- fromPlace: [from.lat, from.lon].join(","),
143
- toPlace: [to.lat, to.lon].join(","),
197
+ fromPlace: `${from.name}::${from.lat},${from.lon}}`,
198
+ toPlace: `${to.name}::${to.lat},${to.lon}}`,
144
199
  modes: params.modes,
145
- allowBikeRental,
146
200
  walkReluctance,
147
201
  wheelchair,
148
202
  bikeReluctance,