MATSIM
TransitScheduleReaderV2.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * *
4  * *********************************************************************** *
5  * *
6  * copyright : (C) 2018 by the members listed in the COPYING, *
7  * LICENSE and WARRANTY file. *
8  * email : info at matsim dot org *
9  * *
10  * *********************************************************************** *
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * See also COPYING, LICENSE and WARRANTY file *
17  * *
18  * *********************************************************************** */
19 
20 package org.matsim.pt.transitSchedule;
21 
22 import java.util.ArrayList;
23 import java.util.LinkedHashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Stack;
27 import java.util.concurrent.ConcurrentHashMap;
28 
29 import org.apache.logging.log4j.LogManager;
30 import org.apache.logging.log4j.Logger;
31 import org.matsim.api.core.v01.Coord;
32 import org.matsim.api.core.v01.Id;
33 import org.matsim.api.core.v01.Scenario;
42 import org.matsim.core.utils.misc.Time;
52 import org.matsim.vehicles.Vehicle;
53 import org.xml.sax.Attributes;
54 
61  private static final Logger log = LogManager.getLogger(TransitScheduleReaderV2.class);
62 
63  private final String externalInputCRS;
64  private final String targetCRS;
65  private final TransitSchedule schedule;
67 
71  private Departure currentDeparture = null;
72 
75 
77  private final StringCache cache = new StringCache();
78 
79  public TransitScheduleReaderV2(final TransitSchedule schedule, final RouteFactories routeFactory) {
80  this( null, null , schedule , routeFactory );
81  }
82 
84  final String externalInputCRS,
85  final String targetCRS,
86  final Scenario scenario) {
88  }
89 
91  String externalInputCRS,
92  String targetCRS,
93  TransitSchedule schedule,
94  RouteFactories routeFactory) {
95  super(ValidationType.DTD_ONLY);
96  this.externalInputCRS = externalInputCRS;
97  this.targetCRS = targetCRS;
98  this.schedule = schedule;
99  this.routeFactory = routeFactory;
100  if (externalInputCRS != null && targetCRS != null) {
101  this.coordinateTransformation = TransformationFactory.getCoordinateTransformation(externalInputCRS, targetCRS);
102  ProjectionUtils.putCRS(this.schedule, targetCRS);
103  }
104  }
105 
106  @Override
107  public void startTag(final String name, final Attributes atts, final Stack<String> context) {
108  if (Constants.STOP_FACILITY.equals(name)) {
109  boolean isBlocking = Boolean.parseBoolean(atts.getValue(Constants.IS_BLOCKING));
110  Coord coord = atts.getValue(Constants.Z) == null ?
111  new Coord(Double.parseDouble(atts.getValue(Constants.X)), Double.parseDouble(atts.getValue(Constants.Y))) :
112  new Coord(Double.parseDouble(atts.getValue(Constants.X)), Double.parseDouble(atts.getValue(Constants.Y)), Double.parseDouble(atts.getValue(Constants.Z)));
113  TransitStopFacility stop =
114  this.schedule.getFactory().createTransitStopFacility(
115  Id.create(atts.getValue(Constants.ID), TransitStopFacility.class),
116  this.coordinateTransformation.transform(coord),
117  isBlocking);
118  this.currentAttributes = stop.getAttributes();
119  if (atts.getValue(Constants.LINK_REF_ID) != null) {
120  Id<Link> linkId = Id.create(atts.getValue(Constants.LINK_REF_ID), Link.class);
121  stop.setLinkId(linkId);
122  }
123  if (atts.getValue(Constants.NAME) != null) {
124  stop.setName(this.cache.get(atts.getValue(Constants.NAME)));
125  }
126  if (atts.getValue(Constants.STOP_AREA_ID) != null) {
127  stop.setStopAreaId(Id.create(atts.getValue(Constants.STOP_AREA_ID), TransitStopArea.class));
128  }
129  this.schedule.addStopFacility(stop);
130  } else if (Constants.TRANSIT_LINE.equals(name)) {
131  Id<TransitLine> id = Id.create(atts.getValue(Constants.ID), TransitLine.class);
132  this.currentTransitLine = this.schedule.getFactory().createTransitLine(id);
133  this.currentAttributes = this.currentTransitLine.getAttributes();
134  if (atts.getValue(Constants.NAME) != null) {
135  this.currentTransitLine.setName(atts.getValue(Constants.NAME));
136  }
137  this.schedule.addTransitLine(this.currentTransitLine);
138  } else if (Constants.TRANSIT_ROUTE.equals(name)) {
139  Id<TransitRoute> id = Id.create(atts.getValue(Constants.ID), TransitRoute.class);
140  this.currentTransitRoute = new TempTransitRoute(id);
141  this.currentAttributes = this.currentTransitRoute.attributes;
142  } else if (Constants.DEPARTURE.equals(name)) {
143  Id<Departure> id = Id.create(atts.getValue(Constants.ID), Departure.class);
144  this.currentDeparture = new DepartureImpl(id, Time.parseTime(atts.getValue("departureTime")));
145  this.currentAttributes = this.currentDeparture.getAttributes();
146  String vehicleRefId = atts.getValue(Constants.VEHICLE_REF_ID);
147  if (vehicleRefId != null) {
148  this.currentDeparture.setVehicleId(Id.create(vehicleRefId, Vehicle.class));
149  }
150  this.currentTransitRoute.departures.put(id, this.currentDeparture);
151  } else if (Constants.ROUTE_PROFILE.equals(name)) {
152  this.currentRouteProfile = new TempRoute();
153  } else if (Constants.LINK.equals(name)) {
154  String linkStr = atts.getValue(Constants.REF_ID);
155  if (!linkStr.contains(" ")) {
156  this.currentRouteProfile.addLink(Id.create(linkStr, Link.class));
157  } else {
158  String[] links = linkStr.split(" ");
159  for (int i = 0; i < links.length; i++) {
160  this.currentRouteProfile.addLink(Id.create(links[i], Link.class));
161  }
162  }
163  } else if (Constants.STOP.equals(name)) {
164  Id<TransitStopFacility> id = Id.create(atts.getValue(Constants.REF_ID), TransitStopFacility.class);
165  TransitStopFacility facility = this.schedule.getFacilities().get(id);
166  if (facility == null) {
167  throw new RuntimeException("no stop/facility with id " + atts.getValue(Constants.REF_ID));
168  }
169  TransitRouteStopImpl.Builder stopBuilder = new TransitRouteStopImpl.Builder().stop(facility);
170  String arrival = atts.getValue(Constants.ARRIVAL_OFFSET);
171  String departure = atts.getValue(Constants.DEPARTURE_OFFSET);
172  if (arrival != null) {
173  Time.parseOptionalTime(arrival).ifDefined(stopBuilder::arrivalOffset);
174  }
175  if (departure != null) {
176  Time.parseOptionalTime(departure).ifDefined(stopBuilder::departureOffset);
177  }
178  stopBuilder.allowBoarding(Boolean.parseBoolean(atts.getValue(Constants.ALLOW_BOARDING)));
179  stopBuilder.allowAlighting(Boolean.parseBoolean(atts.getValue(Constants.ALLOW_ALIGHTING)));
180  stopBuilder.awaitDepartureTime(Boolean.parseBoolean(atts.getValue(Constants.AWAIT_DEPARTURE)));
181  this.currentTransitRoute.stopBuilders.add(stopBuilder);
182  } else if (Constants.RELATION.equals(name)) {
183  Id<TransitStopFacility> fromStop = Id.create(atts.getValue(Constants.FROM_STOP), TransitStopFacility.class);
184  Id<TransitStopFacility> toStop = Id.create(atts.getValue(Constants.TO_STOP), TransitStopFacility.class);
185  double transferTime = Time.parseTime(atts.getValue(Constants.TRANSFER_TIME));
186  this.schedule.getMinimalTransferTimes().set(fromStop, toStop, transferTime);
187  } else if (Constants.ATTRIBUTE.equals(name)) {
188  this.attributesDelegate.startTag(name, atts, context, this.currentAttributes);
189  } else if (Constants.ATTRIBUTES.equals(name)) {
190  this.attributesDelegate.startTag(name, atts, context, this.currentAttributes);
191  } else if (Constants.TRANSIT_SCHEDULE.equals(name)) {
192  this.currentAttributes = this.schedule.getAttributes();
193  }
194  }
195 
196  @Override
197  public void endTag(final String name, final String content, final Stack<String> context) {
198  if (Constants.DEPARTURE.equals(name)) {
199  this.currentDeparture = null;
200  }
201  if (Constants.DESCRIPTION.equals(name) && Constants.TRANSIT_ROUTE.equals(context.peek())) {
202  this.currentTransitRoute.description = content;
203  } else if (Constants.TRANSPORT_MODE.equals(name)) {
204  this.currentTransitRoute.mode = content.intern();
205  } else if (Constants.DEPARTURE.equals(name)) {
206  this.currentDeparture = null;
207  } else if (Constants.TRANSIT_ROUTE.equals(name)) {
208  List<TransitRouteStop> stops = new ArrayList<>(this.currentTransitRoute.stopBuilders.size());
209  this.currentTransitRoute.stopBuilders.forEach(stopBuilder -> stops.add(stopBuilder.build()));
210  NetworkRoute route = null;
211  if (this.currentRouteProfile.firstLinkId != null) {
212  if (this.currentRouteProfile.lastLinkId == null) {
213  this.currentRouteProfile.lastLinkId = this.currentRouteProfile.firstLinkId;
214  }
215  route = this.routeFactory.createRoute(NetworkRoute.class, this.currentRouteProfile.firstLinkId, this.currentRouteProfile.lastLinkId);
216  route.setLinkIds(this.currentRouteProfile.firstLinkId, this.currentRouteProfile.linkIds, this.currentRouteProfile.lastLinkId);
217  }
218  TransitRoute transitRoute = this.schedule.getFactory().createTransitRoute(this.currentTransitRoute.id, route, stops, this.currentTransitRoute.mode);
219  transitRoute.setDescription(this.currentTransitRoute.description);
220  for (Departure departure : this.currentTransitRoute.departures.values()) {
221  transitRoute.addDeparture(departure);
222  }
223  AttributesUtils.copyTo(this.currentTransitRoute.attributes, transitRoute.getAttributes());
224  this.currentTransitLine.addRoute(transitRoute);
225  this.currentTransitRoute = null;
226  } else if (Constants.TRANSIT_LINE.equals(name)) {
227  this.currentTransitLine = null;
228  } else if (Constants.ATTRIBUTE.equals(name)) {
229  this.attributesDelegate.endTag(name, content, context);
230  } else if (Constants.ATTRIBUTES.equals(name)) {
231  if (context.peek().equals(Constants.TRANSIT_SCHEDULE)) {
232  String inputCRS = (String) currentAttributes.getAttribute(ProjectionUtils.INPUT_CRS_ATT);
233 
234  if (inputCRS != null && targetCRS != null) {
235  if (externalInputCRS != null) {
236  // warn or crash?
237  log.warn("coordinate transformation defined both in config and in input file: setting from input file will be used");
238  }
239  coordinateTransformation = TransformationFactory.getCoordinateTransformation(inputCRS, targetCRS);
241  }
242  }
243  this.currentAttributes = null;
244  }
245  }
246 
247  private static class TempTransitRoute {
248  protected final Id<TransitRoute> id;
250  protected String description = null;
251  protected Map<Id<Departure>, Departure> departures = new LinkedHashMap<>();
252  /*package*/ List<TransitRouteStopImpl.Builder> stopBuilders = new ArrayList<>();
253  /*package*/ String mode = null;
254 
255  protected TempTransitRoute(final Id<TransitRoute> id) {
256  this.id = id;
257  }
258  }
259 
260  private static class TempRoute {
261  /*package*/ List<Id<Link>> linkIds = new ArrayList<>();
262  /*package*/ Id<Link> firstLinkId = null;
263  /*package*/ Id<Link> lastLinkId = null;
264 
265  protected TempRoute() {
266  // public constructor for private inner class
267  }
268 
269  protected void addLink(final Id<Link> linkId) {
270  if (this.firstLinkId == null) {
271  this.firstLinkId = linkId;
272  } else if (this.lastLinkId == null) {
273  this.lastLinkId = linkId;
274  } else {
275  this.linkIds.add(this.lastLinkId);
276  this.lastLinkId = linkId;
277  }
278  }
279 
280  }
281 
282  private static class StringCache {
283 
284  private ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>(10000);
285 
293  public String get(final String string) {
294  if (string == null) {
295  return null;
296  }
297  String s = this.cache.putIfAbsent(string, string);
298  if (s == null) {
299  return string;
300  }
301  return s;
302  }
303  }
304 
305 }
void ifDefined(DoubleConsumer action)
Map< Id< TransitStopFacility >, TransitStopFacility > getFacilities()
void setStopAreaId(Id< TransitStopArea > stopAreaId)
void addTransitLine(final TransitLine line)
TransitScheduleReaderV2(String externalInputCRS, String targetCRS, TransitSchedule schedule, RouteFactories routeFactory)
TransitScheduleReaderV2(final TransitSchedule schedule, final RouteFactories routeFactory)
static CoordinateTransformation getCoordinateTransformation(final String fromSystem, final String toSystem)
static< T extends MatsimToplevelContainer &Attributable > void putCRS(T container, String CRS)
static void copyTo(Attributes from, Attributes to)
void addRoute(final TransitRoute transitRoute)
void setDescription(final String description)
void startTag(final String name, final Attributes atts, final Stack< String > context)
static< T > Id< T > create(final long key, final Class< T > type)
Definition: Id.java:68
static final OptionalTime parseOptionalTime(final String time)
Definition: Time.java:167
void endTag(final String name, final String content, final Stack< String > context)
static final double parseTime(final String time)
Definition: Time.java:163
void setVehicleId(final Id< Vehicle > vehicleId)
void addDeparture(final Departure departure)
Object putAttribute(final String attribute, final Object value)
abstract TransitLine createTransitLine(final Id< TransitLine > lineId)
TransitScheduleReaderV2(final String externalInputCRS, final String targetCRS, final Scenario scenario)
final org.matsim.utils.objectattributes.attributable.Attributes attributes
double set(Id< TransitStopFacility > fromStop, Id< TransitStopFacility > toStop, double seconds)
abstract TransitStopFacility createTransitStopFacility(final Id< TransitStopFacility > facilityId, final Coord coordinate, final boolean blocksLane)
void addStopFacility(final TransitStopFacility stop)
TransitSchedule getTransitSchedule()
abstract TransitRoute createTransitRoute(final Id< TransitRoute > routeId, final NetworkRoute route, final List< TransitRouteStop > stops, final String mode)
void setLinkIds(final Id< Link > startLinkId, final List< Id< Link >> linkIds, final Id< Link > endLinkId)
org.matsim.utils.objectattributes.attributable.Attributes currentAttributes
void startTag(String name, org.xml.sax.Attributes atts, Stack< String > context, Attributes currentAttributes)