bifrost

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 5, 2023 License: MIT Imports: 17 Imported by: 0

README

Bifrost

A lightweight, blazing fast, multi-modal routing engine in go. It can route on public transport and streets. Its features are still limited compared to other routing engines, but it is already quite fast and easy to use.

Usage

You can use it either as a library or as a command line tool. The cli will start a server that you can query with http requests. You will need to prepare a GTFS and an OSM file. We use the golang binding of the friendly public transport format for journey input and output.

Note, that internally, one of the libraries uses CGO for faster parsing. This can be turned off by setting the environment variable CGO_ENABLED=0 before building.

CLI Usage

Please prepare at least one GTFS and one OSM file. After that, run:

go run server/main.go -gtfs data/mvv/gtfs/ -osm data/mvv/osm/oberbayern-latest.osm.pbf -bifrost data/mvv/munich.bifrost

This will start a server on port 8090. You can query it with http requests. See here for the api specification.

Library Usage
go get github.com/Vector-Hector/bifrost

Example script:

package main

import (
	"fmt"
	"github.com/Vector-Hector/bifrost"
	"github.com/Vector-Hector/fptf"
	"time"
)

func main() {
	b := bifrost.DefaultBifrost // Create a new router with default parameters
	err := b.LoadData(&bifrost.LoadOptions{
		OsmPaths:    []string{"oberbayern-latest.osm.pbf"},
		GtfsPaths:   []string{"gtfs/"},
		BifrostPath: "munich.bifrost",
	}) // Load cached data or create and cache routing data from source
	if err != nil {
		panic(err)
	}

	r := b.NewRounds() // Reusable rounds object for routing

	// define origin, destination and time
	origin := &fptf.Location{
		Name:      "München Hbf",
		Longitude: 11.5596949,
		Latitude:  48.140262,
	}

	dest := &fptf.Location{
		Name:      "Marienplatz",
		Longitude: 11.5757167,
		Latitude:  48.1378071,
	}

	departureTime, err := time.Parse(time.RFC3339, "2023-12-12T08:30:00Z")
	if err != nil {
		panic(err)
	}

	journey, err := b.Route(r, []bifrost.SourceLocation{{
		Location:  origin,
		Departure: departureTime,
	}}, dest, false, false)
	if err != nil {
		panic(err)
	}

	fmt.Println("Journey from", journey.GetOrigin().GetName(), "to", journey.GetDestination().GetName(), "departs at", journey.GetDeparture(), "and arrives at", journey.GetArrival())
}

How it works internally

The routing algorithm is based on dijkstra and the RAPTOR algorithm. It switches each round between public transport and street routing to find the best multi-modal path.

References

Thanks to all the people who wrote the following articles, algorithms and libraries:

Documentation

Index

Constants

View Source
const (
	TripIdTransfer = 0xffffffff
	TripIdNoChange = 0xfffffffe
	TripIdOrigin   = 0xfffffffd

	ArrivalTimeNotReached uint64 = 0xffffffffffffffff
)
View Source
const DayInMs uint32 = 24 * 60 * 60 * 1000

Variables

View Source
var DefaultBifrost = &Bifrost{
	TransferLimit:             4,
	TransferPaddingMs:         0,
	WalkingSpeed:              0.8 * 0.001,
	MaxWalkingMs:              60 * 1000 * 15,
	MaxStopsConnectionSeconds: 60 * 1000 * 5,
}

Functions

func Distance

func Distance(lat1 float64, lng1 float64, lat2 float64, lng2 float64, unit ...string) float64

Distance https://www.geodatasource.com/developers/go

func GetTripFromTransfer

func GetTripFromTransfer(r *RoutingData, round map[uint64]StopArrival, destination uint64) (*fptf.Trip, uint64)

func GetTripFromTrip

func GetTripFromTrip(r *RoutingData, round map[uint64]StopArrival, arrival StopArrival) (*fptf.Trip, uint64)

Types

type Arc

type Arc struct {
	Target   uint64
	Distance uint32 // in ms
}

type Bifrost

