/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
* Copyright (C) 2011 Google, 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.transit_data_federation.services.realtime;
import org.onebusaway.geospatial.model.CoordinatePoint;
import org.onebusaway.gtfs.model.AgencyAndId;
import org.onebusaway.realtime.api.EVehiclePhase;
import org.onebusaway.transit_data_federation.services.blocks.BlockInstance;
import org.onebusaway.transit_data_federation.services.blocks.BlockTripInstance;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockStopTimeEntry;
import org.onebusaway.transit_data_federation.services.transit_graph.BlockTripEntry;
/**
* Vehicle position information for a particular block.
*
* @author bdferris
*/
public class BlockLocation {
/**
* The time for which the block location was generated
*/
private long time;
/****
* These are fields that we can supply from schedule data
****/
private BlockInstance blockInstance;
private BlockTripEntry activeTrip;
private boolean inService;
private double scheduledDistanceAlongBlock = Double.NaN;
/****
* These are fields that we can supply from schedule data, but also update
* from real-time data when available
****/
private double distanceAlongBlock = Double.NaN;
/**
* Time, in seconds
*/
private int effectiveScheduleTime;
private CoordinatePoint location;
private double orientation = Double.NaN;
private BlockStopTimeEntry closestStop;
private int closestStopTimeOffset;
private BlockStopTimeEntry nextStop;
private int nextStopTimeOffset;
private BlockStopTimeEntry previousStop;
private int previousStopTimeOffset;
private EVehiclePhase phase;
private String status;
/****
* These are fields that we can supply only from real-time data
****/
private boolean predicted;
private long lastUpdateTime;
private long lastLocationUpdateTime;
private double lastKnownDistanceAlongBlock = Double.NaN;
private CoordinatePoint lastKnownLocation;
private double lastKnownOrientation = Double.NaN;
private double scheduleDeviation = Double.NaN;
private ScheduleDeviationSamples scheduleDeviations = null;
private AgencyAndId vehicleId;
public BlockLocation() {
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public BlockInstance getBlockInstance() {
return blockInstance;
}
public void setBlockInstance(BlockInstance instance) {
this.blockInstance = instance;
}
/**
* @return the active trip for the block
*/
public BlockTripEntry getActiveTrip() {
return activeTrip;
}
public void setActiveTrip(BlockTripEntry activeTrip) {
this.activeTrip = activeTrip;
}
/**
*
* @return the active trip instance for the block location
*/
public BlockTripInstance getActiveTripInstance() {
if (activeTrip == null)
return null;
return new BlockTripInstance(activeTrip, blockInstance.getState());
}
/**
* @return true if the block trip is actively in service
*/
public boolean isInService() {
return inService;
}
public void setInService(boolean inService) {
this.inService = inService;
}
public boolean isScheduledDistanceAlongBlockSet() {
return !Double.isNaN(scheduledDistanceAlongBlock);
}
/**
* If the trip is not in service (see {@link #isInService()}), this value will
* be {@link Double#NaN}.
*
* @return the scheduled distance traveled along the shape of the block, in
* meters
*/
public double getScheduledDistanceAlongBlock() {
return scheduledDistanceAlongBlock;
}
public void setScheduledDistanceAlongBlock(double scheduledDistanceAlongBlock) {
this.scheduledDistanceAlongBlock = scheduledDistanceAlongBlock;
}
/**
* The effective schedule time measures the progress of the transit vehicle in
* serving the underlying schedule.
*
* effectiveScheduleTime = currentTime - scheduleDeviation
*
* @return time, in seconds
*/
public int getEffectiveScheduleTime() {
return effectiveScheduleTime;
}
public void setEffectiveScheduleTime(int effectiveScheduleTime) {
this.effectiveScheduleTime = effectiveScheduleTime;
}
/**
* If the trip is non in service (see {@link #isInService()}, this value with
* be false.
*
* @return
*/
public boolean isDistanceAlongBlockSet() {
return !Double.isNaN(distanceAlongBlock);
}
/**
* If the trip is not in service (see {@link #isInService()}), this value will
* be {@link Double#NaN}. See {@link #isDistanceAlongBlockSet()}.
*
* @return the distance traveled along the shape of the block, in meters
*/
public double getDistanceAlongBlock() {
return distanceAlongBlock;
}
public void setDistanceAlongBlock(double distanceAlongBlock) {
this.distanceAlongBlock = distanceAlongBlock;
}
/**
* @return the block position
*/
public CoordinatePoint getLocation() {
return location;
}
public void setLocation(CoordinatePoint location) {
this.location = location;
}
public boolean isOrientationSet() {
return !Double.isNaN(orientation);
}
/**
* In degrees, 0º is East, 90º is North, 180º is West, and 270º is South
*/
public double getOrientation() {
return orientation;
}
public void setOrientation(double orientation) {
this.orientation = orientation;
}
/**
* The closest stop to the current position of the transit vehicle among the
* stop times of the current trip.
*
* @return the closest stop time entry
*/
public BlockStopTimeEntry getClosestStop() {
return closestStop;
}
public void setClosestStop(BlockStopTimeEntry closestStop) {
this.closestStop = closestStop;
}
/**
* The time offset, in seconds, from the closest stop to the current position
* of the transit vehicle among the stop times of the current trip. If the
* number is positive, the stop is coming up. If negative, the stop has
* already been passed.
*
* @return time, in seconds
*/
public int getClosestStopTimeOffset() {
return closestStopTimeOffset;
}
/**
* See description in {@link #getClosestStopTimeOffset()}.
*
* @param closestStopTimeOffset the time offset from the closest stop, in
* seconds
*/
public void setClosestStopTimeOffset(int closestStopTimeOffset) {
this.closestStopTimeOffset = closestStopTimeOffset;
}
/**
* The next upcoming stop to the current position of the transit vehicle among
* the stop times of the current trip.
*
* @return the next stop time entry
*/
public BlockStopTimeEntry getNextStop() {
return nextStop;
}
public void setNextStop(BlockStopTimeEntry nextStop) {
this.nextStop = nextStop;
}
/**
* The time offset, in seconds, from the next stop to the current position of
* the transit vehicle.
*
* @return time, in seconds
*/
public int getNextStopTimeOffset() {
return nextStopTimeOffset;
}
/**
* See {@link #getNextStopTimeOffset()}
*
* @param nextStopTimeOffset
*/
public void setNextStopTimeOffset(int nextStopTimeOffset) {
this.nextStopTimeOffset = nextStopTimeOffset;
}
public BlockStopTimeEntry getPreviousStop() {
return previousStop;
}
public void setPreviousStop(BlockStopTimeEntry previousStop) {
this.previousStop = previousStop;
}
public int getPreviousStopTimeOffset() {
return previousStopTimeOffset;
}
public void setPreviousStopTimeOffset(int previousStopTimeOffset) {
this.previousStopTimeOffset = previousStopTimeOffset;
}
public EVehiclePhase getPhase() {
return phase;
}
public void setPhase(EVehiclePhase phase) {
this.phase = phase;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
/**
* If real-time data is available in any form (schedule deviation,
* distanceAlongBlock, last known location) for this vehicle
*
* @return true if real-time is available
*/
public boolean isPredicted() {
return predicted;
}
public void setPredicted(boolean predicted) {
this.predicted = predicted;
}
/**
* @return the time we last heard from the bus (Unix-time)
*/
public long getLastUpdateTime() {
return lastUpdateTime;
}
public void setLastUpdateTime(long lastUpdateTime) {
this.lastUpdateTime = lastUpdateTime;
}
/**
* @return the time we last heard a location update from the bus (Unix-time)
*/
public long getLastLocationUpdateTime() {
return lastLocationUpdateTime;
}
public void setLastLocationUpdateTime(long lastLocationUpdateTime) {
this.lastLocationUpdateTime = lastLocationUpdateTime;
}
public boolean isLastKnownDistanceAlongBlockSet() {
return !Double.isNaN(lastKnownDistanceAlongBlock);
}
public double getLastKnownDistanceAlongBlock() {
return lastKnownDistanceAlongBlock;
}
public void setLastKnownDistanceAlongBlock(double lastKnownDistanceAlongBlock) {
this.lastKnownDistanceAlongBlock = lastKnownDistanceAlongBlock;
}
public CoordinatePoint getLastKnownLocation() {
return lastKnownLocation;
}
public void setLastKnownLocation(CoordinatePoint lastKnownLocation) {
this.lastKnownLocation = lastKnownLocation;
}
public boolean isLastKnownOrientationSet() {
return !Double.isNaN(lastKnownOrientation);
}
/**
* In degrees, 0º is East, 90º is North, 180º is West, and 270º is South
*/
public double getLastKnownOrientation() {
return lastKnownOrientation;
}
public void setLastKnownOrientation(double lastKnownOrientation) {
this.lastKnownOrientation = lastKnownOrientation;
}
/**
* @return true if we have schedule deviation data
*/
public boolean isScheduleDeviationSet() {
return !Double.isNaN(scheduleDeviation);
}
/**
* If no schedule deviation data is available, this value with be
* {@link Double#NaN}.
*
* @return schedule deviation, in seconds, (+deviation is late, -deviation is
* early)
*/
public double getScheduleDeviation() {
return scheduleDeviation;
}
/**
*
* @param scheduleDeviation schedule deviation, in seconds, (+deviation is
* late, -deviation is early)
*/
public void setScheduleDeviation(double scheduleDeviation) {
this.scheduleDeviation = scheduleDeviation;
}
public boolean areScheduleDeviationsSet() {
return scheduleDeviations != null && !scheduleDeviations.isEmpty();
}
public ScheduleDeviationSamples getScheduleDeviations() {
return scheduleDeviations;
}
public void setScheduleDeviations(ScheduleDeviationSamples scheduleDeviations) {
this.scheduleDeviations = scheduleDeviations;
}
public AgencyAndId getVehicleId() {
return vehicleId;
}
public void setVehicleId(AgencyAndId vehicleId) {
this.vehicleId = vehicleId;
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("BlockLocation(");
b.append("block=").append(blockInstance.getBlock().getBlock().getId()).append(
",");
if (phase != null)
b.append("phase=").append(phase).append(",");
if (status != null)
b.append("status=").append(status).append(",");
if (isScheduleDeviationSet())
b.append("scheduleDeviation=").append(scheduleDeviation).append(",");
if (predicted)
b.append("predicted=true,");
if (isDistanceAlongBlockSet())
b.append("distanceAlongBlock=").append(distanceAlongBlock).append(",");
if (vehicleId != null)
b.append("vehicleId=").append(vehicleId).append(",");
b.append(")");
return b.toString();
}
}