
org.opentripplanner.transit.model.site.Station Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otp Show documentation
Show all versions of otp Show documentation
The OpenTripPlanner multimodal journey planning system
package org.opentripplanner.transit.model.site;
import static org.opentripplanner.util.geometry.GeometryUtils.getGeometryFactory;
import com.fasterxml.jackson.annotation.JsonBackReference;
import java.time.ZoneId;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.locationtech.jts.algorithm.ConvexHull;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.Point;
import org.opentripplanner.transit.model.basic.I18NString;
import org.opentripplanner.transit.model.basic.WgsCoordinate;
import org.opentripplanner.transit.model.framework.AbstractTransitEntity;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.framework.LogInfo;
/**
* A grouping of stops in GTFS or the lowest level grouping in NeTEx. It can be a train station, a
* bus terminal, or a bus station (with a bus stop at each side of the road). Equivalent to GTFS
* stop location type 1 or NeTEx monomodal StopPlace.
*/
public class Station
extends AbstractTransitEntity
implements StopLocationsGroup, LogInfo {
public static final StopTransferPriority DEFAULT_PRIORITY = StopTransferPriority.ALLOWED;
private final I18NString name;
private final String code;
private final I18NString description;
private final WgsCoordinate coordinate;
private final StopTransferPriority priority;
private final I18NString url;
private final ZoneId timezone;
private final boolean transfersNotAllowed;
// We serialize this class to json only for snapshot tests, and this creates cyclical structures
@JsonBackReference
private final Set childStops = new HashSet<>();
private GeometryCollection geometry;
Station(StationBuilder builder) {
super(builder.getId());
// Required fields
this.name = Objects.requireNonNull(builder.getName());
this.coordinate = Objects.requireNonNull(builder.getCoordinate());
this.priority = Objects.requireNonNullElse(builder.getPriority(), DEFAULT_PRIORITY);
this.transfersNotAllowed = builder.isTransfersNotAllowed();
// Optional fields
this.code = builder.getCode();
this.description = builder.getDescription();
this.url = builder.getUrl();
this.timezone = builder.getTimezone();
// Initialize the geometry with an empty set of children
this.geometry = computeGeometry(coordinate, Set.of());
}
public static StationBuilder of(FeedScopedId id) {
return new StationBuilder(id);
}
void addChildStop(RegularStop stop) {
this.childStops.add(stop);
this.geometry = computeGeometry(coordinate, childStops);
}
public boolean includes(StopLocation stop) {
return childStops.contains(stop);
}
@Nonnull
public I18NString getName() {
return name;
}
@Nonnull
public Collection getChildStops() {
return childStops;
}
@Override
public double getLat() {
return coordinate.latitude();
}
@Override
public double getLon() {
return coordinate.longitude();
}
@Nonnull
public WgsCoordinate getCoordinate() {
return coordinate;
}
/** Public facing station code (short text or number) */
@Nullable
public String getCode() {
return code;
}
/** Additional information about the station (if needed) */
@Nullable
public I18NString getDescription() {
return description;
}
/**
* URL to a web page containing information about this particular station
*/
@Nullable
public I18NString getUrl() {
return url;
}
/**
* The generalized cost priority associated with the stop independently of trips, routes and/or
* other stops. This is supported in NeTEx, but not in GTFS. This should work by adding adjusting
* the cost for all board-/alight- events in the routing search.
*
* To not interfere with request parameters this must be implemented in a neutral way. This mean
* that the {@link StopTransferPriority#ALLOWED} (which is default) should a nett-effect of adding
* 0 - zero cost.
*/
@Nonnull
public StopTransferPriority getPriority() {
return priority;
}
@Nullable
public ZoneId getTimezone() {
return timezone;
}
/**
* If true do not allow any transfers to or from any stop within station
*/
public boolean isTransfersNotAllowed() {
return transfersNotAllowed;
}
/**
* A geometry collection that contains the center point and the convex hull of all the child
* stops.
*/
@Nonnull
public GeometryCollection getGeometry() {
return geometry;
}
@Override
@Nullable
public String logName() {
return name == null ? null : name.toString();
}
@Override
@Nonnull
public StationBuilder copy() {
return new StationBuilder(this);
}
@Override
public boolean sameAs(@Nonnull Station other) {
return (
getId().equals(other.getId()) &&
Objects.equals(name, other.name) &&
Objects.equals(code, other.code) &&
Objects.equals(description, other.description) &&
Objects.equals(coordinate, other.coordinate) &&
Objects.equals(priority, other.priority) &&
Objects.equals(url, other.url) &&
Objects.equals(timezone, other.timezone)
);
}
private static GeometryCollection computeGeometry(
WgsCoordinate coordinate,
Set childStops
) {
Point stationPoint = null;
var childGeometries = childStops
.stream()
.map(StopLocation::getGeometry)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (coordinate != null) {
stationPoint = getGeometryFactory().createPoint(coordinate.asJtsCoordinate());
childGeometries.add(stationPoint);
}
var geometryCollection = getGeometryFactory()
.createGeometryCollection(childGeometries.toArray(new Geometry[] {}));
var convexHull = new ConvexHull(geometryCollection).getConvexHull();
var geometries = stationPoint != null
? new Geometry[] { stationPoint, convexHull }
: new Geometry[] { convexHull };
return getGeometryFactory().createGeometryCollection(geometries);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy