diff --git a/contribs/application/src/main/java/org/matsim/application/prepare/network/CleanNetwork.java b/contribs/application/src/main/java/org/matsim/application/prepare/network/CleanNetwork.java index 8b3e621ac22..64cef3959ac 100644 --- a/contribs/application/src/main/java/org/matsim/application/prepare/network/CleanNetwork.java +++ b/contribs/application/src/main/java/org/matsim/application/prepare/network/CleanNetwork.java @@ -1,8 +1,10 @@ package org.matsim.application.prepare.network; import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.application.MATSimAppCommand; +import org.matsim.core.network.DisallowedNextLinks; import org.matsim.core.network.NetworkUtils; import org.matsim.core.network.algorithms.MultimodalNetworkCleaner; import picocli.CommandLine; @@ -25,11 +27,30 @@ public class CleanNetwork implements MATSimAppCommand { @CommandLine.Option(names = "--modes", description = "List of modes to clean", split = ",", defaultValue = TransportMode.car) private Set modes; + @CommandLine.Option(names = "--remove-turn-restrictions", description = "Remove turn restrictions for specified modes.", defaultValue = "false") + private boolean rmTurnRestrictions; + + public static void main(String[] args) { + new CleanNetwork().execute(args); + } + @Override public Integer call() throws Exception { Network network = NetworkUtils.readNetwork(input.toString()); + if (rmTurnRestrictions) { + for (Link link : network.getLinks().values()) { + DisallowedNextLinks disallowed = NetworkUtils.getDisallowedNextLinks(link); + if (disallowed != null) { + modes.forEach(disallowed::removeDisallowedLinkSequences); + if (disallowed.isEmpty()) { + NetworkUtils.removeDisallowedNextLinks(link); + } + } + } + } + var cleaner = new MultimodalNetworkCleaner(network); for (String m : modes) { diff --git a/contribs/sumo/src/main/java/org/matsim/contrib/sumo/SumoNetworkConverter.java b/contribs/sumo/src/main/java/org/matsim/contrib/sumo/SumoNetworkConverter.java index 592243b1310..378703db1eb 100644 --- a/contribs/sumo/src/main/java/org/matsim/contrib/sumo/SumoNetworkConverter.java +++ b/contribs/sumo/src/main/java/org/matsim/contrib/sumo/SumoNetworkConverter.java @@ -5,7 +5,6 @@ import org.apache.commons.csv.CSVPrinter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.locationtech.jts.geom.Geometry; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.TransportMode; @@ -21,7 +20,6 @@ import org.matsim.core.scenario.ProjectionUtils; import org.matsim.core.utils.geometry.CoordinateTransformation; import org.matsim.core.utils.geometry.transformations.TransformationFactory; -import org.matsim.core.utils.gis.GeoFileReader; import org.matsim.core.utils.io.IOUtils; import org.xml.sax.SAXException; import picocli.CommandLine; @@ -70,8 +68,8 @@ private SumoNetworkConverter(List input, Path output, String fromCRS, Stri this.fromCRS = fromCRS; this.toCRS = toCRS; this.freeSpeedFactor = freeSpeedFactor; - this.laneRestriction = laneRestriction; - } + this.laneRestriction = laneRestriction; + } private SumoNetworkConverter() { } @@ -119,14 +117,6 @@ public static void main(String[] args) { System.exit(new CommandLine(new SumoNetworkConverter()).execute(args)); } - /** - * Network area based on the cut-out. - */ - private static Geometry calculateNetworkArea(Path shapeFile) { - // only the first feature is used - return ((Geometry) GeoFileReader.getAllFeatures(shapeFile.toString()).iterator().next().getDefaultGeometry()); - } - /** * Determine if a mode is allowed on a link. */ @@ -342,6 +332,9 @@ public SumoNetworkHandler convert(Network network) throws ParserConfigurationExc Set> ignored = new HashSet<>(); + // map of link and source link that are restricted + Map, Set>> restrictions = new HashMap<>(); + for (Map.Entry> kv : sumoHandler.connections.entrySet()) { Link link = network.getLinks().get(Id.createLinkId(kv.getKey())); @@ -350,16 +343,30 @@ public SumoNetworkHandler convert(Network network) throws ParserConfigurationExc Set> outLinks = link.getToNode().getOutLinks().keySet(); Set> allowed = kv.getValue().stream().map(c -> Id.createLinkId(c.to)).collect(Collectors.toSet()); - Sets.SetView> diff = Sets.difference(outLinks, allowed); + // Disallowed link ids + Sets.SetView> dis = Sets.difference(outLinks, allowed); - if (outLinks.size() == diff.size()) { + if (outLinks.size() == dis.size()) { ignored.add(link.getId()); continue; } - if (!diff.isEmpty()) { + if (!dis.isEmpty()) { DisallowedNextLinks disallowed = new DisallowedNextLinks(); - for (Id id : diff) { + for (Id id : dis) { + + Set> restricted = restrictions.computeIfAbsent(id, (k) -> new HashSet<>()); + + Link targetLink = network.getLinks().get(id); + Map, ? extends Link> turnLinks = targetLink.getFromNode().getOutLinks(); + + // Ensure that a link is always reachable from at least one other link + if (turnLinks.size() - 1 <= restricted.size()) { + ignored.add(id); + continue; + } + + restricted.add(link.getId()); disallowed.addDisallowedLinkSequence(TransportMode.car, List.of(id)); } @@ -368,6 +375,9 @@ public SumoNetworkHandler convert(Network network) throws ParserConfigurationExc } } + // clean again (possibly with turn restrictions) + new NetworkCleaner().run(network); + if (!ignored.isEmpty()) { log.warn("Ignored turn restrictions for {} links with no connections: {}", ignored.size(), ignored); }