some custom stuff
This commit is contained in:
217
cmd/planner/csa.go
Normal file
217
cmd/planner/csa.go
Normal file
@@ -0,0 +1,217 @@
|
||||
package main
|
||||
|
||||
// import (
|
||||
// "sort"
|
||||
// "time"
|
||||
|
||||
// "git.tornberg.me/go-gtfs/pkg/reader"
|
||||
// "git.tornberg.me/go-gtfs/pkg/types"
|
||||
// )
|
||||
|
||||
// // Connection represents a single leg of a trip between two stops.
|
||||
// type CSAConnection struct {
|
||||
// DepartureStopID string
|
||||
// ArrivalStopID string
|
||||
// DepartureTime types.SecondsAfterMidnight
|
||||
// ArrivalTime types.SecondsAfterMidnight
|
||||
// TripID string
|
||||
// }
|
||||
|
||||
// // CSAPlanner uses the Connection Scan Algorithm for routing.
|
||||
// type CSAPlanner struct {
|
||||
// *reader.TripData
|
||||
// connections []CSAConnection
|
||||
// }
|
||||
|
||||
// // NewCSAPlanner creates and preprocesses data for the Connection Scan Algorithm.
|
||||
// func NewCSAPlanner(data *reader.TripData) *CSAPlanner {
|
||||
// p := &CSAPlanner{
|
||||
// TripData: data,
|
||||
// }
|
||||
// p.preprocess()
|
||||
// return p
|
||||
// }
|
||||
|
||||
// // preprocess creates a sorted list of all connections.
|
||||
// func (p *CSAPlanner) preprocess() {
|
||||
// p.connections = make([]CSAConnection, 0)
|
||||
// for tripID, trip := range p.Trips {
|
||||
// sts := trip.Stops
|
||||
// sort.Slice(sts, func(i, j int) bool {
|
||||
// return sts[i].StopSequence < sts[j].StopSequence
|
||||
// })
|
||||
// for i := 0; i < len(sts)-1; i++ {
|
||||
// from := sts[i]
|
||||
// to := sts[i+1]
|
||||
// if from.DepartureTime < to.ArrivalTime {
|
||||
// p.connections = append(p.connections, CSAConnection{
|
||||
// DepartureStopID: from.StopId,
|
||||
// ArrivalStopID: to.StopId,
|
||||
// DepartureTime: from.DepartureTime,
|
||||
// ArrivalTime: to.ArrivalTime,
|
||||
// TripID: tripID,
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // Sort connections by departure time, which is crucial for the algorithm.
|
||||
// sort.Slice(p.connections, func(i, j int) bool {
|
||||
// return p.connections[i].DepartureTime < p.connections[j].DepartureTime
|
||||
// })
|
||||
// }
|
||||
|
||||
// // FindRoute finds the best route using the Connection Scan Algorithm.
|
||||
// func (p *CSAPlanner) FindRoute(startStopID, endStopID string, when time.Time) *Route {
|
||||
// earliestArrival := make(map[string]time.Time)
|
||||
// journeyPointers := make(map[string]CSAConnection) // To reconstruct the path
|
||||
|
||||
// startTime := types.AsSecondsAfterMidnight(when)
|
||||
// day := when.Truncate(24 * time.Hour)
|
||||
|
||||
// // Initialize earliest arrival times
|
||||
// for stopID := range p.Stops {
|
||||
// earliestArrival[stopID] = time.Time{} // Zero time represents infinity
|
||||
// }
|
||||
// earliestArrival[startStopID] = when
|
||||
|
||||
// // Find the starting point in the connections array
|
||||
// firstConnectionIdx := sort.Search(len(p.connections), func(i int) bool {
|
||||
// return p.connections[i].DepartureTime >= startTime
|
||||
// })
|
||||
|
||||
// // Scan through connections
|
||||
// for i := firstConnectionIdx; i < len(p.connections); i++ {
|
||||
// conn := p.connections[i]
|
||||
|
||||
// depStopArrival, reachable := earliestArrival[conn.DepartureStopID]
|
||||
// if !reachable || depStopArrival.IsZero() {
|
||||
// continue // Cannot reach the departure stop of this connection yet
|
||||
// }
|
||||
|
||||
// connDepartureTime := day.Add(time.Duration(conn.DepartureTime) * time.Second)
|
||||
// if connDepartureTime.Before(depStopArrival) {
|
||||
// connDepartureTime = connDepartureTime.Add(24 * time.Hour) // Next day
|
||||
// }
|
||||
|
||||
// if !depStopArrival.IsZero() && connDepartureTime.After(depStopArrival) {
|
||||
// // We can catch this connection
|
||||
// connArrivalTime := day.Add(time.Duration(conn.ArrivalTime) * time.Second)
|
||||
// if connArrivalTime.Before(connDepartureTime) {
|
||||
// connArrivalTime = connArrivalTime.Add(24 * time.Hour)
|
||||
// }
|
||||
|
||||
// // Check if this connection offers a better arrival time at the destination stop
|
||||
// currentBestArrival, hasArrival := earliestArrival[conn.ArrivalStopID]
|
||||
// if !hasArrival || currentBestArrival.IsZero() || connArrivalTime.Before(currentBestArrival) {
|
||||
// earliestArrival[conn.ArrivalStopID] = connArrivalTime
|
||||
// journeyPointers[conn.ArrivalStopID] = conn
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Reconstruct the path if the destination was reached
|
||||
// if _, ok := journeyPointers[endStopID]; !ok {
|
||||
// return nil // No path found
|
||||
// }
|
||||
|
||||
// return p.reconstructCSAPath(startStopID, endStopID, journeyPointers)
|
||||
// }
|
||||
|
||||
// // reconstructCSAPath builds the route from the journey pointers.
|
||||
// func (p *CSAPlanner) reconstructCSAPath(startStopID, endStopID string, pointers map[string]CSAConnection) *Route {
|
||||
// var path []CSAConnection
|
||||
// currentStopID := endStopID
|
||||
// for currentStopID != startStopID {
|
||||
// conn, ok := pointers[currentStopID]
|
||||
// if !ok {
|
||||
// break // Should not happen if a path was found
|
||||
// }
|
||||
// path = append([]CSAConnection{conn}, path...)
|
||||
// currentStopID = conn.DepartureStopID
|
||||
// }
|
||||
|
||||
// if len(path) == 0 {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// // Group connections into legs
|
||||
// var legs []Leg
|
||||
// if len(path) > 0 {
|
||||
// currentLeg := p.connectionToLeg(path[0])
|
||||
// for i := 1; i < len(path); i++ {
|
||||
// if path[i].TripID == currentLeg.TripID {
|
||||
// // Continue the current leg
|
||||
// currentLeg.To = path[i].ArrivalStopID
|
||||
// currentLeg.ToStop = p.GetStop(currentLeg.To)
|
||||
// currentLeg.Stops = append(currentLeg.Stops, currentLeg.To)
|
||||
// } else {
|
||||
// // New leg
|
||||
// legs = append(legs, *currentLeg)
|
||||
// currentLeg = p.connectionToLeg(path[i])
|
||||
// }
|
||||
// }
|
||||
// legs = append(legs, *currentLeg)
|
||||
// }
|
||||
|
||||
// return &Route{Legs: legs}
|
||||
// }
|
||||
|
||||
// func (p *CSAPlanner) connectionToLeg(conn CSAConnection) *Leg {
|
||||
// trip := p.GetTrip(conn.TripID)
|
||||
// route := p.GetRoute(trip.RouteId)
|
||||
// return &Leg{
|
||||
// TripID: conn.TripID,
|
||||
// From: conn.DepartureStopID,
|
||||
// To: conn.ArrivalStopID,
|
||||
// FromStop: p.GetStop(conn.DepartureStopID),
|
||||
// ToStop: p.GetStop(conn.ArrivalStopID),
|
||||
// Trip: trip,
|
||||
// Agency: p.GetAgency(route.AgencyID),
|
||||
// Route: route,
|
||||
// Stops: []string{conn.DepartureStopID, conn.ArrivalStopID},
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (p *CSAPlanner) GetRoute(routeId string) *types.Route {
|
||||
// if routeId == "" {
|
||||
// return nil
|
||||
// }
|
||||
// route, ok := p.Routes[routeId]
|
||||
// if !ok {
|
||||
// return nil
|
||||
// }
|
||||
// return route
|
||||
// }
|
||||
|
||||
// func (p *CSAPlanner) GetAgency(agencyId string) *types.Agency {
|
||||
// if agencyId == "" {
|
||||
// return nil
|
||||
// }
|
||||
// agency, ok := p.Agencies[agencyId]
|
||||
// if !ok {
|
||||
// return nil
|
||||
// }
|
||||
// return agency
|
||||
// }
|
||||
|
||||
// func (p *CSAPlanner) GetTrip(tripId string) *types.Trip {
|
||||
// if tripId == "" {
|
||||
// return nil
|
||||
// }
|
||||
// trip, ok := p.Trips[tripId]
|
||||
// if !ok {
|
||||
// return nil
|
||||
// }
|
||||
// return trip
|
||||
// }
|
||||
|
||||
// func (p *CSAPlanner) GetStop(stopID string) *types.Stop {
|
||||
// if stopID == "" {
|
||||
// return nil
|
||||
// }
|
||||
// stop, ok := p.Stops[stopID]
|
||||
// if !ok {
|
||||
// return nil
|
||||
// }
|
||||
// return stop
|
||||
// }
|
||||
Reference in New Issue
Block a user