type Bifrost struct {
	TransferLimit             int
	TransferPaddingMs         uint64  // only search for trips, padded a bit after transitioning
	WalkingSpeed              float64 // in meters per ms
	MaxWalkingMs              uint32  // duration of walks not allowed to be higher than this when transferring
	MaxStopsConnectionSeconds uint32  // max length of added arcs between stops and street graph in deciseconds

	Data *RoutingData
}

func (*Bifrost) AddBifrostData

func (b *Bifrost) AddBifrostData(fileName string)

AddBifrostData Adds cached bifrost data file to the Bifrost data. Used by LoadOptions, generated by WriteBifrostData

func (*Bifrost) AddGtfs

func (b *Bifrost) AddGtfs(directory string) error

func (*Bifrost) AddOSM

func (b *Bifrost) AddOSM(path string) error

func (*Bifrost) ConnectStopsToVertices

func (b *Bifrost) ConnectStopsToVertices()

ConnectStopsToVertices connects stops to street graph using knn and the Bifrost parameters.

func (*Bifrost) DistanceMs

func (b *Bifrost) DistanceMs(from kdtree.Point, to kdtree.Point) uint32

func (*Bifrost) LoadData

func (b *Bifrost) LoadData(load *LoadOptions) error

LoadData loads the data from a given bifrost cache if it exists. Otherwise it will generate the data from given GTFS and street CSV files. After generating the data it will write the data to a bifrost cache.

func (*Bifrost) MergeData

func (b *Bifrost) MergeData(other *RoutingData)

func (*Bifrost) NewRounds

func (b *Bifrost) NewRounds() *Rounds

func (*Bifrost) ReconstructJourney

func (b *Bifrost) ReconstructJourney(destKey uint64, lastRound int, rounds *Rounds) *fptf.Journey

func (*Bifrost) Route

func (b *Bifrost) Route(rounds *Rounds, origins []SourceLocation, dest *fptf.Location, onlyWalk bool, debug bool) (*fptf.Journey, error)

func (*Bifrost) RouteOnlyWalk

func (b *Bifrost) RouteOnlyWalk(rounds *Rounds, origins []SourceKey, destKey uint64, debug bool) (*fptf.Journey, error)

func (*Bifrost) RouteUsingKeys

func (b *Bifrost) RouteUsingKeys(rounds *Rounds, origins []SourceKey, destKey uint64, debug bool) (*fptf.Journey, error)

func (*Bifrost) WriteBifrostData

func (b *Bifrost) WriteBifrostData(fileName string)

type GeoPoint

type GeoPoint struct {
	Latitude  float64
	Longitude float64
	VertKey   uint64
}

func (*GeoPoint) Dimension

func (s *GeoPoint) Dimension(i int) float64

func (*GeoPoint) Dimensions

func (s *GeoPoint) Dimensions() int

type LoadOptions

type LoadOptions struct {
	OsmPaths    []string // paths to osm pbf files
	GtfsPaths   []string // path to GTFS zip files
	BifrostPath string   // path to bifrost cache
}

type Progress

type Progress struct {
	Start     time.Time
	LastPrint time.Time
	Current   uint64
	Total     uint64
}

func (*Progress) ETA

func (p *Progress) ETA() string

ETA returns the estimated time of arrival

func (*Progress) Increment

func (p *Progress) Increment()

func (*Progress) Print

func (p *Progress) Print()

Print prints the current progress bar to the console with current, total, percentage and ETA

func (*Progress) Reset

func (p *Progress) Reset(total uint64)

type Rounds

type Rounds struct {
	Rounds                 []map[uint64]StopArrival
	MarkedStops            map[uint64]bool
	MarkedStopsForTransfer map[uint64]bool
	EarliestArrivals       map[uint64]uint64
	Queue                  map[uint32]uint32
}

func (*Rounds) NewSession

func (r *Rounds) NewSession()

func (*Rounds) ResetRounds

func (r *Rounds) ResetRounds()

type Route

type Route struct {
	Stops []uint64
	Trips []uint32
}

type RouteInformation

type RouteInformation struct {
	ShortName string
}

type RoutingData

