Directions: merge consecutive turn-by-turn steps on the same street
All checks were successful
CI / test-and-build (push) Successful in 58s
All checks were successful
CI / test-and-build (push) Successful in 58s
buildTurnInstructions grouped steps purely by heading change, so a street that bends (same name, >30° heading shift) produced redundant 'Continue/Turn onto Pine St' entries. Now consecutive legs sharing the same street name are collapsed into a single step with summed distance. - routing.ts: track each leg's street name and absorb subsequent same-street steps' distance into the first; the arrival step uses the final bearing - scripts/test.mjs: assert a bent single-named road yields 1 step, and that two distinct streets are not merged
This commit is contained in:
parent
f054164e84
commit
8941d837b5
@ -180,6 +180,31 @@ async function run() {
|
|||||||
check(namedTurns.some((t) => t.instruction.toLowerCase().includes('onto 21st st')), 'turn step includes destination street ("Turn right onto 21st St")');
|
check(namedTurns.some((t) => t.instruction.toLowerCase().includes('onto 21st st')), 'turn step includes destination street ("Turn right onto 21st St")');
|
||||||
check(turns[turns.length - 1].instruction === 'Arrive at destination', 'last step is "Arrive at destination"');
|
check(turns[turns.length - 1].instruction === 'Arrive at destination', 'last step is "Arrive at destination"');
|
||||||
|
|
||||||
|
// Same-street merge: a road that bends (>30\u00b0 heading change) but keeps
|
||||||
|
// ONE name must collapse into a single step rather than two.
|
||||||
|
{
|
||||||
|
// S-shape: north, then a 45\u00b0 bend, then north again — all "Oak Ave".
|
||||||
|
const bendPath = [];
|
||||||
|
for (let i = 0; i <= 10; i++) bendPath.push([36.1 + i * 0.000017, -95.9]); // north
|
||||||
|
for (let i = 1; i <= 10; i++) bendPath.push([36.10017 + i * 0.000017, -95.9 + i * 0.000012]); // NE bend
|
||||||
|
for (let i = 1; i <= 10; i++) bendPath.push([36.10034 + i * 0.000012, -95.89988 + i * 0.000017]); // east-ish
|
||||||
|
const bent = buildTurnInstructions(bendPath, () => 'Oak Ave');
|
||||||
|
const oakSteps = bent.filter((t) => t.instruction.toLowerCase().includes('oak ave'));
|
||||||
|
check(oakSteps.length === 1, `same-street merge: a bent "Oak Ave" collapses to 1 step (got ${oakSteps.length})`);
|
||||||
|
// Sum of all non-arrival step distances should still cover the route.
|
||||||
|
const namedCount = bent.filter((t) => t.instruction !== 'Arrive at destination').length;
|
||||||
|
check(namedCount >= 1, 'merged path still has instruction steps');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge must NOT merge two distinct streets.
|
||||||
|
{
|
||||||
|
const mpath = [];
|
||||||
|
for (let i = 0; i <= 10; i++) mpath.push([36.1 + i * 0.000017, -95.9]); // north on A St
|
||||||
|
for (let i = 1; i <= 20; i++) mpath.push([36.10017, -95.9 + i * 0.000017]); // east on B St
|
||||||
|
const mt = buildTurnInstructions(mpath, (i) => (i < 10 ? 'A St' : 'B St'));
|
||||||
|
check(mt.some((t) => t.instruction.toLowerCase().includes('b st')), 'distinct streets are NOT merged (B St step present)');
|
||||||
|
}
|
||||||
|
|
||||||
const { route } = await import(resolve(__dirname, '..', 'src', 'lib', 'routing.ts'));
|
const { route } = await import(resolve(__dirname, '..', 'src', 'lib', 'routing.ts'));
|
||||||
// Disconnected destination -> partial path.
|
// Disconnected destination -> partial path.
|
||||||
const g2 = {
|
const g2 = {
|
||||||
|
|||||||
@ -182,7 +182,10 @@ export function buildTurnInstructions(
|
|||||||
merged.push({ ...leg });
|
merged.push({ ...leg });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const steps: TurnStep[] = [];
|
// Build one entry per leg, carrying its street name so later steps on the
|
||||||
|
// SAME street can be combined.
|
||||||
|
type LegStep = { distanceM: number; instruction: string; bearing: number; name?: string };
|
||||||
|
const raw: LegStep[] = [];
|
||||||
function legEnd(li: number): number {
|
function legEnd(li: number): number {
|
||||||
return li + 1 < merged.length ? merged[li + 1].segStart - 1 : segBearing.length - 1;
|
return li + 1 < merged.length ? merged[li + 1].segStart - 1 : segBearing.length - 1;
|
||||||
}
|
}
|
||||||
@ -199,10 +202,28 @@ export function buildTurnInstructions(
|
|||||||
const angle = turnAngle(prevBearing, bearing);
|
const angle = turnAngle(prevBearing, bearing);
|
||||||
instruction = name ? `${maneuverLabel(angle)} onto ${name}` : maneuverLabel(angle);
|
instruction = name ? `${maneuverLabel(angle)} onto ${name}` : maneuverLabel(angle);
|
||||||
}
|
}
|
||||||
steps.push({ distanceM: Math.round(leg.dist), instruction, bearing });
|
raw.push({ distanceM: Math.round(leg.dist), instruction, bearing, name });
|
||||||
}
|
}
|
||||||
// Canonical final arrival step.
|
|
||||||
steps.push({ distanceM: 0, instruction: 'Arrive at destination', bearing: segBearing[legs[legs.length - 1].segStart] });
|
// Merge consecutive steps that share the same street name into a single
|
||||||
|
// step, summing their distance. This collapses redundant "Continue on Pine
|
||||||
|
// St" / "Turn onto Pine St" entries when a street merely bends or dips.
|
||||||
|
const steps: TurnStep[] = [];
|
||||||
|
let lastStreet: string | undefined;
|
||||||
|
for (const step of raw) {
|
||||||
|
const last = steps[steps.length - 1];
|
||||||
|
if (last && step.name !== undefined && lastStreet === step.name) {
|
||||||
|
// Same street as the previous step — absorb distance into it.
|
||||||
|
last.distanceM += step.distanceM;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
steps.push({ distanceM: step.distanceM, instruction: step.instruction, bearing: step.bearing });
|
||||||
|
lastStreet = step.name !== undefined ? step.name : lastStreet;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Canonical final arrival step. Use the final step's segment bearing.
|
||||||
|
const lastBearing = steps.length ? steps[steps.length - 1].bearing : (segBearing.length ? segBearing[segBearing.length - 1] : 0);
|
||||||
|
steps.push({ distanceM: 0, instruction: 'Arrive at destination', bearing: lastBearing });
|
||||||
return steps;
|
return steps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user