MATSIM
CompressedNetworkRouteImpl.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * CompressedRoute.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2008 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.population.routes;
22 
23 import java.util.ArrayList;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 
29 import org.apache.logging.log4j.LogManager;
30 import org.apache.logging.log4j.Logger;
31 import org.matsim.api.core.v01.Id;
36 import org.matsim.vehicles.Vehicle;
37 
58 final class CompressedNetworkRouteImpl extends AbstractRoute implements NetworkRoute, Cloneable {
59 
60  private final static Logger log = LogManager.getLogger(CompressedNetworkRouteImpl.class);
61 
62  private ArrayList<Id<Link>> route = new ArrayList<>(0);
63  private final Map<Id<Link>, Id<Link>> subsequentLinks;
64  private double travelCost = Double.NaN;
66  private int uncompressedLength = -1;
67  private Id<Vehicle> vehicleId = null;
68  private final Network network;
69  private final Map<Id<Link>, ? extends Link> links;
70 
71  public CompressedNetworkRouteImpl(final Id<Link> startLinkId, final Id<Link> endLinkId, Network network, final Map<Id<Link>, Id<Link>> subsequentLinks) {
72  super(startLinkId, endLinkId);
73  this.network = network;
74  this.links = network.getLinks();
75  this.subsequentLinks = subsequentLinks;
76  }
77 
78  @Override
79  public CompressedNetworkRouteImpl clone() {
80  CompressedNetworkRouteImpl cloned = (CompressedNetworkRouteImpl) super.clone();
81  ArrayList<Id<Link>> tmpRoute = cloned.route;
82  cloned.route = new ArrayList<>(tmpRoute); // deep copy
83  return cloned;
84  }
85 
86  @Override
87  public List<Id<Link>> getLinkIds() {
88  if (this.uncompressedLength < 0) { // it seems the route never got initialized correctly
89  return new ArrayList<>(0);
90  }
91  ArrayList<Id<Link>> links = new ArrayList<>(this.uncompressedLength);
92  Id<Link> previousLinkId = getStartLinkId();
93  Id<Link> endLinkId = getEndLinkId();
94  if ((previousLinkId == null) || (endLinkId == null)) {
95  return links;
96  }
97  if (previousLinkId.equals(endLinkId) && this.uncompressedLength == 0) {
98  return links;
99  }
100  for (Id<Link> linkId : this.route) {
101  getLinksTillLink(links, linkId, previousLinkId);
102  links.add(linkId);
103  previousLinkId = linkId;
104  }
105  getLinksTillLink(links, endLinkId, previousLinkId);
106 
107  return links;
108  }
109 
110  private void getLinksTillLink(final List<Id<Link>> links, final Id<Link> nextLinkId, final Id<Link> startLinkId) {
111  Id<Link> linkId = startLinkId;
112  Link nextLink = this.links.get(nextLinkId);
113  while (true) { // loop until we hit "return;"
114  Link link = this.links.get(linkId);
115  if (link.getToNode() == nextLink.getFromNode()) {
116  return;
117  }
118  linkId = this.subsequentLinks.get(linkId);
119  links.add(linkId);
120  }
121  }
122 
123  @Override
124  public NetworkRoute getSubRoute(Id<Link> fromLinkId, Id<Link> toLinkId) {
125  List<Id<Link>> newLinkIds = new ArrayList<>(10);
126  boolean foundFromLink = fromLinkId.equals(this.getStartLinkId());
127  boolean collectLinks = foundFromLink;
128  boolean equalFromTo = fromLinkId.equals(toLinkId);
129 
130  if (!foundFromLink || !equalFromTo) {
131  for (Id<Link> linkId : getLinkIds()) {
132  if (linkId.equals(toLinkId)) {
133  collectLinks = false;
134  if (equalFromTo) {
135  foundFromLink = true;
136  }
137  if (foundFromLink) {
138  // only break if from is also found, as endLink could be part of a loop/circle
139  break; // we found start and end, stop looping
140  }
141  }
142  if (collectLinks) {
143  newLinkIds.add(linkId);
144  }
145  if (linkId.equals(fromLinkId)) {
146  foundFromLink = true;
147  collectLinks = true; // we found the start, start collecting
148  newLinkIds.clear(); // in case of a loop, cut it out
149  }
150  }
151  if (!foundFromLink) {
152  foundFromLink = fromLinkId.equals(this.getEndLinkId());
153  collectLinks = foundFromLink;
154  }
155  if (!foundFromLink) {
156  throw new IllegalArgumentException("fromLinkId is not part of this route.");
157  }
158  if ((collectLinks) && (toLinkId.equals(this.getEndLinkId()))) {
159  collectLinks = false;
160  }
161  if (collectLinks) {
162  throw new IllegalArgumentException("toLinkId is not part of this route.");
163  }
164  }
165  NetworkRoute subRoute = new CompressedNetworkRouteImpl(fromLinkId, toLinkId, this.network, this.subsequentLinks);
166  subRoute.setLinkIds(fromLinkId, newLinkIds, toLinkId);
167  return subRoute;
168  }
169 
170  @Override
171  public double getTravelCost() {
172  return this.travelCost;
173  }
174 
175  @Override
176  public void setTravelCost(final double travelCost) {
177  this.travelCost = travelCost;
178  }
179 
180  @Override
181  public void setLinkIds(final Id<Link> startLinkId, final List<Id<Link>> srcRoute, final Id<Link> endLinkId) {
182  this.route.clear();
183  Set<Id<Node>> visitedNodes = new HashSet<>();
184  Set<Id<Node>> multiplyVisitedNodes = new HashSet<>();
185  setStartLinkId(startLinkId);
186  setEndLinkId(endLinkId);
187  if ((srcRoute == null) || (srcRoute.size() == 0)) {
188  this.uncompressedLength = 0;
189  return;
190  }
191  // compress route
192  Id<Link> previousLinkId = startLinkId;
193  for (Id<Link> linkId : srcRoute) {
194  Link link = this.links.get(linkId);
195  Id<Node> fromNodeId = link.getFromNode().getId();
196  if (!visitedNodes.add(fromNodeId)) {
197  // the node was already visited
198  multiplyVisitedNodes.add(fromNodeId);
199  }
200  if (!this.subsequentLinks.get(previousLinkId).equals(linkId)) {
201  this.route.add(linkId);
202  }
203  previousLinkId = linkId;
204  }
205  Link endLink = this.links.get(endLinkId);
206  Id<Node> fromNodeId = endLink.getFromNode().getId();
207  if (!visitedNodes.add(fromNodeId)) {
208  // the node was already visited
209  multiplyVisitedNodes.add(fromNodeId);
210  }
211 
212  if (!multiplyVisitedNodes.isEmpty()) {
213  // the route contains at least one loop, we need to re-encode it and make sure
214  // that no loop is left out when reconstructing the uncompressed route
215  this.route.clear();
216  previousLinkId = startLinkId;
217  for (Id<Link> linkId : srcRoute) {
218  Link link = this.links.get(linkId);
219  fromNodeId = link.getFromNode().getId();
220  if (!this.subsequentLinks.get(previousLinkId).equals(linkId) || multiplyVisitedNodes.contains(fromNodeId)) {
221  this.route.add(linkId);
222  }
223  previousLinkId = linkId;
224  }
225  }
226 
227  this.route.trimToSize();
228  this.uncompressedLength = srcRoute.size();
229 // System.out.println("uncompressed size: \t" + this.uncompressedLength + "\tcompressed size: \t" + this.route.size());
230 
231  this.setLocked() ;
232  }
233 
234  @Override
235  public Id<Vehicle> getVehicleId() {
236  return this.vehicleId;
237  }
238 
239  @Override
240  public void setVehicleId(final Id<Vehicle> vehicleId) {
241  this.vehicleId = vehicleId;
242  }
243 
244  @Override
245  public String getRouteType() {
246  return "links";
247  }
248 
249  @Override
250  public String getRouteDescription() {
251  StringBuilder desc = new StringBuilder(100);
252  desc.append(this.getStartLinkId().toString());
253  for (Id<Link> linkId : this.getLinkIds()) {
254  desc.append(" ");
255  desc.append(linkId.toString());
256  }
257  // If the start links equals the end link additionally check if its is a round trip.
258  if (!this.getEndLinkId().equals(this.getStartLinkId()) || this.getLinkIds().size() > 0) {
259  desc.append(" ");
260  desc.append(this.getEndLinkId().toString());
261  }
262  return desc.toString();
263  }
264 
265  @Override
266  public void setRouteDescription(String routeDescription) {
267  List<Id<Link>> linkIds = NetworkUtils.getLinkIds(routeDescription);
268  Id<Link> startLinkId = getStartLinkId();
269  Id<Link> endLinkId = getEndLinkId();
270  if (linkIds.size() > 0) {
271  startLinkId = linkIds.remove(0);
272  setStartLinkId(startLinkId);
273  }
274  if (linkIds.size() > 0) {
275  endLinkId = linkIds.remove(linkIds.size() - 1);
276  setEndLinkId(endLinkId);
277  }
278  this.setLinkIds(startLinkId, linkIds, endLinkId);
279 
280  }
281 
282 }
final void setEndLinkId(final Id< Link > linkId)
final void setStartLinkId(final Id< Link > linkId)