Skip to content

Commit

Permalink
script to create gartenfeld network
Browse files Browse the repository at this point in the history
  • Loading branch information
rakow committed Jul 15, 2024
1 parent 5821048 commit a362062
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 18 deletions.
37 changes: 37 additions & 0 deletions input/gartenfeld/DNG_LinksToDelete.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
647375444
-647375444
883834076
-883834076
178253966
-178253966
936729763
178253967
744696593
-744696593
374301094#1
-374301094#1
178253961#1
178253972
178253961#0
-1060659771
178253969
374301096
-374301096
1007431595
-1007431595
1007431597
-1007431597
374301095#0
374301095#1
-647375378
647375378
682423175
-647375376
647375376
682423176
-1060659769#1
1060659769#1
-883834166
883834166
-1060659769#0
672144104#1
Binary file added input/gartenfeld/DNG_network.gpkg
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.matsim.policies.gartenfeld;

import org.matsim.application.MATSimAppCommand;
import org.matsim.prepare.network.ModifyNetwork;
import picocli.CommandLine;

@CommandLine.Command(name = "create-gartenfeld-network", description = "Create the network for the Gartenfeld scenario.")
public class CreateGartenfeldNetwork implements MATSimAppCommand {

public static void main(String[] args) {
new CreateGartenfeldNetwork().execute(args);
}

@Override
public Integer call() throws Exception {

new ModifyNetwork().execute(
"--network", "input/v6.3/berlin-v6.3-network-with-pt.xml.gz",
"--remove-links", "input/gartenfeld/DNG_LinksToDelete.txt",
"--shp", "input/gartenfeld/DNG_network.gpkg",
"--output", "input/gartenfeld/gartenfeld-network.xml.gz"
);

return 0;
}

}
112 changes: 94 additions & 18 deletions src/main/java/org/matsim/prepare/network/ModifyNetwork.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,26 @@
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.index.strtree.STRtree;
import org.matsim.api.core.v01.Id;
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.api.core.v01.network.Node;
import org.matsim.application.MATSimAppCommand;
import org.matsim.application.options.ShpOptions;
import org.matsim.core.network.NetworkUtils;
import org.matsim.core.network.algorithms.MultimodalNetworkCleaner;
import org.matsim.core.utils.geometry.geotools.MGC;
import picocli.CommandLine;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collectors;

