Skip to content

Commit

Permalink
Merge pull request #1728 from solita-sabinaf/TIS-898/service_link_pol…
Browse files Browse the repository at this point in the history
…ylines

Route geometry in journey pattern map
  • Loading branch information
testower authored Dec 20, 2024
2 parents f709e2d + 7a91142 commit 93cd822
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 18 deletions.
14 changes: 14 additions & 0 deletions src/api/uttu/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,3 +596,17 @@ export const getOrganisationsQuery = `
}
}
`;

export const getServiceLinkQuery = `
query ServiceLinkQuery($quayRefFrom:String, $quayRefTo:String) {
serviceLink(quayRefFrom: $quayRefFrom, quayRefTo: $quayRefTo) {
quayRefFrom,
quayRefTo,
serviceLinkRef,
routeGeometry {
distance
coordinates
}
}
}
`;
3 changes: 3 additions & 0 deletions src/config/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { OidcClientSettings } from 'oidc-client-ts';
import { FlexibleLineType } from '../model/FlexibleLine';
import { Locale } from '../i18n';
import { VEHICLE_MODE } from '../model/enums';

/**
* All sandbox features should be added to this interface like this:
Expand Down Expand Up @@ -89,4 +90,6 @@ export interface Config {
extPath?: string;

hideExportDryRun?: boolean;

routeGeometrySupportedVehicleModes?: VEHICLE_MODE[];
}
16 changes: 16 additions & 0 deletions src/ext/JourneyPatternStopPointMap/JourneyPatternStopPointMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import {
useHandleFocusedQuayId,
useMapZoomIntoLocation,
useStopPlacesStateCombinedWithSearchResults,
useRouteGeometry,
} from './hooks';
import Markers from './Markers';
import { useConfig } from '../../config/ConfigContext';

const JourneyPatternStopPointMap = memo(
({
Expand All @@ -34,6 +36,13 @@ const JourneyPatternStopPointMap = memo(
focusedQuayId,
onFocusedQuayIdUpdate,
}: JourneyPatternStopPointMapProps) => {
const { routeGeometrySupportedVehicleModes } = useConfig();
let isRouteGeometryEnabled =
routeGeometrySupportedVehicleModes &&
routeGeometrySupportedVehicleModes?.filter(
(mode) => mode === transportMode,
).length > 0;

// Capture and store map's zoom level and view bounds.
// Will be used later to produce markers within the visible bounds:
const { mapSpecsState, updateMapSpecs } = useMapSpecs();
Expand Down Expand Up @@ -62,8 +71,15 @@ const JourneyPatternStopPointMap = memo(
pointsInSequence,
totalQuayLocationsIndex,
totalQuayStopPlaceIndex,
!!isRouteGeometryEnabled,
);

if (isRouteGeometryEnabled) {
// Handling service links data;
// If route geometry is enabled, this is where the needed coordinates are set up
useRouteGeometry(pointsInSequence, totalQuayLocationsIndex, setMapState);
}

// If there are already stop points selected, zoom in to the route on initial map load:
useFitMapBounds(pointsInSequence, totalQuayLocationsIndex);

Expand Down
6 changes: 3 additions & 3 deletions src/ext/JourneyPatternStopPointMap/Quay/QuayMarker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ const QuayMarker = memo(
hasSelectedQuay={hasSelectedQuay}
hasNonSelectedQuays={hasNonSelectedQuays}
hideNonSelectedQuaysState={hideNonSelectedQuaysState}
hideNonSelectedQuaysCallback={hideNonSelectedQuays}
showQuaysCallback={showQuays}
addStopPointCallback={addStopPoint}
hideNonSelectedQuays={hideNonSelectedQuays}
showQuays={showQuays}
addStopPoint={addStopPoint}
/>
</Popup>

Expand Down
18 changes: 9 additions & 9 deletions src/ext/JourneyPatternStopPointMap/Quay/QuayPopupButtonPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ interface QuayPopupButtonPanelProps {
hasSelectedQuay: boolean;
hasNonSelectedQuays: boolean;
hideNonSelectedQuaysState: boolean;
hideNonSelectedQuaysCallback: (hideNonSelected: boolean) => void;
showQuaysCallback: (showAll: boolean) => void;
addStopPointCallback: (quayId: string) => void;
hideNonSelectedQuays: (hideNonSelected: boolean) => void;
showQuays: (showAll: boolean) => void;
addStopPoint: (quayId: string) => void;
markerRef: MutableRefObject<any>;
}

const QuayPopupButtonPanel = ({
quayId,
quaysTotalCount,
addStopPointCallback,
addStopPoint,
hasSelectedQuay,
hasNonSelectedQuays,
hideNonSelectedQuaysState,
hideNonSelectedQuaysCallback,
showQuaysCallback,
hideNonSelectedQuays,
showQuays,
markerRef,
}: QuayPopupButtonPanelProps) => {
const intl = useIntl();
Expand All @@ -35,7 +35,7 @@ const QuayPopupButtonPanel = ({
className={'popup-button'}
onClick={() => {
markerRef.current.closePopup();
addStopPointCallback(quayId);
addStopPoint(quayId);
// To avoid grey area on the map once the container gets bigger in the height:
window.dispatchEvent(new Event('resize'));
}}
Expand All @@ -54,7 +54,7 @@ const QuayPopupButtonPanel = ({
}}
onClick={() => {
markerRef.current.closePopup();
hideNonSelectedQuaysCallback(!hideNonSelectedQuaysState);
hideNonSelectedQuays(!hideNonSelectedQuaysState);
}}
width="auto"
size="small"
Expand All @@ -72,7 +72,7 @@ const QuayPopupButtonPanel = ({
style={{
marginLeft: '0.5rem',
}}
onClick={() => showQuaysCallback(false)}
onClick={() => showQuays(false)}
width="auto"
size="small"
>
Expand Down
78 changes: 78 additions & 0 deletions src/ext/JourneyPatternStopPointMap/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,81 @@ export const getStopPointLocationSequence = (
});
return stopPointLocationSequence;
};

export const getServiceLinkRef = (quayRefFrom: string, quayRefTo: string) => {
return quayRefFrom + '_' + quayRefTo;
};

export const getRouteGeometryFetchPromises = (
pointsInSequence: StopPoint[],
quayLocationsIndex: Record<string, Centroid>,
fetchRouteGeometryFunction: (
quayRefFrom: string,
quayRefTo: string,
) => Promise<any>,
serviceLinksIndex: Record<string, number[][]>,
) => {
return pointsInSequence.map((point, i) => {
if (
i == pointsInSequence.length - 1 ||
!point.quayRef ||
!quayLocationsIndex[point.quayRef]
) {
return;
}
const nextPoint = pointsInSequence[i + 1];
if (!nextPoint.quayRef || !quayLocationsIndex[nextPoint.quayRef]) {
return;
}

const serviceLinkRef = getServiceLinkRef(point.quayRef, nextPoint.quayRef);
if (!serviceLinksIndex[serviceLinkRef]) {
return fetchRouteGeometryFunction(
point.quayRef as string,
nextPoint.quayRef as string,
);
}
});
};

export const getStopPointLocationSequenceWithRouteGeometry = (
pointsInSequence: StopPoint[],
quayLocationsIndex: Record<string, Centroid>,
serviceLinksIndex: Record<string, number[][]>,
) => {
const stopPointLocationSequence: StopPointLocation[] = [];

pointsInSequence.forEach((point, i) => {
// Adding the point itself first:
if (!point.quayRef || !quayLocationsIndex[point.quayRef]) {
return;
}
const pointLocation = quayLocationsIndex[point.quayRef].location;
if (!pointLocation) {
return;
}
stopPointLocationSequence.push([
pointLocation.latitude,
pointLocation.longitude,
]);
// Now getting the coordinates from the service link:
if (i == pointsInSequence.length - 1) {
return;
}
const nextPoint = pointsInSequence[i + 1];
if (!nextPoint.quayRef) {
return;
}
const serviceLinkRef = getServiceLinkRef(point.quayRef, nextPoint.quayRef);
const coordinates = serviceLinksIndex[serviceLinkRef];
coordinates.forEach((location, i) => {
const reversedCoordinatesPair = location.slice().reverse() as [
number,
number,
];
stopPointLocationSequence.push(reversedCoordinatesPair);
});
});

return stopPointLocationSequence;
};
98 changes: 92 additions & 6 deletions src/ext/JourneyPatternStopPointMap/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,24 @@ import {
JourneyPatternsMapState,
JourneyPatternsStopPlacesState,
MapSpecs,
ServiceLink,
StopPointLocation,
} from './types';
import { Centroid, Location, StopPlace, UttuQuery } from '../../api';
import { useAppSelector } from '../../store/hooks';
import { useConfig } from '../../config/ConfigContext';
import { useAuth } from '../../auth/auth';
import { getStopPlacesQuery } from '../../api/uttu/queries';
import { getStopPlacesState, getStopPointLocationSequence } from './helpers';
import {
getServiceLinkQuery,
getStopPlacesQuery,
} from '../../api/uttu/queries';
import {
getRouteGeometryFetchPromises,
getServiceLinkRef,
getStopPlacesState,
getStopPointLocationSequence,
getStopPointLocationSequenceWithRouteGeometry,
} from './helpers';
import { useMap } from 'react-leaflet';

/**
Expand Down Expand Up @@ -136,11 +146,13 @@ export const useStopPlacesStateCombinedWithSearchResults = (
* @param pointsInSequence quay that user selected into the journey pattern and its order
* @param quayLocationsIndex a helpful record containing pairs of [quayId -> its location]
* @param quayStopPlaceIndex a helpful record containing pairs of [quayId -> stopId the quay belongs to]
* @param isRouteGeometryEnabled
*/
export const useMapState = (
pointsInSequence: StopPoint[],
quayLocationsIndex: Record<string, Centroid>,
quayStopPlaceIndex: Record<string, string>,
isRouteGeometryEnabled: boolean,
) => {
const [mapState, setMapState] = useReducer<
Reducer<JourneyPatternsMapState, Partial<JourneyPatternsMapState>>
Expand Down Expand Up @@ -192,7 +204,7 @@ export const useMapState = (
return;
}

pointsInSequence.forEach((point) => {
pointsInSequence.forEach((point, i) => {
if (!point?.quayRef) {
stopPointIndex++;
return;
Expand All @@ -210,10 +222,15 @@ export const useMapState = (
// Let's get into show quays mode, so that a quay entered through the form gets visible:
newShowQuaysState[stopPlaceId] = true;

if (quayLocationsIndex[point.quayRef]?.location) {
if (
!isRouteGeometryEnabled &&
quayLocationsIndex[point.quayRef]?.location
) {
// if route geometry is enabled, the right coordinates sequence will be established as part of useRouteGeometry hook
const pointLocation = quayLocationsIndex[point.quayRef].location;
newStopPointLocations.push([
quayLocationsIndex[point.quayRef].location.latitude,
quayLocationsIndex[point.quayRef].location.longitude,
pointLocation.latitude,
pointLocation.longitude,
]);
}
});
Expand Down Expand Up @@ -252,6 +269,7 @@ export const useMapState = (
quayLocationsIndex,
setMapState,
mapStateRef.current,
isRouteGeometryEnabled,
]);

return {
Expand Down Expand Up @@ -437,3 +455,71 @@ export const useFitMapBounds = (
]);
}, [quayLocationsIndex, boundsBeenFit]);
};

/**
* Service links contain intermediate locations within a pair of stop points;
* This allows having a polyline that more realistically follows the shape of the route
* @param pointsInSequence
* @param quayLocationsIndex
* @param setMapState
*/
export const useRouteGeometry = (
pointsInSequence: StopPoint[],
quayLocationsIndex: Record<string, Centroid>,
setMapState: (state: Partial<JourneyPatternsMapState>) => void,
) => {
const serviceLinksIndex = useRef<Record<string, number[][]>>({});
const activeProvider =
useAppSelector((state) => state.userContext.activeProviderCode) ?? '';
const { uttuApiUrl } = useConfig();
const auth = useAuth();

const fetchRouteGeometry = useCallback(
(quayRefFrom: string, quayRefTo: string) => {
return auth.getAccessToken().then((token) => {
return UttuQuery(
uttuApiUrl,
activeProvider,
getServiceLinkQuery,
{ quayRefFrom, quayRefTo },
token,
);
});
},
[activeProvider, auth, uttuApiUrl],
);

useEffect(() => {
const fetchRouteGeometryPromises = getRouteGeometryFetchPromises(
pointsInSequence,
quayLocationsIndex,
fetchRouteGeometry,
serviceLinksIndex.current,
);
const newServiceLinkRefs: Record<string, number[][]> = {};

Promise.all(fetchRouteGeometryPromises).then((serviceLinkResponses) => {
serviceLinkResponses.forEach((data) => {
if (!data) {
return;
}
const serviceLink = data?.serviceLink as ServiceLink;
newServiceLinkRefs[serviceLink.serviceLinkRef] =
serviceLink.routeGeometry.coordinates;
});

serviceLinksIndex.current = {
...serviceLinksIndex.current,
...newServiceLinkRefs,
};

const stopPointLocationSequence =
getStopPointLocationSequenceWithRouteGeometry(
pointsInSequence,
quayLocationsIndex,
serviceLinksIndex.current,
);
setMapState({ stopPointLocationSequence });
});
}, [pointsInSequence, serviceLinksIndex, quayLocationsIndex]);
};
12 changes: 12 additions & 0 deletions src/ext/JourneyPatternStopPointMap/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,15 @@ export interface MapSpecs {
zoom: number;
bounds: [number, number, number, number];
}

export interface ServiceLink {
serviceLinkRef: string;
quayRefFrom: string;
quayRefTo: string;
routeGeometry: RouteGeometry;
}

export interface RouteGeometry {
distance: number;
coordinates: number[][];
}

0 comments on commit 93cd822

Please sign in to comment.