type RoutingData struct {
	MaxTripDayLength uint32 `json:"maxTripDayLength"` // number of days to go backwards in time (for trips that end after midnight or multiple days later than the start)

	Services []*Service `json:"services"`

	Routes       []*Route          `json:"routes"`
	StopToRoutes [][]StopRoutePair `json:"stopToRoutes"`
	Trips        []*Trip           `json:"trips"`
	StreetGraph  [][]Arc           `json:"streetGraph"`

	Reorders map[uint64][]uint32 `json:"reorders"`

	// for reconstructing journeys after routing
	Vertices         []Vertex            `json:"vertices"`
	StopsIndex       map[string]uint64   `json:"stopsIndex"`     // gtfs stop id -> vertex index
	NodesIndex       map[int64]uint64    `json:"nodesIndex"`     // csv vertex id -> vertex index
	GtfsRouteIndex   []uint32            `json:"gtfsRouteIndex"` // route index -> gtfs route index
	RouteInformation []*RouteInformation `json:"routeInformation"`
	TripInformation  []*TripInformation  `json:"tripInformation"`
	TripToRoute      []uint32            `json:"tripToRoute"` // trip index -> route index

	// for finding vertices by location. points are GeoPoint
	VertexTree *kdtree.KDTree `json:"-"`
}

func MergeData

func MergeData(a *RoutingData, b *RoutingData) *RoutingData

MergeData merges two RoutingData structs. It only concatenates the vertices and edges. Use ConnectStopsToVertices to connect stops to the street graph. IMPORTANT: This algorithm may change and re-use the data from both structs. Also note, that using multiple transit feeds may break things like the stops index due to duplicate stop ids. Multiple street graphs are not supported as there is no way of connecting them. todo: fix stops index for multiple transit feeds todo: add support for multiple street graphs

func (*RoutingData) EnsureSliceLengths

func (r *RoutingData) EnsureSliceLengths()

func (*RoutingData) GetFptfStop

func (r *RoutingData) GetFptfStop(stop uint64) *fptf.StopStation

func (*RoutingData) GetTime

func (r *RoutingData) GetTime(ms uint64) fptf.TimeNullable

func (*RoutingData) PrintStats

func (r *RoutingData) PrintStats()

func (*RoutingData) RebuildVertexTree

func (r *RoutingData) RebuildVertexTree()

type Service

type Service struct {
	Weekdays uint8  // bitfield, 1 << 0 = monday, 1 << 6 = sunday
	StartDay uint32 // day relative to PivotDate
	EndDay   uint32 // day relative to PivotDate

	AddedExceptions   []uint32 // unix days
	RemovedExceptions []uint32 // unix days
}

type SourceKey

type SourceKey struct {
	StopKey   uint64    // stop key in RoutingData
	Departure time.Time // departure time
}

type SourceLocation

type SourceLocation struct {
	Location  *fptf.Location
	Departure time.Time
}

type StopArrival

type StopArrival struct {
	Arrival uint64 // arrival time in unix ms
	Trip    uint32 // trip id, 0xffffffff specifies a transfer, 0xfffffffe specifies no change compared to previous round

	EnterKey  uint64 // stop sequence key in route for trips, vertex key for transfers
	Departure uint64 // departure day for trips, departure time in unix ms for transfers
}

type StopContext

type StopContext struct {
	Id   string
	Name string
}

type StopRoutePair

type StopRoutePair struct {
	Route         uint32
	StopKeyInTrip uint32
}

type Stopover

type Stopover struct {
	Arrival   uint32 // ms time since start of day
	Departure uint32 // ms time since start of day
}

func (Stopover) ArrivalAtDay

func (s Stopover) ArrivalAtDay(day uint64) uint64

func (Stopover) DepartureAtDay

func (s Stopover) DepartureAtDay(day uint64) uint64

type Trip

type Trip struct {
	Service   uint32
	StopTimes []Stopover
}

type TripInformation

type TripInformation struct {
	Headsign string
}

type Vertex

type Vertex struct {
	Longitude float64
	Latitude  float64
	Stop      *StopContext
}

func (Vertex) Dimension

func (v Vertex) Dimension(i int) float64

func (Vertex) Dimensions

func (v Vertex) Dimensions() int

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL