Files
go-gtfs/pkg/types/stop.go
2025-11-15 17:53:50 +01:00

131 lines
3.3 KiB
Go

package types
import (
"iter"
"math"
"time"
)
type Stop struct {
Trips map[string]*Trip `json:"-" csv:"-"`
StopId string `json:"stop_id" csv:"stop_id"`
StopName string `json:"stop_name" csv:"stop_name"`
StopLat float64 `json:"stop_lat" csv:"stop_lat"`
StopLon float64 `json:"stop_lon" csv:"stop_lon"`
LocationType int `json:"location_type" csv:"location_type"`
Transfers []*Transfer `json:"-" csv:"transfers"`
}
func (s *Stop) AddTransfer(transfer *Transfer, toStop *Stop) {
transfer.ToStop = toStop
if s.Transfers == nil {
s.Transfers = make([]*Transfer, 0)
}
s.Transfers = append(s.Transfers, transfer)
}
func (s *Stop) AddTrip(trip *Trip) {
s.Trips[trip.TripId] = trip
}
type TripWithDepartureTime struct {
*Trip
DepartureTime SecondsAfterMidnight
}
func (s *Stop) GetTripsAfter(when time.Time) iter.Seq[*TripWithDepartureTime] {
startAfterMidnight := AsSecondsAfterMidnight(when)
return func(yield func(*TripWithDepartureTime) bool) {
for _, trip := range s.Trips {
for _, stop := range trip.Stops {
if stop.StopId == s.StopId && stop.ArrivalTime >= startAfterMidnight && stop.PickupType == 0 {
if !yield(&TripWithDepartureTime{Trip: trip, DepartureTime: stop.DepartureTime}) {
return
}
break
}
}
}
}
}
func (s *Stop) HaversineDistance(other *Stop) float64 {
return haversine(s.StopLat, s.StopLon, other.StopLat, other.StopLon)
}
func haversine(lat1, lon1, lat2, lon2 float64) float64 {
const R = 6371 // Earth radius in km
dLat := (lat2 - lat1) * math.Pi / 180
dLon := (lon2 - lon1) * math.Pi / 180
a := math.Sin(dLat/2)*math.Sin(dLat/2) + math.Cos(lat1*math.Pi/180)*math.Cos(lat2*math.Pi/180)*math.Sin(dLon/2)*math.Sin(dLon/2)
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
return R * c
}
func (s *Stop) GetUpcomingStops(start *StopTime) iter.Seq[*StopTime] {
return func(yield func(*StopTime) bool) {
found := false
for _, trip := range s.Trips {
for _, stop := range trip.Stops {
if !found {
if stop.StopId == start.StopId && stop.DepartureTime >= start.ArrivalTime {
found = true
}
} else {
if !yield(stop) {
return
}
}
}
}
}
}
func (s *Stop) GetStopsAfter(when time.Time) iter.Seq2[*StopTime, *StopTime] {
startAfterMidnight := AsSecondsAfterMidnight(when)
var first *StopTime
return func(yield func(start, stop *StopTime) bool) {
for _, trip := range s.Trips {
found := -1
var start *StopTime
for _, stop := range trip.Stops {
if stop.StopId == s.StopId && stop.ArrivalTime >= startAfterMidnight {
found = stop.StopSequence
start = stop
if first == nil || start.ArrivalTime < first.ArrivalTime {
first = start
}
}
if found != -1 && stop.StopSequence > found && stop.PickupType == 0 {
if !yield(start, stop) {
return
}
}
}
}
if first == nil {
return
}
for _, transfer := range s.Transfers {
if transfer.FromStopId == s.StopId {
if !yield(first, &StopTime{
Stop: transfer.ToStop,
TripId: "transfer",
ArrivalTime: startAfterMidnight + SecondsAfterMidnight(transfer.MinTransferTime),
DepartureTime: startAfterMidnight + SecondsAfterMidnight(transfer.MinTransferTime),
StopId: transfer.ToStopId,
}) {
return
}
}
}
}
}