@CommandLine.Command(name = "modify-network", description = "Remove or add network elements")
public class ModifyNetwork implements MATSimAppCommand {
Expand All @@ -44,91 +49,162 @@ public class ModifyNetwork implements MATSimAppCommand {
@CommandLine.Mixin
private ShpOptions shp = new ShpOptions();

private Network network;
private STRtree nodeIndex;

public static void main(String[] args) {
new ModifyNetwork().execute(args);
}

@Override
public Integer call() throws Exception {

Network network = NetworkUtils.readNetwork(networkPath);
network = NetworkUtils.readNetwork(networkPath);

if (removeCSV != null) {
removeLinks(network);
}

if (shp.isDefined()) {
addLinksFromShape(network);
addLinksFromShape();
}

MultimodalNetworkCleaner cleaner = new MultimodalNetworkCleaner(network);

cleaner.run(Set.of(TransportMode.car));
cleaner.run(Set.of(TransportMode.bike));

NetworkUtils.writeNetwork(network, output.toString());

return 0;
}

private void removeLinks(Network network) throws IOException {

int removed = 0;

for (String line : Files.readAllLines(removeCSV)) {
Id<Link> linkId = Id.createLinkId(line);
network.removeLink(linkId);
removed++;
}

// Remove links that are not connected
List<Id<Node>> toRemove = network.getNodes().values().stream().filter(n -> n.getInLinks().isEmpty() && n.getOutLinks().isEmpty())
.map(Node::getId)
.toList();

log.info("Removed %d links and %d nodes".formatted(removed, toRemove.size()));

toRemove.forEach(network::removeNode);
}

/**
* Read line geometry from a shapefile and add links to the network.
*/
private void addLinksFromShape(Network network) {
private void addLinksFromShape() {

STRtree nodeIndex = new STRtree();
for (Node node : network.getNodes().values()) {
nodeIndex.insert(MGC.coord2Point(node.getCoord()).getEnvelopeInternal(), node);
}
nodeIndex.build();
nodeIndex = createIndex(network);

int added = 0;
List<SimpleFeature> features = shp.readFeatures();
for (SimpleFeature feature : features) {
// Find the nearest node
LineString geom = (LineString) feature.getDefaultGeometry();

Id<Link> linkId = Id.createLinkId(feature.getID());
Node fromNode = matchNode(nodeIndex, geom.getCoordinateN(0));
Node toNode = matchNode(nodeIndex, geom.getCoordinateN(geom.getNumPoints() - 1));
String linkId = feature.getID();
Node fromNode = matchNode(nodeIndex, geom.getCoordinateN(0), "from_" + linkId);
Node toNode = matchNode(nodeIndex, geom.getCoordinateN(geom.getNumPoints() - 1), "to_" + linkId);

if (fromNode == toNode) {
throw new IllegalArgumentException("Link %s would have the same start and end node. Check the shapefile and improve matching to zones.".formatted(linkId));
throw new IllegalArgumentException("Link %s would have the same start and end node. Check the shapefile and improve matching to nodes.".formatted(linkId));
}

Link link = network.getFactory().createLink(linkId, fromNode, toNode);
addLink(linkId, feature, fromNode, toNode);
if (feature.getAttribute("is_oneway") != Boolean.TRUE) {
addLink(linkId + "_r", feature, toNode, fromNode);
}

// TODO: Set link attributes
added++;
}

network.addLink(link);
log.info("Added %d links".formatted(added));
}

private STRtree createIndex(Network network) {
STRtree index = new STRtree();
for (Node node : network.getNodes().values()) {
index.insert(MGC.coord2Point(node.getCoord()).getEnvelopeInternal(), node);
}
index.build();
return index;
}

@SuppressWarnings("unchecked")
private Node matchNode(STRtree index, Coordinate coord) {
private Node matchNode(STRtree index, Coordinate coord, String nodeId) {

Point point = MGC.coordinate2Point(coord);

ToDoubleFunction<Object> distance = n -> NetworkUtils.getEuclideanDistance(((Node) n).getCoord(), MGC.coordinate2Coord(coord));

List<Node> result = index.query(point.buffer(matchingDistance).getEnvelopeInternal())
List<Node> query = index.query(point.buffer(matchingDistance * 2).getEnvelopeInternal());

List<Node> result = query
.stream()
.map(Node.class::cast)
.filter(n -> distance.applyAsDouble(n) < matchingDistance)
.sorted(Comparator.comparingDouble(distance))
.toList();

if (result.isEmpty()) {
throw new IllegalArgumentException("No node found for coordinate %s".formatted(coord));

Id<Node> id = Id.createNodeId(nodeId);
Node node = network.getFactory().createNode(id, MGC.coordinate2Coord(coord));
network.addNode(node);
nodeIndex = createIndex(network);

return node;
}

return result.getFirst();
}

private void addLink(String id, SimpleFeature feature, Node fromNode, Node toNode) {

Id<Link> linkId = Id.createLinkId(id);
Link link = network.getFactory().createLink(linkId, fromNode, toNode);

String modes = (String) feature.getAttribute("Allowed Transport Mode");
if (modes != null) {
String[] m = modes.split(",");
link.setAllowedModes(Arrays.stream(m).collect(Collectors.toSet()));
} else {
link.setAllowedModes(Set.of(TransportMode.car, TransportMode.bike, TransportMode.truck, "freight"));
}

Object freespeed = feature.getAttribute("Free Speed");
if (freespeed != null)
link.setFreespeed((Double) freespeed);
else
link.setFreespeed(30.0 / 3.6);

Object allowedSpeed = feature.getAttribute("allowed_speed");
if (allowedSpeed != null)
link.getAttributes().putAttribute(NetworkUtils.ALLOWED_SPEED, allowedSpeed);

Object capacity = feature.getAttribute("Capacity");
if (capacity != null)
link.setCapacity((Double) capacity);
else
link.setFreespeed(800);

Object numberOfLanes = feature.getAttribute("Number of Lanes");
if (numberOfLanes != null)
link.setNumberOfLanes((Double) numberOfLanes);
else
link.setNumberOfLanes(1);

network.addLink(link);
}

}

0 comments on commit a362062

Please sign in to comment.