Skip to content

Commit

Permalink
Merge pull request #6 from munterfi/feature/decouple-transit-route-co…
Browse files Browse the repository at this point in the history
…ncept

Feature/decouple transit route concept
  • Loading branch information
munterfi authored Nov 20, 2024
2 parents 4d35f49 + 705d298 commit d9ad9e7
Show file tree
Hide file tree
Showing 22 changed files with 304 additions and 290 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The class diagram outlines the core classes and their relationships:

```sh
# configure arguments
NETWORK_GRAPHIC_FILE=integration-test/input/networkGraphic.json
NETWORK_GRAPHIC_FILE=src/test/resources/ng/scenarios/realistic.json
OUTPUT_DIRECTORY=integration-test/output/

# run spring command line runner app
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/ch/sbb/pfi/netzgrafikeditor/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private NetworkGraphicConverter getNetworkGraphicConverter(Path jsonFilePath, Sc
NetworkGraphicSource source = new JsonFileReader(jsonFilePath);

SupplyBuilder builder = new MatsimSupplyBuilder(scenario, new NoInfrastructureRepository(),
new NoRollingStockRepository(), new NoVehicleCircuitsPlanner());
new NoVehicleCircuitsPlanner(new NoRollingStockRepository()));

String baseFilename = jsonFilePath.getFileName().toString();
String filenameWithoutExtension = jsonFilePath.getFileName()
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ch.sbb.pfi.netzgrafikeditor.converter.core;

public enum RouteDirection {
FORWARD,
REVERSE
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
Expand All @@ -32,9 +33,9 @@ void add(TrainrunSection section) {
}

/**
* Traverse the sections and build an ordered sequence.
* Traverse the sections and build an ordered, directed section sequences.
*/
List<TrainrunSection> build() {
EnumMap<RouteDirection, List<TrainrunSection>> build() {
List<TrainrunSection> orderedSections = new LinkedList<>(); // append to start of list

// find first section of the chain
Expand All @@ -45,9 +46,15 @@ List<TrainrunSection> build() {
// traverse from first section and collect sections
traverse(firstSection.get(), orderedSections::addFirst);

// align sections: e.g. A-B, C-B becomes A-B, B-C
SectionAligner.align(orderedSections);

return orderedSections;
// create directed sequences
EnumMap<RouteDirection, List<TrainrunSection>> directedSections = new EnumMap<>(RouteDirection.class);
directedSections.put(RouteDirection.FORWARD, orderedSections);
directedSections.put(RouteDirection.REVERSE, SectionAligner.reverse(orderedSections));

return directedSections;
}

private void traverse(TrainrunSection root, Consumer<TrainrunSection> action) {
Expand Down Expand Up @@ -153,6 +160,10 @@ private static void align(List<TrainrunSection> orderedSections) {
}
}

private static List<TrainrunSection> reverse(List<TrainrunSection> sections) {
return sections.reversed().stream().map(SectionAligner::swap).toList();
}

private static TrainrunSection swap(TrainrunSection original) {
return TrainrunSection.builder().id(original.getId()) // keep
.sourceNodeId(original.getTargetNodeId()) // swap
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
@Value
public class DepartureInfo {

TransitLineInfo transitLine;
RouteDirection direction;
TransitRouteInfo transitRouteInfo;
LocalTime time;

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ public interface InfrastructureRepository {

StopFacilityInfo getStopFacility(String stopId, double x, double y);

List<TrackSegmentInfo> getTrack(StopFacilityInfo fromStop, StopFacilityInfo toStop, TransitLineInfo transitLineInfo);
List<TrackSegmentInfo> getTrack(StopFacilityInfo fromStop, StopFacilityInfo toStop, TransitRouteInfo transitRouteInfo);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public interface RollingStockRepository {

VehicleTypeInfo getVehicleType(String vehicleTypeId);
VehicleTypeInfo getVehicleType(String category);

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ public interface SupplyBuilder {

SupplyBuilder addStopFacility(String id, double x, double y);

SupplyBuilder addTransitLine(String lineId, String vehicleTypeId, String originStopId, Duration dwellTimeAtOrigin);
SupplyBuilder addTransitLine(String id, String category);

SupplyBuilder addRouteStop(String lineId, String stopId, Duration travelTime, Duration dwellTime);
SupplyBuilder addTransitRoute(String id, String lineId, String originStopId, Duration dwellTimeAtOrigin);

SupplyBuilder addRoutePass(String lineId, String stopId);
SupplyBuilder addRouteStop(String routeId, String stopId, Duration travelTime, Duration dwellTime);

SupplyBuilder addDeparture(String lineId, RouteDirection direction, LocalTime time);
SupplyBuilder addRoutePass(String routeId, String stopId);

SupplyBuilder addDeparture(String routeId, LocalTime time);

void build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
public class TransitLineInfo {

String id;
VehicleTypeInfo vehicleTypeInfo;
String category;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ch.sbb.pfi.netzgrafikeditor.converter.core.supply;

import lombok.Value;

@Value
public class TransitRouteInfo {

String id;
TransitLineInfo transitLineInfo;

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.InfrastructureRepository;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.StopFacilityInfo;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.TrackSegmentInfo;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.TransitLineInfo;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.TransitRouteInfo;

import java.util.HashMap;
import java.util.List;
Expand All @@ -22,7 +22,7 @@ public StopFacilityInfo getStopFacility(String stopId, double x, double y) {
}

@Override
public List<TrackSegmentInfo> getTrack(StopFacilityInfo fromStop, StopFacilityInfo toStop, TransitLineInfo transitLineInfo) {
public List<TrackSegmentInfo> getTrack(StopFacilityInfo fromStop, StopFacilityInfo toStop, TransitRouteInfo transitRouteInfo) {
Coordinate fromCoord = coordinates.get(fromStop.getId());
Coordinate toCoord = coordinates.get(toStop.getId());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public class NoRollingStockRepository implements RollingStockRepository {
public static final double DEFAULT_MAX_VELOCITY = 120 / 3.6; // meters per second

@Override
public VehicleTypeInfo getVehicleType(String vehicleTypeId) {
return new VehicleTypeInfo(vehicleTypeId, DEFAULT_CAPACITY, DEFAULT_LENGTH, DEFAULT_MAX_VELOCITY, Map.of());
public VehicleTypeInfo getVehicleType(String category) {
return new VehicleTypeInfo(category, DEFAULT_CAPACITY, DEFAULT_LENGTH, DEFAULT_MAX_VELOCITY, Map.of());
}

}
Original file line number Diff line number Diff line change
@@ -1,44 +1,53 @@
package ch.sbb.pfi.netzgrafikeditor.converter.core.supply.fallback;

import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.DepartureInfo;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.RouteDirection;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.RollingStockRepository;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.VehicleAllocation;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.VehicleCircuitsPlanner;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.VehicleInfo;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.VehicleTypeInfo;
import lombok.RequiredArgsConstructor;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RequiredArgsConstructor
public class NoVehicleCircuitsPlanner implements VehicleCircuitsPlanner {

private final List<DepartureInfo> departures = new ArrayList<>();
private final RollingStockRepository rollingStockRepository;

private final Map<String, VehicleTypeInfo> vehicleTypeInfos = new HashMap<>();
private final List<DepartureInfo> departureInfos = new ArrayList<>();

@Override
public void register(DepartureInfo departureInfo) {
departures.add(departureInfo);
departureInfos.add(departureInfo);
}

@Override
public List<VehicleAllocation> plan() {
Map<String, Integer> vehicleCounts = new HashMap<>();
Map<String, EnumMap<RouteDirection, Integer>> departureCounts = new HashMap<>();
Map<String, Integer> departureCounts = new HashMap<>();

return departureInfos.stream().sorted(Comparator.comparing(DepartureInfo::getTime)).map(departureInfo -> {

return departures.stream().sorted(Comparator.comparing(DepartureInfo::getTime)).map(departureInfo -> {
VehicleTypeInfo vehicleTypeInfo = departureInfo.getTransitLine().getVehicleTypeInfo();
// get vehicle type based on category (product)
String category = departureInfo.getTransitRouteInfo().getTransitLineInfo().getCategory();
VehicleTypeInfo vehicleTypeInfo = vehicleTypeInfos.get(category);
if (vehicleTypeInfo == null) {
vehicleTypeInfo = rollingStockRepository.getVehicleType(category);
vehicleTypeInfos.put(category, vehicleTypeInfo);
}

// update vehicle counts and departure counts
int vehicleCount = vehicleCounts.merge(vehicleTypeInfo.getId(), 1, Integer::sum);
EnumMap<RouteDirection, Integer> lineDepartureCounts = departureCounts.computeIfAbsent(
vehicleTypeInfo.getId(), k -> new EnumMap<>(RouteDirection.class));
int departureCount = lineDepartureCounts.merge(departureInfo.getDirection(), 1, Integer::sum);
int departureCount = departureCounts.merge(departureInfo.getTransitRouteInfo().getId(), 1, Integer::sum);

return new VehicleAllocation(String.format("%s_%s_%s", departureInfo.getTransitLine().getId(),
departureInfo.getDirection().name(), departureCount), departureInfo,
return new VehicleAllocation(
String.format("%s_%s", departureInfo.getTransitRouteInfo().getId(), departureCount), departureInfo,
new VehicleInfo(String.format("%s_%d", vehicleTypeInfo.getId(), vehicleCount), vehicleTypeInfo));
}).toList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,30 +40,30 @@ boolean isValid() {
}

for (Issue<Identifiable> issue : issues) {
log.warn("Found: {}", issue);
log.warn("Invalid identifier: target={}, type={}, id={}", issue.target, issue.type, issue.id);
}

return issues.isEmpty();
}

private void validateId(String id, IssueTarget target, Identifiable object) {
if (id == null || id.isEmpty()) {
issues.add(new Issue<>(target, IssueType.MISSING, object));
issues.add(new Issue<>(target, IssueType.MISSING, id, object));
return;
}

if (containsSpecialCharacter(id)) {
issues.add(new Issue<>(target, IssueType.SPECIAL_CHARACTER, object));
issues.add(new Issue<>(target, IssueType.SPECIAL_CHARACTER, id, object));
return;
}

if (containsTrailingWhitespace(id)) {
issues.add(new Issue<>(target, IssueType.LEADING_OR_TRAILING_WHITESPACE, object));
issues.add(new Issue<>(target, IssueType.LEADING_OR_TRAILING_WHITESPACE, id, object));
return;
}

if (containsWhitespace(id)) {
issues.add(new Issue<>(target, IssueType.WHITESPACE, object));
issues.add(new Issue<>(target, IssueType.WHITESPACE, id, object));
}
}

Expand All @@ -83,7 +83,7 @@ private enum IssueType {
LEADING_OR_TRAILING_WHITESPACE
}

private record Issue<T>(IssueTarget target, IssueType type, T object) {
private record Issue<T>(IssueTarget target, IssueType type, String id, T object) {
}

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package ch.sbb.pfi.netzgrafikeditor.converter.matsim;

import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.InfrastructureRepository;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.RouteDirection;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.RouteElement;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.RouteElementVisitor;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.RoutePass;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.RouteStop;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.StopFacilityInfo;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.TrackSegmentInfo;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.TransitLineInfo;
import ch.sbb.pfi.netzgrafikeditor.converter.core.supply.TransitRouteInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.matsim.api.core.v01.Coord;
Expand Down Expand Up @@ -55,31 +54,25 @@ TransitStopFacility buildTransitStopFacility(StopFacilityInfo stopFacilityInfo)
return stop;
}

TransitRoute buildTransitRoute(TransitLineInfo transitLineInfo, List<RouteElement> routeElements, RouteDirection direction) {
TransitLine transitLine = factory.getOrCreateTransitLine(transitLineInfo.getId());
TransitRoute buildTransitRoute(TransitRouteInfo transitRouteInfo, List<RouteElement> routeElements) {
TransitLine transitLine = factory.getOrCreateTransitLine(transitRouteInfo.getTransitLineInfo().getId());
List<Id<Link>> routeLinks = new ArrayList<>();
List<TransitRouteStop> routeStops = new ArrayList<>();
final double[] travelTime = {0};

// correct for route direction
List<RouteElement> directedRouteElements = switch (direction) {
case FORWARD -> routeElements;
case REVERSE -> routeElements.reversed();
};

// add first stop
RouteStop firstRouteStop = (RouteStop) directedRouteElements.getFirst();
RouteStop firstRouteStop = (RouteStop) routeElements.getFirst();
final TransitStopFacility[] stopFacility = {stopFacilities.get(firstRouteStop.getStopFacilityInfo().getId())};
TransitRouteStop transitRouteStop = factory.createTransitRouteStop(stopFacility[0], OptionalTime.undefined(),
OptionalTime.zeroSeconds());
routeStops.add(transitRouteStop);
routeLinks.add(stopFacility[0].getLinkId());

// loop over route elements, set first stop as last element and start with second element
for (int i = 1; i < directedRouteElements.size(); i++) {
boolean lastStop = i == directedRouteElements.size() - 1;
RouteElement lastElement = directedRouteElements.get(i - 1);
RouteElement currentElement = directedRouteElements.get(i);
for (int i = 1; i < routeElements.size(); i++) {
boolean lastStop = i == routeElements.size() - 1;
RouteElement lastElement = routeElements.get(i - 1);
RouteElement currentElement = routeElements.get(i);

// visit element
currentElement.accept(new RouteElementVisitor() {
Expand Down Expand Up @@ -111,18 +104,17 @@ public void visit(RoutePass routePass) {
});

// connect stop facilities on network and add stop link
routeLinks.addAll(connect(stopFacilities, addedSegments, transitLineInfo, lastElement, currentElement));
routeLinks.addAll(connect(stopFacilities, addedSegments, transitRouteInfo, lastElement, currentElement));
routeLinks.add(stopFacility[0].getLinkId());
}

return factory.createTransitRoute(transitLine,
String.format("%s_%s", transitLineInfo.getId(), direction.name()), routeLinks, routeStops);
return factory.createTransitRoute(transitLine, transitRouteInfo.getId(), routeLinks, routeStops);
}

// connects transit route stops on network, calls infrastructure repository for track information
private List<Id<Link>> connect(Map<String, TransitStopFacility> stopFacilities, Map<String, Id<Link>> addedSegments, TransitLineInfo transitLineInfo, RouteElement from, RouteElement to) {
private List<Id<Link>> connect(Map<String, TransitStopFacility> stopFacilities, Map<String, Id<Link>> addedSegments, TransitRouteInfo transitRouteInfo, RouteElement from, RouteElement to) {
List<TrackSegmentInfo> segments = infrastructureRepository.getTrack(from.getStopFacilityInfo(),
to.getStopFacilityInfo(), transitLineInfo);
to.getStopFacilityInfo(), transitRouteInfo);

List<Id<Link>> linkIds = new ArrayList<>();
int count = 0;
Expand Down
Loading

0 comments on commit d9ad9e7

Please sign in to comment.