Skip to content

Commit e87e2d4

Browse files
committed
add more costing options
1 parent 53963f2 commit e87e2d4

File tree

5 files changed

+144
-25
lines changed

5 files changed

+144
-25
lines changed

src/components/settings-panel/settings-options.ts

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { BicycleType } from '@/components/types';
1+
import type { BicycleType, PedestrianType } from '@/components/types';
22

33
interface NumericSetting {
44
name: string;
@@ -194,6 +194,32 @@ const gatePenalty = {
194194
},
195195
};
196196

197+
const destinationOnlyPenalty = {
198+
name: 'Destination-only Penalty',
199+
param: 'destination_only_penalty',
200+
description:
201+
'A penalty applied when entering an road which is only allowed to enter if necessary to reach the destination.',
202+
unit: 'sec',
203+
settings: {
204+
min: 0,
205+
max: 600,
206+
step: 30,
207+
},
208+
};
209+
210+
const elevatorPenalty = {
211+
name: 'Elevator Penalty',
212+
param: 'elevator_penalty',
213+
description:
214+
'A penalty in seconds added to each transition via an elevator node or onto an elevator edge. Higher values apply larger cost penalties to avoid elevators.',
215+
unit: 'sec',
216+
settings: {
217+
min: 0,
218+
max: 600,
219+
step: 30,
220+
},
221+
};
222+
197223
const tollBoothCost = {
198224
name: 'Toll Booth Cost',
199225
param: 'toll_booth_cost',
@@ -551,6 +577,29 @@ const bicycleType = {
551577
],
552578
};
553579

