MATSIM
IntersectionSimplifier.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * NetworkSimplifier.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2009 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 
21 package org.matsim.core.network.algorithms.intersectionSimplifier;
22 
23 import org.apache.logging.log4j.LogManager;
24 import org.apache.logging.log4j.Logger;
25 import org.matsim.api.core.v01.Coord;
26 import org.matsim.api.core.v01.Id;
34 
35 import java.util.*;
36 
42 public class IntersectionSimplifier {
43  final private static Logger LOG = LogManager.getLogger(IntersectionSimplifier.class);
44  final private double pmin;
45  final private int epsilon;
46 
47  private DensityCluster djc = null;
48  private final Map<Id<Node>, Node> mergedNodeId2clusterNode = new HashMap<>();
49 
50  public IntersectionSimplifier(double pmin, int epsilon) {
51  this.pmin = pmin;
52  this.epsilon = epsilon;
53  }
54 
55  public Network simplify(Network network) {
56  if (this.djc != null) {
57  LOG.error("This NetworkSimplifier has already been used to simplify a network!");
58  throw new RuntimeException("Should instantiate a new NetworkSimplifier");
59  }
60 
61  LOG.info("Simplifying the intersections...");
62  reportNetworkStatistics(network);
63  Network newNetwork = NetworkUtils.createNetwork();
64 
65  /* Get all the network's node coordinates that must be clustered. */
66  List<Node> nodes = new ArrayList<>();
67  for (Node node : network.getNodes().values()) {
68  /* Create new Node instances in order to assure that the original network can not be
69  * changed by accident */
70  nodes.add(NetworkUtils.createNode(node.getId(), node.getCoord()));
71  }
72 
73  /* Set up the clustering infrastructure. */
74  LOG.info("Clustering the network nodes...");
75  this.djc = new DensityCluster(nodes, true);
76  djc.clusterInput(pmin, epsilon);
77  LOG.info("Done clustering.");
78 
79  /* Do the mapping of clustered points. */
80  List<Cluster> clusters = djc.getClusterList();
81 
82  /* Populate a QuadTree with all the clustered nodes, each with a
83  * reference to the cluster they belong to. */
84  LOG.info("Populating QuadTree with clustered points.");
85  QuadTree<Node> clusteredNodes = new QuadTree<>(
86  djc.getClusteredPoints().getMinEasting(),
87  djc.getClusteredPoints().getMinNorthing(),
88  djc.getClusteredPoints().getMaxEasting(),
89  djc.getClusteredPoints().getMaxNorthing());
90  for (Cluster cluster : clusters) {
91  /* Add up node ids of all nodes merged into this clustered node
92  * and use it as id for the clustered node */
93  SortedSet<String> nodeIdsInCluster = new TreeSet<>();
94  for (ClusterActivity nodeInCluster : cluster.getPoints()) {
95  nodeIdsInCluster.add(nodeInCluster.getNode().getId().toString());
96  }
97  StringBuilder clusteredNodeName = new StringBuilder();
98  for (String nodeInCluster : nodeIdsInCluster) {
99  /* Don't add "-" if no node id is in the clusteredNodeName yet */
100  if (!clusteredNodeName.isEmpty()) {
101  clusteredNodeName.append('-');
102  }
103  clusteredNodeName.append(nodeInCluster);
104  }
105  Id<Node> newId = Id.createNodeId(clusteredNodeName.toString());
106 
107  Node newNode = network.getFactory().createNode(newId, cluster.getCenterOfGravity());
108  for (ClusterActivity clusterPoint : cluster.getPoints()) {
109  Coord clusterPointCoord = clusterPoint.getCoord();
110  clusteredNodes.put(clusterPointCoord.getX(), clusterPointCoord.getY(), newNode);
111  mergedNodeId2clusterNode.put(clusterPoint.getNode().getId(), newNode);
112  }
113  }
114  LOG.info("Done populating QuadTree. Number of nodes affected: " + clusteredNodes.size());
115 
116  /* Go through each network link, in given network, and evaluate it's nodes. */
117  for (Link link : network.getLinks().values()) {
118 
119  Node fromNode = NetworkUtils.createNode(link.getFromNode().getId(), link.getFromNode().getCoord());
120  Node fromCentroid = getClusteredNode(fromNode);
121 
122  Node toNode = NetworkUtils.createNode(link.getToNode().getId(), link.getToNode().getCoord());
123  Node toCentroid = getClusteredNode(toNode);
124 
125  Node newFromNode = fromCentroid != null ? fromCentroid : fromNode;
126  Node newToNode = toCentroid != null ? toCentroid : toNode;
127 
128  /* FIXME currently the new link carries no additional information
129  * from the original network. */
130  Link newLink = NetworkUtils.createLink(
131  link.getId(), newFromNode, newToNode, newNetwork,
132  link.getLength(), link.getFreespeed(), link.getCapacity(), link.getNumberOfLanes());
133  newLink.setAllowedModes(link.getAllowedModes());
134 
135  /* If both link nodes are part of the same cluster, their node
136  * Coords will now be the same. The link can be completely ignored,
137  * so we do not need to process it here any further. */
138  if (!newLink.getFromNode().getCoord().equals(newLink.getToNode().getCoord())) {
139  if (!newNetwork.getNodes().containsKey(newLink.getFromNode().getId())) {
140  /* FIXME currently the new node carries no additional
141  * information from the original network. */
142  NetworkUtils.createAndAddNode(newNetwork, newLink.getFromNode().getId(), newLink.getFromNode().getCoord());
143  }
144  if (!newNetwork.getNodes().containsKey(newLink.getToNode().getId())) {
145  NetworkUtils.createAndAddNode(newNetwork, newLink.getToNode().getId(), newLink.getToNode().getCoord());
146  }
147  newLink.setFromNode(newNetwork.getNodes().get(newFromNode.getId()));
148  newLink.setToNode(newNetwork.getNodes().get(newToNode.getId()));
149  newNetwork.addLink(newLink);
150  }
151  }
152 
153  /* Update the network name. */
154  String oldName = network.getName();
155  if (oldName != null) {
156  oldName += oldName.endsWith(".") ? " Simplified." : ". Simplified.";
157  newNetwork.setName(oldName);
158  } else {
159  LOG.warn("The given network does not have a description. This makes reproducibility hard!");
160  }
161 
162  LOG.info("Done simplifying the intersections");
163  reportNetworkStatistics(newNetwork);
164  return newNetwork;
165  }
166 
167 
171  protected Node getClusteredNode(Node node) {
172  // returns null if node was not merged into a clustered node
173  return mergedNodeId2clusterNode.get(node.getId());
174  }
175 
176 
181  public void writeClustersToFile(String file) {
182  if (this.djc == null) {
183  LOG.info("Density-based clustering has not been run yet. Cannot write to file.");
184  } else {
185  this.djc.writeClustersToFile(file);
186  }
187  }
188 
189 
193  public List<Cluster> getClusters() {
194  if (this.djc == null) {
195  LOG.warn("The network has not been simplified yet. Returning 0 clusters");
196  return new ArrayList<>(0);
197  }
198  return this.djc.getClusterList();
199  }
200 
204  public static void reportNetworkStatistics(Network network) {
205  LOG.info("--- Network statistics: ------------------------------------------------------");
206  LOG.info(" Network description: " + network.getName());
207  LOG.info(" Number of nodes: " + network.getNodes().size());
208  LOG.info(" Number of links: " + network.getLinks().size());
209  LOG.info("------------------------------------------------------------------------------");
210  }
211 
212 
213 }
Map< Id< Node >, ? extends Node > getNodes()
static Node createAndAddNode(Network network, final Id< Node > id, final Coord coord)
static Link createLink(Id< Link > id, Node from, Node to, Network network, double length, double freespeed, double capacity, double lanes)
boolean put(final double x, final double y, final T value)
Definition: QuadTree.java:86
boolean equals(final Object other)
Definition: Coord.java:107
Map< Id< Link >, ? extends Link > getLinks()
Node createNode(final Id< Node > id, final Coord coord)
static Node createNode(Id< Node > id)
static Id< Node > createNodeId(final long key)
Definition: Id.java:211