001/* *********************************************************************** * 002 * project: org.matsim.* 003 * CreatePseudoNetwork 004 * * 005 * *********************************************************************** * 006 * * 007 * copyright : (C) 2009 by the members listed in the COPYING, * 008 * LICENSE and WARRANTY file. * 009 * email : info at matsim dot org * 010 * * 011 * *********************************************************************** * 012 * * 013 * This program is free software; you can redistribute it and/or modify * 014 * it under the terms of the GNU General Public License as published by * 015 * the Free Software Foundation; either version 2 of the License, or * 016 * (at your option) any later version. * 017 * See also COPYING, LICENSE and WARRANTY file * 018 * * 019 * *********************************************************************** */ 020 021package org.matsim.pt.utils; 022 023import java.util.ArrayList; 024import java.util.Collections; 025import java.util.HashMap; 026import java.util.LinkedList; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030 031import org.matsim.api.core.v01.Id; 032import org.matsim.api.core.v01.TransportMode; 033import org.matsim.api.core.v01.network.Link; 034import org.matsim.api.core.v01.network.Network; 035import org.matsim.api.core.v01.network.Node; 036import org.matsim.core.population.routes.NetworkRoute; 037import org.matsim.core.population.routes.RouteUtils; 038import org.matsim.core.utils.collections.Tuple; 039import org.matsim.core.utils.geometry.CoordUtils; 040import org.matsim.pt.transitSchedule.api.TransitLine; 041import org.matsim.pt.transitSchedule.api.TransitRoute; 042import org.matsim.pt.transitSchedule.api.TransitRouteStop; 043import org.matsim.pt.transitSchedule.api.TransitSchedule; 044import org.matsim.pt.transitSchedule.api.TransitStopArea; 045import org.matsim.pt.transitSchedule.api.TransitStopFacility; 046 047/** 048 * Builds a network where transit vehicles can drive along and assigns the correct 049 * links to the transit stop facilities and routes of transit lines. As each transit 050 * stop facility can only be connected to at most one link, the algorithm is forced 051 * to duplicated transit stop facilities in certain cases to build the network. 052 * 053 * @author mrieser 054 */ 055public class CreatePseudoNetwork { 056 057 private final TransitSchedule schedule; 058 private final Network network; 059 private final String prefix; 060 private final double linkFreeSpeed; 061 private final double linkCapacity; 062 063 064 private final Map<Tuple<Node, Node>, Link> links = new HashMap<Tuple<Node, Node>, Link>(); 065 private final Map<Tuple<Node, Node>, TransitStopFacility> stopFacilities = new HashMap<Tuple<Node, Node>, TransitStopFacility>(); 066 private final Map<TransitStopFacility, Node> nodes = new HashMap<TransitStopFacility, Node>(); 067 private final Map<TransitStopFacility, List<TransitStopFacility>> facilityCopies = new HashMap<TransitStopFacility, List<TransitStopFacility>>(); 068 069 private long linkIdCounter = 0; 070 071 private final Set<String> transitModes = Collections.singleton(TransportMode.pt); 072 073 public CreatePseudoNetwork(final TransitSchedule schedule, final Network network, final String networkIdPrefix) { 074 this.schedule = schedule; 075 this.network = network; 076 this.prefix = networkIdPrefix; 077 this.linkFreeSpeed = 100.0 / 3.6; 078 this.linkCapacity = 100000.0; 079 } 080 081 public CreatePseudoNetwork(final TransitSchedule schedule, final Network network, final String networkIdPrefix, 082 final double linkFreeSpeed, final double linkCapacity) { 083 this.schedule = schedule; 084 this.network = network; 085 this.prefix = networkIdPrefix; 086 this.linkFreeSpeed = linkFreeSpeed; 087 this.linkCapacity = linkCapacity; 088 } 089 090 public void createNetwork() { 091 092 List<Tuple<TransitLine, TransitRoute>> toBeRemoved = new LinkedList<Tuple<TransitLine, TransitRoute>>(); 093 094 for (TransitLine tLine : this.schedule.getTransitLines().values()) { 095 for (TransitRoute tRoute : tLine.getRoutes().values()) { 096 ArrayList<Id<Link>> routeLinks = new ArrayList<Id<Link>>(); 097 TransitRouteStop prevStop = null; 098 for (TransitRouteStop stop : tRoute.getStops()) { 099 Link link = getNetworkLink(prevStop, stop); 100 routeLinks.add(link.getId()); 101 prevStop = stop; 102 } 103 104 if (routeLinks.size() > 0) { 105 NetworkRoute route = RouteUtils.createNetworkRoute(routeLinks, this.network); 106 tRoute.setRoute(route); 107 } else { 108 System.err.println("Line " + tLine.getId() + " route " + tRoute.getId() + " has less than two stops. Removing this route from schedule."); 109 toBeRemoved.add(new Tuple<TransitLine, TransitRoute>(tLine, tRoute)); 110 } 111 } 112 } 113 114 for (Tuple<TransitLine, TransitRoute> remove : toBeRemoved) { 115 remove.getFirst().removeRoute(remove.getSecond()); 116 } 117 } 118 119 private Link getNetworkLink(final TransitRouteStop fromStop, final TransitRouteStop toStop) { 120 TransitStopFacility fromFacility = (fromStop == null) ? toStop.getStopFacility() : fromStop.getStopFacility(); 121 TransitStopFacility toFacility = toStop.getStopFacility(); 122 123 Node fromNode = this.nodes.get(fromFacility); 124 if (fromNode == null) { 125 fromNode = this.network.getFactory().createNode(Id.create(this.prefix + toFacility.getId(), Node.class), fromFacility.getCoord()); 126 this.network.addNode(fromNode); 127 this.nodes.put(toFacility, fromNode); 128 } 129 130 Node toNode = this.nodes.get(toFacility); 131 if (toNode == null) { 132 toNode = this.network.getFactory().createNode(Id.create(this.prefix + toFacility.getId(), Node.class), toFacility.getCoord()); 133 this.network.addNode(toNode); 134 this.nodes.put(toFacility, toNode); 135 } 136 137 Tuple<Node, Node> connection = new Tuple<Node, Node>(fromNode, toNode); 138 Link link = this.links.get(connection); 139 if (link == null) { 140 link = createAndAddLink(fromNode, toNode, connection); 141 142 if (toFacility.getLinkId() == null) { 143 toFacility.setLinkId(link.getId()); 144 this.stopFacilities.put(connection, toFacility); 145 } else { 146 List<TransitStopFacility> copies = this.facilityCopies.get(toFacility); 147 if (copies == null) { 148 copies = new ArrayList<TransitStopFacility>(); 149 this.facilityCopies.put(toFacility, copies); 150 } 151 Id<TransitStopFacility> newId = Id.create(toFacility.getId().toString() + "." + Integer.toString(copies.size() + 1), TransitStopFacility.class); 152 TransitStopFacility newFacility = this.schedule.getFactory().createTransitStopFacility(newId, toFacility.getCoord(), toFacility.getIsBlockingLane()); 153 newFacility.setStopAreaId(Id.create(toFacility.getId(), TransitStopArea.class)); 154 newFacility.setLinkId(link.getId()); 155 newFacility.setName(toFacility.getName()); 156 copies.add(newFacility); 157 this.nodes.put(newFacility, toNode); 158 this.schedule.addStopFacility(newFacility); 159 toStop.setStopFacility(newFacility); 160 this.stopFacilities.put(connection, newFacility); 161 } 162 } else { 163 toStop.setStopFacility(this.stopFacilities.get(connection)); 164 } 165 return link; 166 } 167 168 private Link createAndAddLink(Node fromNode, Node toNode, 169 Tuple<Node, Node> connection) { 170 Link link; 171 link = this.network.getFactory().createLink(Id.create(this.prefix + this.linkIdCounter++, Link.class), fromNode, toNode); 172 if (fromNode == toNode) { 173 link.setLength(50); 174 } else { 175 link.setLength(CoordUtils.calcEuclideanDistance(fromNode.getCoord(), toNode.getCoord())); 176 } 177 link.setFreespeed(linkFreeSpeed); 178 link.setCapacity(linkCapacity); 179 link.setNumberOfLanes(1); 180 this.network.addLink(link); 181 link.setAllowedModes(this.transitModes); 182 this.links.put(connection, link); 183 return link; 184 } 185 186 public Link getLinkBetweenStops(final TransitStopFacility fromStop, final TransitStopFacility toStop) { 187 Node fromNode = this.nodes.get(fromStop); 188 Node toNode = this.nodes.get(toStop); 189 Tuple<Node, Node> connection = new Tuple<Node, Node>(fromNode, toNode); 190 return this.links.get(connection); 191 } 192 193}