planner
This commit is contained in:
259
pkg/reader/csvreader.go
Normal file
259
pkg/reader/csvreader.go
Normal file
@@ -0,0 +1,259 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"git.tornberg.me/go-gtfs/pkg/types"
|
||||
)
|
||||
|
||||
func ParseAgencies(r io.Reader, callback func(types.Agency)) error {
|
||||
reader := csv.NewReader(r)
|
||||
// skip header
|
||||
if _, err := reader.Read(); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
agency := types.Agency{
|
||||
AgencyID: record[0],
|
||||
AgencyName: record[1],
|
||||
AgencyURL: record[2],
|
||||
AgencyTimezone: record[3],
|
||||
AgencyLang: record[4],
|
||||
}
|
||||
callback(agency)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseCalendars(r io.Reader, callback func(types.Calendar)) error {
|
||||
reader := csv.NewReader(r)
|
||||
if _, err := reader.Read(); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
monday, _ := strconv.Atoi(record[1])
|
||||
tuesday, _ := strconv.Atoi(record[2])
|
||||
wednesday, _ := strconv.Atoi(record[3])
|
||||
thursday, _ := strconv.Atoi(record[4])
|
||||
friday, _ := strconv.Atoi(record[5])
|
||||
saturday, _ := strconv.Atoi(record[6])
|
||||
sunday, _ := strconv.Atoi(record[7])
|
||||
calendar := types.Calendar{
|
||||
ServiceID: record[0],
|
||||
Monday: monday,
|
||||
Tuesday: tuesday,
|
||||
Wednesday: wednesday,
|
||||
Thursday: thursday,
|
||||
Friday: friday,
|
||||
Saturday: saturday,
|
||||
Sunday: sunday,
|
||||
StartDate: record[8],
|
||||
EndDate: record[9],
|
||||
}
|
||||
callback(calendar)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseCalendarDates(r io.Reader, callback func(types.CalendarDate)) error {
|
||||
reader := csv.NewReader(r)
|
||||
if _, err := reader.Read(); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
exceptionType, _ := strconv.Atoi(record[2])
|
||||
calendarDate := types.CalendarDate{
|
||||
ServiceID: record[0],
|
||||
Date: record[1],
|
||||
ExceptionType: exceptionType,
|
||||
}
|
||||
callback(calendarDate)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseFeedInfos(r io.Reader, callback func(types.FeedInfo)) error {
|
||||
reader := csv.NewReader(r)
|
||||
if _, err := reader.Read(); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
feedInfo := types.FeedInfo{
|
||||
FeedID: record[0],
|
||||
FeedPublisherName: record[1],
|
||||
FeedPublisherURL: record[2],
|
||||
FeedLang: record[3],
|
||||
FeedVersion: record[4],
|
||||
}
|
||||
callback(feedInfo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseRoutes(r io.Reader, callback func(types.Route)) error {
|
||||
reader := csv.NewReader(r)
|
||||
if _, err := reader.Read(); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
routeType, _ := strconv.Atoi(record[4])
|
||||
route := types.Route{
|
||||
RouteID: record[0],
|
||||
AgencyID: record[1],
|
||||
RouteShortName: record[2],
|
||||
RouteLongName: record[3],
|
||||
RouteType: routeType,
|
||||
RouteURL: record[5],
|
||||
}
|
||||
callback(route)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseStopTimes(r io.Reader, callback func(types.StopTime)) error {
|
||||
reader := csv.NewReader(r)
|
||||
if _, err := reader.Read(); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stopSequence, _ := strconv.Atoi(record[4])
|
||||
pickupType, _ := strconv.Atoi(record[5])
|
||||
dropOffType, _ := strconv.Atoi(record[6])
|
||||
stopTime := types.StopTime{
|
||||
TripID: record[0],
|
||||
ArrivalTime: record[1],
|
||||
DepartureTime: record[2],
|
||||
StopID: record[3],
|
||||
StopSequence: stopSequence,
|
||||
PickupType: pickupType,
|
||||
DropOffType: dropOffType,
|
||||
}
|
||||
callback(stopTime)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseStops(r io.Reader, callback func(types.Stop)) error {
|
||||
reader := csv.NewReader(r)
|
||||
if _, err := reader.Read(); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stopLat, _ := strconv.ParseFloat(record[2], 64)
|
||||
stopLon, _ := strconv.ParseFloat(record[3], 64)
|
||||
locationType, _ := strconv.Atoi(record[4])
|
||||
stop := types.Stop{
|
||||
StopID: record[0],
|
||||
StopName: record[1],
|
||||
StopLat: stopLat,
|
||||
StopLon: stopLon,
|
||||
LocationType: locationType,
|
||||
}
|
||||
callback(stop)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseTransfers(r io.Reader, callback func(types.Transfer)) error {
|
||||
reader := csv.NewReader(r)
|
||||
if _, err := reader.Read(); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
transferType, _ := strconv.Atoi(record[2])
|
||||
minTransferTime, _ := strconv.Atoi(record[3])
|
||||
transfer := types.Transfer{
|
||||
FromStopID: record[0],
|
||||
ToStopID: record[1],
|
||||
TransferType: transferType,
|
||||
MinTransferTime: minTransferTime,
|
||||
FromTripID: record[4],
|
||||
ToTripID: record[5],
|
||||
}
|
||||
callback(transfer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseTrips(r io.Reader, callback func(types.Trip)) error {
|
||||
reader := csv.NewReader(r)
|
||||
if _, err := reader.Read(); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
trip := types.Trip{
|
||||
RouteID: record[0],
|
||||
ServiceID: record[1],
|
||||
TripID: record[2],
|
||||
TripHeadsign: record[3],
|
||||
TripShortName: record[4],
|
||||
}
|
||||
callback(trip)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
17
pkg/types/agency.go
Normal file
17
pkg/types/agency.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package types
|
||||
|
||||
type Agency struct {
|
||||
AgencyID string `json:"agency_id" csv:"agency_id"`
|
||||
AgencyName string `json:"agency_name" csv:"agency_name"`
|
||||
AgencyURL string `json:"agency_url" csv:"agency_url"`
|
||||
AgencyTimezone string `json:"agency_timezone" csv:"agency_timezone"`
|
||||
AgencyLang string `json:"agency_lang" csv:"agency_lang"`
|
||||
Routes map[string]*Route
|
||||
}
|
||||
|
||||
func (a *Agency) AddRoute(route *Route) {
|
||||
if a.Routes == nil {
|
||||
a.Routes = make(map[string]*Route)
|
||||
}
|
||||
a.Routes[route.RouteID] = route
|
||||
}
|
||||
14
pkg/types/calendar.go
Normal file
14
pkg/types/calendar.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package types
|
||||
|
||||
type Calendar struct {
|
||||
ServiceID string `json:"service_id" csv:"service_id"`
|
||||
Monday int `json:"monday" csv:"monday"`
|
||||
Tuesday int `json:"tuesday" csv:"tuesday"`
|
||||
Wednesday int `json:"wednesday" csv:"wednesday"`
|
||||
Thursday int `json:"thursday" csv:"thursday"`
|
||||
Friday int `json:"friday" csv:"friday"`
|
||||
Saturday int `json:"saturday" csv:"saturday"`
|
||||
Sunday int `json:"sunday" csv:"sunday"`
|
||||
StartDate string `json:"start_date" csv:"start_date"`
|
||||
EndDate string `json:"end_date" csv:"end_date"`
|
||||
}
|
||||
7
pkg/types/calendardate.go
Normal file
7
pkg/types/calendardate.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package types
|
||||
|
||||
type CalendarDate struct {
|
||||
ServiceID string `json:"service_id" csv:"service_id"`
|
||||
Date string `json:"date" csv:"date"`
|
||||
ExceptionType int `json:"exception_type" csv:"exception_type"`
|
||||
}
|
||||
9
pkg/types/feedinfo.go
Normal file
9
pkg/types/feedinfo.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package types
|
||||
|
||||
type FeedInfo struct {
|
||||
FeedID string `json:"feed_id" csv:"feed_id"`
|
||||
FeedPublisherName string `json:"feed_publisher_name" csv:"feed_publisher_name"`
|
||||
FeedPublisherURL string `json:"feed_publisher_url" csv:"feed_publisher_url"`
|
||||
FeedLang string `json:"feed_lang" csv:"feed_lang"`
|
||||
FeedVersion string `json:"feed_version" csv:"feed_version"`
|
||||
}
|
||||
23
pkg/types/route.go
Normal file
23
pkg/types/route.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package types
|
||||
|
||||
type Route struct {
|
||||
Agency *Agency `json:"agency" csv:"agency"`
|
||||
Trips []*Trip `json:"trips" csv:"trips"`
|
||||
RouteID string `json:"route_id" csv:"route_id"`
|
||||
AgencyID string `json:"agency_id" csv:"agency_id"`
|
||||
RouteShortName string `json:"route_short_name" csv:"route_short_name"`
|
||||
RouteLongName string `json:"route_long_name" csv:"route_long_name"`
|
||||
RouteType int `json:"route_type" csv:"route_type"`
|
||||
RouteURL string `json:"route_url" csv:"route_url"`
|
||||
}
|
||||
|
||||
func (r *Route) SetAgency(agency *Agency) {
|
||||
r.Agency = agency
|
||||
}
|
||||
|
||||
func (r *Route) AddTrip(trip *Trip) {
|
||||
if r.Trips == nil {
|
||||
r.Trips = make([]*Trip, 0)
|
||||
}
|
||||
r.Trips = append(r.Trips, trip)
|
||||
}
|
||||
42
pkg/types/stop.go
Normal file
42
pkg/types/stop.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Stop struct {
|
||||
trips map[string]*Trip
|
||||
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:"transfers" csv:"transfers"`
|
||||
}
|
||||
|
||||
func (s *Stop) AddTransfer(transfer *Transfer) {
|
||||
if s.Transfers == nil {
|
||||
s.Transfers = make([]*Transfer, 0)
|
||||
}
|
||||
s.Transfers = append(s.Transfers, transfer)
|
||||
}
|
||||
|
||||
func (s *Stop) AddTrip(trip *Trip) {
|
||||
if s.trips == nil {
|
||||
s.trips = make(map[string]*Trip)
|
||||
}
|
||||
s.trips[trip.TripID] = trip
|
||||
}
|
||||
|
||||
func (s *Stop) GetTripsAfter(time time.Time) []*Trip {
|
||||
var trips []*Trip
|
||||
for _, trip := range s.trips {
|
||||
for _, stop := range trip.Stops {
|
||||
if stop.StopID == s.StopID && stop.DepartsAfter(time) {
|
||||
trips = append(trips, trip)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return trips
|
||||
}
|
||||
63
pkg/types/stoptime.go
Normal file
63
pkg/types/stoptime.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StopTime struct {
|
||||
departureTime int
|
||||
Stop *Stop `json:"stop"`
|
||||
TripID string `json:"trip_id" csv:"trip_id"`
|
||||
ArrivalTime string `json:"arrival_time" csv:"arrival_time"`
|
||||
DepartureTime string `json:"departure_time" csv:"departure_time"`
|
||||
StopID string `json:"stop_id" csv:"stop_id"`
|
||||
StopSequence int `json:"stop_sequence" csv:"stop_sequence"`
|
||||
PickupType int `json:"pickup_type" csv:"pickup_type"`
|
||||
DropOffType int `json:"drop_off_type" csv:"drop_off_type"`
|
||||
}
|
||||
|
||||
func parseTime(s string) int {
|
||||
parts := strings.Split(s, ":")
|
||||
if len(parts) != 3 {
|
||||
return 0
|
||||
}
|
||||
h, _ := strconv.Atoi(parts[0])
|
||||
m, _ := strconv.Atoi(parts[1])
|
||||
sec, _ := strconv.Atoi(parts[2])
|
||||
return h*3600 + m*60 + sec
|
||||
}
|
||||
|
||||
func (st *StopTime) DepartTimeAsSeconds() int {
|
||||
if st.departureTime > 0 {
|
||||
return st.departureTime
|
||||
}
|
||||
if st.DepartureTime == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
st.departureTime = parseTime(st.DepartureTime)
|
||||
return st.departureTime
|
||||
}
|
||||
|
||||
func (st *StopTime) DepartsAfter(when time.Time) bool {
|
||||
secondsAfterMidnight := st.DepartTimeAsSeconds()
|
||||
return secondsAfterMidnight >= when.Hour()*3600+when.Minute()*60+when.Second()
|
||||
}
|
||||
|
||||
// func (st *StopTime) GetPossibleTrips() iter.Seq[*Trip] {
|
||||
// return func(yield func(*Trip) bool) {
|
||||
// for _, trip := range st.Stop.trips {
|
||||
// if trip.TripID != st.TripID {
|
||||
// if !yield(trip) {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
func (st *StopTime) SetStop(stop *Stop) {
|
||||
st.Stop = stop
|
||||
}
|
||||
10
pkg/types/transfer.go
Normal file
10
pkg/types/transfer.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package types
|
||||
|
||||
type Transfer struct {
|
||||
FromStopID string `json:"from_stop_id" csv:"from_stop_id"`
|
||||
ToStopID string `json:"to_stop_id" csv:"to_stop_id"`
|
||||
TransferType int `json:"transfer_type" csv:"transfer_type"`
|
||||
MinTransferTime int `json:"min_transfer_time" csv:"min_transfer_time"`
|
||||
FromTripID string `json:"from_trip_id" csv:"from_trip_id"`
|
||||
ToTripID string `json:"to_trip_id" csv:"to_trip_id"`
|
||||
}
|
||||
46
pkg/types/trip.go
Normal file
46
pkg/types/trip.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Trip struct {
|
||||
*Route
|
||||
Stops []*StopTime `json:"stops" csv:"stops"`
|
||||
RouteID string `json:"route_id" csv:"route_id"`
|
||||
ServiceID string `json:"service_id" csv:"service_id"`
|
||||
TripID string `json:"trip_id" csv:"trip_id"`
|
||||
TripHeadsign string `json:"trip_headsign" csv:"trip_headsign"`
|
||||
TripShortName string `json:"trip_short_name" csv:"trip_short_name"`
|
||||
}
|
||||
|
||||
func (t *Trip) GetDirectPossibleDestinations(stop *Stop, when time.Time) iter.Seq[*StopTime] {
|
||||
return func(yield func(*StopTime) bool) {
|
||||
started := false
|
||||
for _, st := range t.Stops {
|
||||
if !started {
|
||||
if st.StopID == stop.StopID && st.PickupType == 0 {
|
||||
started = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
if started && st.DropOffType == 0 && st.DepartsAfter(when) {
|
||||
if !yield(st) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Trip) SetRoute(route *Route) {
|
||||
t.Route = route
|
||||
}
|
||||
|
||||
func (t *Trip) AddStopTime(stopTime *StopTime) {
|
||||
if t.Stops == nil {
|
||||
t.Stops = make([]*StopTime, 0)
|
||||
}
|
||||
t.Stops = append(t.Stops, stopTime)
|
||||
}
|
||||
Reference in New Issue
Block a user