-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Another strategy for NYS-226 station accessibility
- Loading branch information
1 parent
c94e5c7
commit a4aba37
Showing
3 changed files
with
385 additions
and
2 deletions.
There are no files selected for viewing
255 changes: 255 additions & 0 deletions
255
...usaway-gtfs-transformer/src/main/java/org/onebusaway/gtfs_transformer/csv/MTAStation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
/** | ||
* Copyright (C) 2023 Cambridge Systematics, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.onebusaway.gtfs_transformer.csv; | ||
|
||
import org.onebusaway.csv_entities.schema.annotations.CsvField; | ||
|
||
/** | ||
* Metadata about an MTA Station. | ||
* | ||
* See https://new.mta.info/developers/display-elevators-NYCT | ||
*/ | ||
public class MTAStation { | ||
|
||
public static final int ADA_NOT_ACCESSIBLE = 0; | ||
public static final int ADA_FULLY_ACCESSIBLE = 1; | ||
public static final int ADA_PARTIALLY_ACCESSIBLE = 2; | ||
|
||
private static final int MISSING_VALUE = -999; | ||
@CsvField(name = "Station ID") | ||
private int id; | ||
|
||
@CsvField(name = "Complex ID") | ||
private int complexId; | ||
|
||
@CsvField(name = "GTFS Stop ID") | ||
private String stopId; | ||
|
||
@CsvField(name = "Division") | ||
private String division; | ||
|
||
@CsvField(name = "Line") | ||
private String line; | ||
|
||
@CsvField(name = "Stop Name") | ||
private String stopName; | ||
|
||
@CsvField(name = "Borough") | ||
private String borough; | ||
|
||
@CsvField(name = "Daytime Routes") | ||
private String daytimeRoutes; | ||
|
||
@CsvField(name = "Structure") | ||
private String structure; | ||
|
||
@CsvField(name = "GTFS Latitude") | ||
private double lat; | ||
|
||
@CsvField(name = "GTFS Longitude") | ||
private double lon; | ||
|
||
@CsvField(name = "North Direction Label", optional = true) | ||
private String northDirection; | ||
|
||
@CsvField(name = "South Direction Label", optional = true) | ||
private String southDirection; | ||
|
||
/** | ||
* Look at the ADA column. | ||
* | ||
* 0 means it’s not accessible, | ||
* 1 means it is fully accessible, and | ||
* 2 means it is partially accessible. Partially accessible stations are usually accessible in one direction. | ||
*/ | ||
@CsvField(name = "ADA") | ||
private int ada; | ||
|
||
@CsvField(name = "ADA Direction Notes", optional = true) | ||
private String adaDirectionNotes; | ||
|
||
/** | ||
* If ADA_PARTIALLY_ACCESSIBLE and this is 1, this | ||
* station is accessible | ||
*/ | ||
@CsvField(name = "ADA NB", optional = true) | ||
private int adaNorthBound = MISSING_VALUE; | ||
|
||
/** | ||
* If ADA_PARTIALLY_ACCESSIBLE and this is 1, this | ||
* station is accessible | ||
*/ | ||
@CsvField(name = "ADA SB", optional = true) | ||
private int adaSouthBound = MISSING_VALUE; | ||
|
||
@CsvField(name = "Capital Outage NB", optional = true) | ||
private String capitalOutageNB; | ||
|
||
@CsvField(name = "Capital Outage SB", optional = true) | ||
private String capitalOutageSB; | ||
|
||
public int getId() { | ||
return id; | ||
} | ||
|
||
public void setId(int id) { | ||
this.id = id; | ||
} | ||
|
||
public int getComplexId() { | ||
return complexId; | ||
} | ||
|
||
public void setComplexId(int complexId) { | ||
this.complexId = complexId; | ||
} | ||
|
||
public String getStopId() { | ||
return stopId; | ||
} | ||
|
||
public void setStopId(String stopId) { | ||
this.stopId = stopId; | ||
} | ||
|
||
public String getDivision() { | ||
return division; | ||
} | ||
|
||
public void setDivision(String division) { | ||
this.division = division; | ||
} | ||
|
||
public String getLine() { | ||
return line; | ||
} | ||
|
||
public void setLine(String line) { | ||
this.line = line; | ||
} | ||
|
||
public String getStopName() { | ||
return stopName; | ||
} | ||
|
||
public void setStopName(String stopName) { | ||
this.stopName = stopName; | ||
} | ||
|
||
public String getBorough() { | ||
return borough; | ||
} | ||
|
||
public void setBorough(String borough) { | ||
this.borough = borough; | ||
} | ||
|
||
public String getDaytimeRoutes() { | ||
return daytimeRoutes; | ||
} | ||
|
||
public void setDaytimeRoutes(String daytimeRoutes) { | ||
this.daytimeRoutes = daytimeRoutes; | ||
} | ||
|
||
public String getStructure() { | ||
return structure; | ||
} | ||
|
||
public void setStructure(String structure) { | ||
this.structure = structure; | ||
} | ||
|
||
public double getLat() { | ||
return lat; | ||
} | ||
|
||
public void setLat(double lat) { | ||
this.lat = lat; | ||
} | ||
|
||
public double getLon() { | ||
return lon; | ||
} | ||
|
||
public void setLon(double lon) { | ||
this.lon = lon; | ||
} | ||
|
||
public String getNorthDirection() { | ||
return northDirection; | ||
} | ||
|
||
public void setNorthDirection(String northDirection) { | ||
this.northDirection = northDirection; | ||
} | ||
|
||
public String getSouthDirection() { | ||
return southDirection; | ||
} | ||
|
||
public void setSouthDirection(String southDirection) { | ||
this.southDirection = southDirection; | ||
} | ||
|
||
public int getAda() { | ||
return ada; | ||
} | ||
|
||
public void setAda(int ada) { | ||
this.ada = ada; | ||
} | ||
|
||
public String getAdaDirectionNotes() { | ||
return adaDirectionNotes; | ||
} | ||
|
||
public void setAdaDirectionNotes(String adaDirectionNotes) { | ||
this.adaDirectionNotes = adaDirectionNotes; | ||
} | ||
|
||
public int getAdaNorthBound() { | ||
return adaNorthBound; | ||
} | ||
|
||
public void setAdaNorthBound(int adaNorthBound) { | ||
this.adaNorthBound = adaNorthBound; | ||
} | ||
|
||
public int getAdaSouthBound() { | ||
return adaSouthBound; | ||
} | ||
|
||
public void setAdaSouthBound(int adaSouthBound) { | ||
this.adaSouthBound = adaSouthBound; | ||
} | ||
|
||
public String getCapitalOutageNB() { | ||
return capitalOutageNB; | ||
} | ||
|
||
public void setCapitalOutageNB(String capitalOutageNB) { | ||
this.capitalOutageNB = capitalOutageNB; | ||
} | ||
|
||
public String getCapitalOutageSB() { | ||
return capitalOutageSB; | ||
} | ||
|
||
public void setCapitalOutageSB(String capitalOutageSB) { | ||
this.capitalOutageSB = capitalOutageSB; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
...r/src/main/java/org/onebusaway/gtfs_transformer/impl/MTAStationAccessibilityStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/** | ||
* Copyright (C) 2023 Cambridge Systematics, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.onebusaway.gtfs_transformer.impl; | ||
|
||
import org.onebusaway.cloud.api.ExternalServices; | ||
import org.onebusaway.cloud.api.ExternalServicesBridgeFactory; | ||
import org.onebusaway.csv_entities.schema.annotations.CsvField; | ||
import org.onebusaway.gtfs.model.FeedInfo; | ||
import org.onebusaway.gtfs.model.Stop; | ||
import org.onebusaway.gtfs.services.GtfsMutableRelationalDao; | ||
import org.onebusaway.gtfs_transformer.csv.MTAStation; | ||
import org.onebusaway.gtfs_transformer.services.GtfsTransformStrategy; | ||
import org.onebusaway.gtfs_transformer.services.TransformContext; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.File; | ||
import java.util.*; | ||
|
||
import static org.onebusaway.gtfs_transformer.csv.CSVUtil.readCsv; | ||
import static org.onebusaway.gtfs_transformer.impl.MTAEntrancesStrategy.WHEELCHAIR_ACCESSIBLE; | ||
|
||
/** | ||
* Based on a CSV of MTAStations set the associated stops accessible as specified. | ||
*/ | ||
public class MTAStationAccessibilityStrategy implements GtfsTransformStrategy { | ||
|
||
private static final Logger _log = LoggerFactory.getLogger(MTAStationAccessibilityStrategy.class); | ||
private String stationsCsv; | ||
|
||
@CsvField(ignore = true) | ||
private Set<Stop> accessibleStops = new HashSet<>(); | ||
|
||
@CsvField(ignore = true) | ||
private Map<String, Stop> idToStopMap = new HashMap<>(); | ||
|
||
@Override | ||
public String getName() { | ||
return this.getClass().getName(); | ||
} | ||
|
||
@Override | ||
public void run(TransformContext context, GtfsMutableRelationalDao dao) { | ||
|
||
ExternalServices es = new ExternalServicesBridgeFactory().getExternalServices(); | ||
Collection<FeedInfo> feedInfos = dao.getAllFeedInfos(); | ||
|
||
// name the feed for logging/reference | ||
String feed = null; | ||
if(feedInfos.size() > 0) | ||
feed = feedInfos.iterator().next().getPublisherName(); | ||
|
||
// stops are unqualified, build up a map of them for lookups | ||
for (Stop stop : dao.getAllStops()) { | ||
idToStopMap.put(stop.getId().getId(), stop); | ||
} | ||
|
||
File stationsFile = new File(stationsCsv); | ||
if (!stationsFile.exists()) { | ||
es.publishMultiDimensionalMetric(getNamespace(), "MissingControlFiles", | ||
new String[]{"feed", "controlFileName"}, | ||
new String[]{feed, stationsCsv}, 1); | ||
throw new IllegalStateException( | ||
"Entrances file does not exist: " + stationsFile.getName()); | ||
} | ||
|
||
// we have a file, load the contents | ||
List<MTAStation> stations = getStations(); | ||
for (MTAStation station : stations) { | ||
if (station.getAda() == MTAStation.ADA_FULLY_ACCESSIBLE) { | ||
markStopAccessible(dao, station.getStopId(), "N"); | ||
markStopAccessible(dao, station.getStopId(), "S"); | ||
} else if (station.getAda() == MTAStation.ADA_PARTIALLY_ACCESSIBLE) { | ||
if (station.getAdaNorthBound() == WHEELCHAIR_ACCESSIBLE) { | ||
markStopAccessible(dao, station.getStopId(), "N"); | ||
} | ||
if (station.getAdaSouthBound() == WHEELCHAIR_ACCESSIBLE) { | ||
markStopAccessible(dao, station.getStopId(), "S"); | ||
} | ||
} | ||
} | ||
|
||
_log.info("marking {} stops as accessible", accessibleStops.size()); | ||
for (Stop accessibleStop : this.accessibleStops) { | ||
// save the changes | ||
dao.updateEntity(accessibleStop); | ||
} | ||
|
||
} | ||
|
||
private void markStopAccessible(GtfsMutableRelationalDao dao, String stopId, String compassDirection) { | ||
String unqualifedStopId = stopId + compassDirection; | ||
Stop stopForId = idToStopMap.get(unqualifedStopId); | ||
if (stopForId == null) { | ||
_log.error("no such stop for stopId {}", unqualifedStopId); | ||
return; | ||
} | ||
stopForId.setWheelchairBoarding(WHEELCHAIR_ACCESSIBLE); | ||
this.accessibleStops.add(stopForId); | ||
} | ||
|
||
|
||
private List<MTAStation> getStations() { | ||
return readCsv(MTAStation.class, stationsCsv); | ||
} | ||
|
||
public void setStationsCsv(String stationsCsv) { | ||
this.stationsCsv = stationsCsv; | ||
} | ||
|
||
private String getNamespace(){ | ||
return System.getProperty("cloudwatch.namespace"); | ||
} | ||
|
||
} |