All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentripplanner.netex.mapping.StopAndStationMapper Maven / Gradle / Ivy

package org.opentripplanner.netex.mapping;

import static java.util.stream.Collectors.toList;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.opentripplanner.common.model.T2;
import org.opentripplanner.graph_builder.DataImportIssueStore;
import org.opentripplanner.graph_builder.Issue;
import org.opentripplanner.model.FareZone;
import org.opentripplanner.model.Station;
import org.opentripplanner.model.Stop;
import org.opentripplanner.model.TransitMode;
import org.opentripplanner.netex.index.api.ReadOnlyHierarchicalVersionMapById;
import org.opentripplanner.netex.issues.StopPlaceWithoutQuays;
import org.opentripplanner.netex.mapping.support.FeedScopedIdFactory;
import org.opentripplanner.netex.mapping.support.StopPlaceVersionAndValidityComparator;
import org.rutebanken.netex.model.Quay;
import org.rutebanken.netex.model.Quays_RelStructure;
import org.rutebanken.netex.model.StopPlace;
import org.rutebanken.netex.model.TariffZoneRef;

/**
 * This maps a NeTEx StopPlace and its child quays to and OTP parent stop and child stops. NeTEx also contains
 * GroupsOfStopPlaces and these are also mapped to parent stops, because searching from a StopPlace and searching from
 * a GroupOfStopPlaces both corresponding to searching from all of its underlying quays. Model changes in OTP are
 * required if we want to preserve the original NeTEx hierarchy.
 * 

* A NeTEx StopPlace can contain both a version and a validity period. Since none of these are present in the OTP model * we have to choose which version should be mapped based on both of these parameters. *

* To ensure compatibility with older data sets, we also have to keep quays that are only present in older versions * of the StopPlace. */ class StopAndStationMapper { private final ReadOnlyHierarchicalVersionMapById quayIndex; private final StationMapper stationMapper; private final StopMapper stopMapper; private final TariffZoneMapper tariffZoneMapper; private final StopPlaceTypeMapper stopPlaceTypeMapper = new StopPlaceTypeMapper(); private final DataImportIssueStore issueStore; /** * Quay ids for all processed stop places */ private final Set quaysAlreadyProcessed = new HashSet<>(); final List resultStops = new ArrayList<>(); final List resultStations = new ArrayList<>(); final Multimap resultStationByMultiModalStationRfs = ArrayListMultimap.create(); StopAndStationMapper( FeedScopedIdFactory idFactory, ReadOnlyHierarchicalVersionMapById quayIndex, TariffZoneMapper tariffZoneMapper, DataImportIssueStore issueStore ) { this.stationMapper = new StationMapper(issueStore, idFactory); this.stopMapper = new StopMapper(idFactory, issueStore); this.tariffZoneMapper = tariffZoneMapper; this.quayIndex = quayIndex; this.issueStore = issueStore; } /** * @param stopPlaces all stop places including multiple versions of each. */ void mapParentAndChildStops(final Collection stopPlaces) { // Prioritize StopPlace versions. Highest priority first. // TODO OTP2 - This should pushed up into the ReadOnlyHierarchicalVersionMapById as part of // - Issue: Netex import resolve version for all entities , not just stops #2781 List stopPlaceAllVersions = sortStopPlacesByValidityAndVersionDesc(stopPlaces); StopPlace selectedStopPlace = first(stopPlaceAllVersions); Station station = mapStopPlaceAllVersionsToStation(selectedStopPlace); Collection fareZones = mapTariffZones(selectedStopPlace); T2 transitMode = stopPlaceTypeMapper.map(selectedStopPlace); // Loop through all versions of the StopPlace in order to collect all quays, even if they // were deleted in never versions of the StopPlace for (StopPlace stopPlace : stopPlaceAllVersions) { for (Quay quay : listOfQuays(stopPlace)) { addNewStopToParentIfNotPresent(quay, station, fareZones, transitMode); } } } private Station mapStopPlaceAllVersionsToStation(StopPlace stopPlace) { Station station = stationMapper.map(stopPlace); if (stopPlace.getParentSiteRef() != null) { resultStationByMultiModalStationRfs.put( stopPlace.getParentSiteRef().getRef(), station ); } resultStations.add(station); return station; } private Collection mapTariffZones(StopPlace stopPlace) { if(stopPlace.getTariffZones() == null) { return List.of(); } return stopPlace.getTariffZones() .getTariffZoneRef() .stream() .map(ref -> findTariffZone(stopPlace, ref)) .filter(Objects::nonNull) .collect(Collectors.toList()); } private FareZone findTariffZone(StopPlace stopPlace, TariffZoneRef ref) { if(ref == null) { return null; } var result = tariffZoneMapper.findAndMapTariffZone(ref); if(result == null) { issueStore.add( Issue.issue( "StopPlaceMissingFareZone", "StopPlace %s has unsupported tariff zone reference: %s", stopPlace.getId(), ref ) ); } return result; } /** * Sort stop places on version with latest version first (descending order). */ private List sortStopPlacesByValidityAndVersionDesc(Collection stopPlaces) { return stopPlaces.stream() .sorted(new StopPlaceVersionAndValidityComparator()) .collect(toList()); } private void addNewStopToParentIfNotPresent( Quay quay, Station station, Collection fareZones, T2 transitMode ) { // TODO OTP2 - This assumption is only valid because Norway have a // - national stop register, we should add all stops/quays // - for version resolution. // Continue if this is not newest version of quay if (!quayIndex.isNewerOrSameVersionComparedWithExistingValues(quay)) { return; } if (quaysAlreadyProcessed.contains(quay.getId())) { return; } Stop stop = stopMapper.mapQuayToStop(quay, station, fareZones, transitMode); if (stop == null) return; station.addChildStop(stop); resultStops.add(stop); quaysAlreadyProcessed.add(quay.getId()); } /** * Return the list of quays for the given {@code stopPlace} or an empty list if * no quays exist. *

* We do not support quay references, all quays must be included as part of the * given stopPlace. */ private List listOfQuays(StopPlace stopPlace) { Quays_RelStructure quays = stopPlace.getQuays(); if(quays == null) { issueStore.add(new StopPlaceWithoutQuays(stopPlace.getId())); return Collections.emptyList(); } List result = new ArrayList<>(); for (Object it : quays.getQuayRefOrQuay()) { if(it instanceof Quay) { result.add((Quay) it); } else { issueStore.add( Issue.issue( "StopPlaceWithoutQuays", "StopPlace %s has unsupported quay reference: %s", stopPlace.getId(), it ) ); } } return result; } private static StopPlace first(List stops) { return stops.get(0); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy