Skip to content

Commit

Permalink
Merge pull request #5174 from HSLdevcom/shift-nontransit-legs
Browse files Browse the repository at this point in the history
Reconstruct itinerary after realtime modifications
  • Loading branch information
partisaani authored Nov 22, 2024
2 parents 4647033 + 318d65b commit 6f53889
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 1 deletion.
87 changes: 86 additions & 1 deletion app/component/itinerary/navigator/hooks/useRealtimeLegs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,89 @@ import { useCallback, useEffect, useState } from 'react';
import { fetchQuery } from 'react-relay';
import { checkPositioningPermission } from '../../../../action/PositionActions';
import { legQuery } from '../../queries/LegQuery';
import { legTime } from '../../../../util/legUtils';
import { epochToIso } from '../../../../util/timeUtils';

function nextTransitIndex(legs, i) {
for (let j = i; j < legs.length; j++) {
if (legs[j].transitLeg) {
return j;
}
}
// negative indicates not found
return -1;
}

function getLegGap(legs, index) {
return legTime(legs[index + 1].start) - legTime(legs[index].end);
}

// change non-transit legs' scheduled times
function shiftLegs(legs, i1, i2, gap) {
for (let j = i1; j <= i2; j++) {
const leg = legs[j];
leg.start.scheduledTime = epochToIso(legTime(leg.start) + gap);
leg.end.scheduledTime = epochToIso(legTime(leg.end) + gap);
}
}

// scale non-transit legs' scheduled times
function scaleLegs(legs, i1, i2, k) {
const base = legTime(legs[i1].start);
for (let j = i1; j <= i2; j++) {
const leg = legs[j];
const s = legTime(leg.start);
const e = legTime(leg.end);
leg.start.scheduledTime = epochToIso(s + k * (s - base));
leg.end.scheduledTime = epochToIso(e + k * (e - base));
}
}

function matchLegEnds(legs) {
if (legs.length < 2) {
return;
}
let transit;
let gap;

// shift first legs to match transit start
transit = nextTransitIndex(legs, 0);
if (transit > 0) {
gap = getLegGap(legs, transit - 1);
if (gap) {
shiftLegs(legs, 0, transit - 1, gap);
}
}

// shift transfers and legs after transit end
while (transit > 0) {
const walk = transit + 1; // first leg after transit
const nextTransit = nextTransitIndex(legs, walk);
const shiftEnd = nextTransit > 0 ? nextTransit - 1 : legs.length - 1;
if (shiftEnd > transit) {
gap = getLegGap(legs, transit);
if (gap) {
shiftLegs(legs, walk, shiftEnd, -gap);
}
}
if (nextTransit > walk) {
// check if transfer needs scaling
gap = getLegGap(legs, nextTransit - 1);
if (gap < 0) {
// transfer overlaps next transit leg, so we must make it shorter
const transferDuration =
legTime(legs[shiftEnd].end) - legTime(legs[walk].start);
scaleLegs(
legs,
walk,
shiftEnd,
(transferDuration + gap) / transferDuration,
);
}
}
transit = nextTransit;
}
}

const useRealtimeLegs = (initialLegs, mapRef, relayEnvironment) => {
const [isPositioningAllowed, setPositioningAllowed] = useState(false);
Expand Down Expand Up @@ -60,8 +143,10 @@ const useRealtimeLegs = (initialLegs, mapRef, relayEnvironment) => {
},
};
}
return { ...l };
return { ...l, start: { ...l.start }, end: { ...l.end } };
});
// shift non-transit-legs to match possibly changed transit legs
matchLegEnds(rtLegs);
setRealTimeLegs(rtLegs);
}, [initialLegs, queryAndMapRealtimeLegs]);

Expand Down
9 changes: 9 additions & 0 deletions app/util/legUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ export function legTimeStr(lt) {
return `${time[0]}:${time[1]}`;
}

/**
* Get time as 'hh:mm:ss'
*/
export function legTimeAcc(lt) {
const t = lt.estimated?.time || lt.scheduledTime;
const parts = t.split('T')[1].split('+');
return parts[0];
}

function filterLegStops(leg, filter) {
if (leg.from.stop && leg.to.stop && leg.trip) {
const stops = [leg.from.stop.gtfsId, leg.to.stop.gtfsId];
Expand Down
7 changes: 7 additions & 0 deletions app/util/timeUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,10 @@ export function timeStr(dateTime) {
const time = parts[1].split(':');
return `${time[0]}:${time[1]}`;
}

/**
* Epoch ms to ISO-8601/RFC3339 datetime str
*/
export function epochToIso(ms) {
return moment(ms).format();
}

0 comments on commit 6f53889

Please sign in to comment.