580+
const pedestrianType = {
581+
name: 'Pedestrian Type',
582+
description: `One of "foot", "wheelchair", "blind". If set to blind, enables additional route instructions, especially useful for blind users: Announcing crossed streets, the stairs, bridges, tunnels, gates and bollards, which need to be passed on route; information about traffic signals on crosswalks; route numbers not announced for named routes. If set to wheelchair, changes the defaults for max_distance, walking_speed, and step_penalty to be better aligned to the needs of wheelchair users.`,
583+
param: 'type',
584+
enums: [
585+
{
586+
key: 'Foot',
587+
text: 'Foot',
588+
value: 'Foot',
589+
},
590+
{
591+
key: 'Wheelchair',
592+
text: 'Wheelchair',
593+
value: 'Wheelchair',
594+
},
595+
{
596+
key: 'Blind',
597+
text: 'Blind',
598+
value: 'Blind',
599+
},
600+
],
601+
};
602+
554603
const cyclingSpeed = {
555604
name: 'Cycling Speed',
556605
param: 'cycling_speed',
@@ -826,6 +875,8 @@ export const settingsInit = {
826875
use_living_streets: 0.5,
827876
use_tracks: 0,
828877
private_access_penalty: 450,
878+
destination_only_penalty: 300,
879+
elevator_penalty: 120,
829880
ignore_closures: false,
830881
ignore_restrictions: false,
831882
ignore_access: false,
@@ -836,6 +887,7 @@ export const settingsInit = {
836887
shortest: false,
837888
exclude_cash_only_tolls: false,
838889
bicycle_type: 'Hybrid' as BicycleType,
890+
type: 'Foot' as PedestrianType,
839891
cycling_speed: 20,
840892
use_roads: 0.5,
841893
use_hills: 0.5,
@@ -891,6 +943,7 @@ const commonVehicleProfileNumeric = [
891943
topSpeed,
892944
fixedSpeed,
893945
privateAccessPenalty,
946+
destinationOnlyPenalty,
894947
closureFactor,
895948
...serviceSettings,
896949
...gateSettings,
@@ -964,10 +1017,14 @@ export const profileSettings: Record<SettingsProfile, SettingsGroup> = {
9641017
sidewalkFactor,
9651018
alleyFactor,
9661019
drivewayFactor,
1020+
privateAccessPenalty,
1021+
destinationOnlyPenalty,
1022+
elevatorPenalty,
9671023
stepPenalty,
9681024
maxHikingDifficulty,
9691025
],
970-
[shortest]
1026+
[shortest],
1027+
[pedestrianType]
9711028
),
9721029

9731030
motor_scooter: createSettings(

src/components/settings-panel/settings-panel.spec.tsx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ vi.mock('@/stores/common-store', () => ({
5151
use_living_streets: 0.5,
5252
alternates: 2,
5353
bicycle_type: 'Hybrid',
54+
type: 'Foot',
5455
service_penalty: 15,
5556
service_factor: 1,
5657
maneuver_penalty: 5,
@@ -61,6 +62,16 @@ vi.mock('@/stores/common-store', () => ({
6162
country_crossing_cost: 600,
6263
country_crossing_penalty: 0,
6364
turn_penalty_factor: 0,
65+
use_lit: 0.5,
66+
walking_speed: 5.1,
67+
walkway_factor: 1,
68+
sidewalk_factor: 1,
69+
alley_factor: 2,
70+
driveway_factor: 5,
71+
step_penalty: 0,
72+
max_hiking_difficulty: 1,
73+
destination_only_penalty: 300,
74+
elevator_penalty: 120,
6475
},
6576
settingsPanelOpen: true,
6677
updateSettings: mockUpdateSettings,
@@ -501,6 +512,62 @@ describe('SettingsPanel', () => {
501512
});
502513
});
503514

515+
describe('Enum Settings', () => {
516+
it('should render Bicycle Type select only once for bicycle profile', () => {
517+
renderWithQueryClient(<SettingsPanel />);
518+
const bicycleTypeLabels = screen.getAllByText('Bicycle Type');
519+
expect(bicycleTypeLabels).toHaveLength(1);
520+
});
521+
522+
it('should display current bicycle_type value from settings', () => {
523+
renderWithQueryClient(<SettingsPanel />);
524+
// The mock has bicycle_type: 'Hybrid'
525+
expect(screen.getByText('Hybrid')).toBeInTheDocument();
526+
});
527+
528+
it('should render Pedestrian Type select only once for pedestrian profile', () => {
529+
mockUseSearch.mockReturnValue({ profile: 'pedestrian' });
530+
renderWithQueryClient(<SettingsPanel />);
531+
const pedestrianTypeLabels = screen.getAllByText('Pedestrian Type');
532+
expect(pedestrianTypeLabels).toHaveLength(1);
533+
});
534+
535+
it('should display current pedestrian type value from settings', () => {
536+
mockUseSearch.mockReturnValue({ profile: 'pedestrian' });
537+
renderWithQueryClient(<SettingsPanel />);
538+
// The mock has type: 'Foot'
539+
expect(screen.getByText('Foot')).toBeInTheDocument();
540+
});
541+
542+
it('should not render Bicycle Type for pedestrian profile', () => {
543+
mockUseSearch.mockReturnValue({ profile: 'pedestrian' });
544+
renderWithQueryClient(<SettingsPanel />);
545+
expect(screen.queryByText('Bicycle Type')).not.toBeInTheDocument();
546+
});
547+
548+
it('should not render Pedestrian Type for bicycle profile', () => {
549+
renderWithQueryClient(<SettingsPanel />);
550+
expect(screen.queryByText('Pedestrian Type')).not.toBeInTheDocument();
551+
});
552+
553+
it('should render bicycle type combobox with correct id', () => {
554+
renderWithQueryClient(<SettingsPanel />);
555+
const bicycleTypeSelect = screen.getByRole('combobox', {
556+
name: /Bicycle Type/i,
557+
});
558+
expect(bicycleTypeSelect).toBeInTheDocument();
559+
});
560+
561+
it('should render pedestrian type combobox with correct id', () => {
562+
mockUseSearch.mockReturnValue({ profile: 'pedestrian' });
563+
renderWithQueryClient(<SettingsPanel />);
564+
const pedestrianTypeSelect = screen.getByRole('combobox', {
565+
name: /Pedestrian Type/i,
566+
});
567+
expect(pedestrianTypeSelect).toBeInTheDocument();
568+
});
569+
});
570+
504571
describe('Language Picker', () => {
505572
it('should render Directions Language section when activeTab is directions', () => {
506573
renderWithQueryClient(<SettingsPanel />);

src/components/settings-panel/settings-panel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ export const SettingsPanel = () => {
227227
id={option.param}
228228
label={option.name}
229229
description={option.description}
230-
placeholder="Select Bicycle Type"
231-
value={settings.bicycle_type as string}
230+
placeholder={`Select ${option.name}`}
231+
value={settings[option.param] as string}
232232
options={option.enums}
233233
onValueChange={(value) => {
234234
handleUpdateSettings({

src/components/types.ts

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export type Settings = Record<
1919
>;
2020

2121
export type BicycleType = 'Hybrid' | 'Road' | 'City' | 'Cross' | 'Mountain';
22+
export type PedestrianType = 'Foot' | 'Wheelchair' | 'Blind';
2223

2324
export interface PossibleSettings {
2425
maneuver_penalty: number;
@@ -37,6 +38,8 @@ export interface PossibleSettings {
3738
use_living_streets: number;
3839
use_tracks: number;
3940
private_access_penalty: number;
41+
destination_only_penalty: number;
42+
elevator_penalty: number;
4043
ignore_closures: boolean;
4144
ignore_restrictions: boolean;
4245
ignore_access: boolean;
@@ -47,6 +50,7 @@ export interface PossibleSettings {
4750
shortest: boolean;
4851
exclude_cash_only_tolls: boolean;
4952
bicycle_type: BicycleType;
53+
type: PedestrianType;
5054
cycling_speed: number;
5155
use_roads: number;
5256
use_hills: number;
@@ -180,27 +184,6 @@ export interface Center {
180184
addressindex: number;
181185
}
182186

183-
export interface Costing {
184-
maneuver_penalty: number;
185-
use_ferry: number;
186-
use_living_streets: number;
187-
service_penalty: number;
188-
service_factor: number;
189-
shortest: boolean;
190-
bicycle_type: string;
191-
cycling_speed: number;
192-
use_roads: number;
193-
use_hills: number;
194-
avoid_bad_surfaces: number;
195-
gate_penalty: number;
196-
gate_cost: number;
197-
}
198-
199-
export interface Directions {
200-
alternates: number;
201-
exclude_polygons: GeoJSON.GeoJSON[];
202-
}
203-
204187
export interface NominationResponse {
205188
place_id: number;
206189
licence: string;

src/utils/valhalla.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ describe('valhalla.ts', () => {
199199

200200
const mockSettings: Settings = {
201201
costing: {
202+
destination_only_penalty: 300,
203+
elevator_penalty: 300,
202204
maneuver_penalty: 5,
203205
country_crossing_penalty: 0,
204206
country_crossing_cost: 600,
@@ -225,6 +227,7 @@ describe('valhalla.ts', () => {
225227
shortest: false,
226228
exclude_cash_only_tolls: false,
227229
bicycle_type: 'Hybrid',
230+
type: 'Foot',
228231
cycling_speed: 20,
229232
use_roads: 0.5,
230233
use_hills: 0.5,
@@ -260,6 +263,8 @@ describe('valhalla.ts', () => {
260263
speed_types: [],
261264
},
262265
directions: {
266+
destination_only_penalty: 300,
267+
elevator_penalty: 300,
263268
maneuver_penalty: 5,
264269
country_crossing_penalty: 0,
265270
country_crossing_cost: 600,
@@ -286,6 +291,7 @@ describe('valhalla.ts', () => {
286291
shortest: false,
287292
exclude_cash_only_tolls: false,
288293
bicycle_type: 'Hybrid',
294+
type: 'Foot',
289295
cycling_speed: 20,
290296
use_roads: 0.5,
291297
use_hills: 0.5,
@@ -719,6 +725,8 @@ describe('valhalla.ts', () => {
719725

720726
const mockSettings: Settings = {
721727
costing: {
728+
destination_only_penalty: 300,
729+
elevator_penalty: 300,
722730
maneuver_penalty: 5,
723731
country_crossing_penalty: 0,
724732
country_crossing_cost: 600,
@@ -745,6 +753,7 @@ describe('valhalla.ts', () => {
745753
shortest: false,
746754
exclude_cash_only_tolls: false,
747755
bicycle_type: 'Hybrid',
756+
type: 'Foot',
748757
cycling_speed: 20,
749758
use_roads: 0.5,
750759
use_hills: 0.5,
@@ -780,6 +789,8 @@ describe('valhalla.ts', () => {
780789
speed_types: [],
781790
},
782791
directions: {
792+
destination_only_penalty: 300,
793+
elevator_penalty: 300,
783794
maneuver_penalty: 5,
784795
country_crossing_penalty: 0,
785796
country_crossing_cost: 600,
@@ -806,6 +817,7 @@ describe('valhalla.ts', () => {
806817
shortest: false,
807818
exclude_cash_only_tolls: false,
808819
bicycle_type: 'Hybrid',
820+
type: 'Foot',
809821
cycling_speed: 20,
810822
use_roads: 0.5,
811823
use_hills: 0.5,

0 commit comments

Comments
 (0)