Skip to content

Commit

Permalink
Another strategy for NYS-226 station accessibility
Browse files Browse the repository at this point in the history
  • Loading branch information
sheldonabrown committed Sep 20, 2023
1 parent c94e5c7 commit a4aba37
Show file tree
Hide file tree
Showing 3 changed files with 385 additions and 2 deletions.
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ public class MTAEntrancesStrategy implements GtfsTransformStrategy {
private static final int LOCATION_TYPE_PAYGATE = 3;
private static final int LOCATION_TYPE_GENERIC = 4;

private static final int WHEELCHAIR_ACCESSIBLE = 1;
private static final int NOT_WHEELCHAIR_ACCESSIBLE = 2;
static final int WHEELCHAIR_ACCESSIBLE = 1;
static final int NOT_WHEELCHAIR_ACCESSIBLE = 2;

private static final String DEFAULT_MEZZ = "default";

Expand Down
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");
}

}

0 comments on commit a4aba37

Please sign in to comment.