temp
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"slices"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.tornberg.me/go-gtfs/pkg/reader"
|
||||
@@ -41,41 +40,41 @@ const (
|
||||
func NewTripPlanner(data *reader.TripData) *TripPlanner {
|
||||
return &TripPlanner{
|
||||
TripData: data,
|
||||
graph: make(map[string][]Edge),
|
||||
//graph: make(map[string][]Edge),
|
||||
}
|
||||
}
|
||||
|
||||
// Preprocess builds the routing graph and precomputes routes
|
||||
func (tp *TripPlanner) Preprocess() error {
|
||||
|
||||
if hosjo, ok := tp.Stops["740025287"]; ok {
|
||||
trips := hosjo.GetTripsAfter(time.Now())
|
||||
for trip := range trips {
|
||||
log.Printf("Trip %s (%s):", trip.TripShortName, trip.TripHeadsign)
|
||||
for stop := range trip.GetDirectPossibleDestinations(hosjo, time.Now()) {
|
||||
log.Printf("- Stop %s at %s", stop.Stop.StopName, types.AsTime(stop.DepartureTime))
|
||||
}
|
||||
}
|
||||
// if hosjo, ok := tp.Stops["740025287"]; ok {
|
||||
// trips := hosjo.GetTripsAfter(time.Now())
|
||||
// for trip := range trips {
|
||||
// log.Printf("Trip %s (%s):", trip.TripShortName, trip.TripHeadsign)
|
||||
// for stop := range trip.GetDirectPossibleDestinations(hosjo, time.Now()) {
|
||||
// log.Printf("- Stop %s at %s", stop.Stop.StopName, types.AsTime(stop.DepartureTime))
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
// Build graph with trip edges
|
||||
for tripID, trip := range tp.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].StopId
|
||||
to := sts[i+1].StopId
|
||||
departure := sts[i].DepartureTime
|
||||
arrival := sts[i+1].DepartureTime
|
||||
timeDiff := arrival - departure
|
||||
if timeDiff > 0 {
|
||||
tp.graph[from] = append(tp.graph[from], Edge{To: to, TripID: tripID, Time: timeDiff, DepartureTime: departure})
|
||||
}
|
||||
}
|
||||
}
|
||||
// // Build graph with trip edges
|
||||
// for tripID, trip := range tp.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].StopId
|
||||
// to := sts[i+1].StopId
|
||||
// departure := sts[i].DepartureTime
|
||||
// arrival := sts[i+1].DepartureTime
|
||||
// timeDiff := arrival - departure
|
||||
// if timeDiff > 0 {
|
||||
// tp.graph[from] = append(tp.graph[from], Edge{To: to, TripID: tripID, Time: timeDiff, DepartureTime: departure})
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Add transfer edges
|
||||
// for _, tr := range tp.transfers {
|
||||
@@ -100,8 +99,8 @@ type History struct {
|
||||
TravelTime types.SecondsAfterMidnight
|
||||
}
|
||||
|
||||
func NewHistory(st *types.StopTime, distanceToEnd float64, travelTime types.SecondsAfterMidnight) *History {
|
||||
return &History{
|
||||
func NewHistory(st *types.StopTime, distanceToEnd float64, travelTime types.SecondsAfterMidnight) History {
|
||||
return History{
|
||||
StopTime: st,
|
||||
DistanceToEnd: distanceToEnd,
|
||||
TravelTime: travelTime,
|
||||
@@ -109,7 +108,7 @@ func NewHistory(st *types.StopTime, distanceToEnd float64, travelTime types.Seco
|
||||
}
|
||||
|
||||
// FindRoutes finds the best routes (up to num) between two stops starting at the given time
|
||||
func (tp *TripPlanner) FindRoute(from, to string, when time.Time) (*Route, error) {
|
||||
func (tp *TripPlanner) FindRoute(from, to string, when time.Time) ([]*Route, error) {
|
||||
|
||||
fromStop := tp.GetStop(from)
|
||||
toStop := tp.GetStop(to)
|
||||
@@ -117,28 +116,61 @@ func (tp *TripPlanner) FindRoute(from, to string, when time.Time) (*Route, error
|
||||
if fromStop == nil || toStop == nil {
|
||||
return nil, fmt.Errorf("invalid from or to stop")
|
||||
}
|
||||
routes := make([]*Route, 0)
|
||||
usedRouteIds := make(map[string]struct{})
|
||||
|
||||
for trip := range fromStop.GetTripsAfter(when) {
|
||||
if _, used := usedRouteIds[trip.RouteId]; used {
|
||||
continue
|
||||
}
|
||||
for i := len(trip.Stops) - 1; i >= 0; i-- {
|
||||
stop := trip.Stops[i]
|
||||
if stop.StopId == toStop.StopId {
|
||||
usedRouteIds[trip.RouteId] = struct{}{}
|
||||
routes = append(routes, &Route{
|
||||
Legs: []Leg{NewLeg(trip.Stops[0], trip.Stops[i])},
|
||||
})
|
||||
break
|
||||
} else if stop.StopId == fromStop.StopId {
|
||||
break
|
||||
} else if stop.PickupType == 0 {
|
||||
distance := stop.Stop.HaversineDistance(toStop)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
possibleNextStops := make([]*types.StopTime, 0)
|
||||
var startTime *types.StopTime
|
||||
for start, stop := range fromStop.GetStopsAfter(when) {
|
||||
if stop.StopId == toStop.StopId {
|
||||
return &Route{
|
||||
routes = append(routes, &Route{
|
||||
Legs: []Leg{NewLeg(start, stop)},
|
||||
}, nil
|
||||
})
|
||||
} else if from != stop.StopId {
|
||||
startTime = start
|
||||
possibleNextStops = append(possibleNextStops, stop)
|
||||
}
|
||||
}
|
||||
slices.SortFunc(possibleNextStops, byDistanceTo(*toStop))
|
||||
for _, nextStop := range possibleNextStops {
|
||||
route, err := tp.findRoute(*nextStop, toStop, *NewHistory(startTime, startTime.Stop.HaversineDistance(toStop), types.AsSecondsAfterMidnight(when)), *NewHistory(nextStop, nextStop.Stop.HaversineDistance(toStop), nextStop.ArrivalTime-startTime.ArrivalTime))
|
||||
if err == nil && route != nil {
|
||||
return route, nil
|
||||
}
|
||||
}
|
||||
// startTime = start
|
||||
route, err := tp.findRoute(*start, toStop, NewHistory(start, start.Stop.HaversineDistance(toStop), 0), NewHistory(stop, stop.Stop.HaversineDistance(toStop), stop.ArrivalTime-start.DepartureTime))
|
||||
|
||||
return nil, fmt.Errorf("no route found")
|
||||
if err == nil && route != nil {
|
||||
routes = append(routes, route)
|
||||
}
|
||||
}
|
||||
}
|
||||
// slices.SortFunc(possibleNextStops, byDistanceTo(*toStop))
|
||||
// for _, nextStop := range possibleNextStops {
|
||||
// route, err := tp.findRoute(*nextStop, toStop, *NewHistory(startTime, startTime.Stop.HaversineDistance(toStop), types.AsSecondsAfterMidnight(when)), *NewHistory(nextStop, nextStop.Stop.HaversineDistance(toStop), nextStop.ArrivalTime-startTime.ArrivalTime))
|
||||
// if err == nil && route != nil {
|
||||
// return route, nil
|
||||
// }
|
||||
// }
|
||||
slices.SortFunc(routes, func(a, b *Route) int {
|
||||
transfersA := len(a.Legs) - 1
|
||||
transfersB := len(b.Legs) - 1
|
||||
if transfersA != transfersB {
|
||||
return transfersA - transfersB
|
||||
}
|
||||
return a.Duration() - b.Duration() - (transfersA-transfersB)*int(transferPenalty.Seconds())
|
||||
})
|
||||
return routes[:min(len(routes), 10)], nil
|
||||
}
|
||||
|
||||
func byDistanceTo(end types.Stop) func(a, b *types.StopTime) int {
|
||||
@@ -149,10 +181,38 @@ func byDistanceTo(end types.Stop) func(a, b *types.StopTime) int {
|
||||
}
|
||||
}
|
||||
|
||||
func isInCorrectDirection(from, possible, end *types.Stop) bool {
|
||||
if from.StopId == end.StopId || possible.StopId == end.StopId {
|
||||
return true
|
||||
}
|
||||
if from.StopId == possible.StopId {
|
||||
return false
|
||||
}
|
||||
startToEndLat := end.StopLat - from.StopLat
|
||||
startToEndLon := end.StopLon - from.StopLon
|
||||
startToPossibleLat := possible.StopLat - from.StopLat
|
||||
startToPossibleLon := possible.StopLon - from.StopLon
|
||||
dotProduct := startToEndLat*startToPossibleLat + startToEndLon*startToPossibleLon
|
||||
return dotProduct > -0.4 && dotProduct < 0.4
|
||||
}
|
||||
|
||||
func shouldTryStop(end *types.Stop, visited ...History) func(possible *types.StopTime) bool {
|
||||
lastDistance := visited[len(visited)-1].Stop.HaversineDistance(end)
|
||||
return func(possible *types.StopTime) bool {
|
||||
if end.StopId == possible.StopId {
|
||||
return true
|
||||
}
|
||||
if possible.DepartureTime > visited[len(visited)-1].DepartureTime+types.SecondsAfterMidnight(maxWaitBetweenTrips.Seconds()) {
|
||||
return false
|
||||
}
|
||||
if possible.DropOffType == 1 {
|
||||
return false
|
||||
}
|
||||
// if !isInCorrectDirection(visited[len(visited)-1].Stop, possible.Stop, end) {
|
||||
// return false
|
||||
// }
|
||||
distance := possible.Stop.HaversineDistance(end)
|
||||
|
||||
for _, v := range visited {
|
||||
if v.DistanceToEnd <= distance*1.2 {
|
||||
return false
|
||||
@@ -187,7 +247,7 @@ func (tp *TripPlanner) findRoute(start types.StopTime, end *types.Stop, changes
|
||||
|
||||
tries := 15
|
||||
for _, nextStop := range possibleNextStops {
|
||||
route, err := tp.findRoute(*nextStop, end, append(changes, *NewHistory(nextStop, nextStop.Stop.HaversineDistance(end), nextStop.ArrivalTime-start.ArrivalTime))...)
|
||||
route, err := tp.findRoute(*nextStop, end, append(changes, NewHistory(nextStop, nextStop.Stop.HaversineDistance(end), nextStop.ArrivalTime-start.ArrivalTime))...)
|
||||
if err == nil && route != nil {
|
||||
return route, nil
|
||||
}
|
||||
@@ -213,9 +273,24 @@ func CreateLegs(stops []History, finalStop *types.StopTime) []Leg {
|
||||
}
|
||||
|
||||
func NewLeg(fromStop, toStop *types.StopTime) Leg {
|
||||
trip, ok := toStop.Stop.Trips[toStop.TripId]
|
||||
if !ok {
|
||||
log.Printf("trip %s not found for stop %s", toStop.TripId, toStop.Stop.StopName)
|
||||
return Leg{
|
||||
From: fromStop,
|
||||
To: toStop,
|
||||
}
|
||||
}
|
||||
return Leg{
|
||||
From: fromStop,
|
||||
To: toStop,
|
||||
Trip: &JSONTrip{
|
||||
TripId: trip.TripId,
|
||||
RouteId: trip.RouteID,
|
||||
AgencyName: trip.Agency.AgencyName,
|
||||
TripHeadsign: trip.TripHeadsign,
|
||||
TripShortName: trip.TripShortName,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user