Files
firestar5683 ab81464bd1 Maps
Add navigation and map matching providers with the vendored map service sources.

Co-authored-by: Daniel Koepping <elkoled@gmail.com>
Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
2026-10-14 19:56:17 -05:00

180 lines
6.1 KiB
Go

package main
import (
"strconv"
"strings"
"time"
"pfeifer.dev/mapd/maps"
m "pfeifer.dev/mapd/math"
ms "pfeifer.dev/mapd/settings"
"pfeifer.dev/mapd/utils"
)
type SpeedLimitState struct {
Limit utils.Float32Tracker
Suggestion utils.Float32Tracker
SetSpeedWhenAccepted float32
OverrideSpeed float32
AcceptedLimit float32
NextLimit Upcoming[float32]
}
func (s *SpeedLimitState) Init() {
s.Limit.AllowNullLastValue = false
s.Suggestion.AllowNullLastValue = true
s.NextLimit = NewUpcoming(10, 0, checkWayForSpeedLimitChange)
}
func (s *SpeedLimitState) Update(currentWay CurrentWay, car CarState) {
if ms.Settings.SpeedLimitSettings.PressGasToOverrideSpeedLimit && car.GasPressed && car.VEgo > s.AcceptedLimit {
s.OverrideSpeed = car.VEgo
}
if s.OverrideSpeed < s.AcceptedLimit {
s.OverrideSpeed = 0
}
if car.SetSpeedChanging {
s.OverrideSpeed = 0
}
s.UpdateLimitAcceptedState(car)
s.UpdateAcceptedLimitValue(currentWay, car)
}
func (s *SpeedLimitState) UpdateLimitAcceptedState(car CarState) {
timeout := ms.Settings.SpeedLimitSettings.AcceptSpeedLimitTimeout
if timeout > 0 && time.Since(s.Limit.UpdatedTime) > time.Duration(timeout)*time.Second {
return
}
if ms.Settings.SpeedLimitSettings.PressGasToAcceptSpeedLimit && car.GasPressed {
ms.Settings.AcceptSpeedLimit()
}
if ms.Settings.SpeedLimitSettings.AdjustSetSpeedToAcceptSpeedLimit && car.SetSpeed.UpdatedTime.After(s.Limit.UpdatedTime) {
if ms.Settings.SpeedLimitAccepted() && s.SetSpeedWhenAccepted != car.SetSpeed.Value {
ms.Settings.ResetSpeedLimitAccepted()
}
if s.SetSpeedWhenAccepted == 0 {
s.SetSpeedWhenAccepted = car.SetSpeed.Value
ms.Settings.AcceptSpeedLimit()
}
}
}
func (s *SpeedLimitState) UpdateAcceptedLimitValue(currentWay CurrentWay, car CarState) {
suggestedSpeedUpdated := s.Suggestion.Update(s.SuggestNewSpeedLimit(currentWay, car))
if suggestedSpeedUpdated {
ms.Settings.ResetSpeedLimitAccepted()
s.SetSpeedWhenAccepted = 0
}
if ms.Settings.SpeedLimitAccepted() {
if s.AcceptedLimit != s.Suggestion.Value {
s.OverrideSpeed = 0
}
s.AcceptedLimit = s.Suggestion.Value
}
}
func (s *SpeedLimitState) SpeedLimitFinalSuggestion(enableSpeedActive bool, setSpeedChanging bool, vEgo float32) float32 {
slSuggestedSpeed := s.AcceptedLimit
if s.OverrideSpeed > 0 && s.OverrideSpeed > slSuggestedSpeed {
slSuggestedSpeed = s.OverrideSpeed
}
if !ms.Settings.SpeedLimitUseEnableSpeed || enableSpeedActive {
return slSuggestedSpeed
} else if setSpeedChanging && ms.Settings.SpeedLimitSettings.HoldSpeedLimitWhileChangingSetSpeed && vEgo-1 < s.AcceptedLimit {
return slSuggestedSpeed
}
return 0
}
func (s *SpeedLimitState) SuggestNewSpeedLimit(currentWay CurrentWay, car CarState) float32 {
slSuggestedSpeed := ms.Settings.PrioritySpeedLimit(float32(currentWay.EffectiveMaxSpeed()))
if slSuggestedSpeed == 0 && ms.Settings.SpeedLimitSettings.HoldLastSeenSpeedLimit {
slSuggestedSpeed = float32(s.Limit.LastValue)
}
if slSuggestedSpeed > 0 {
slSuggestedSpeed += ms.Settings.SpeedLimitSettings.SpeedLimitOffset
}
if s.NextLimit.Value > 0 {
offsetNextSpeedLimit := s.NextLimit.Value + ms.Settings.SpeedLimitSettings.SpeedLimitOffset
s.Limit.Update(ms.Settings.PrioritySpeedLimit(float32(currentWay.EffectiveMaxSpeed())))
nextIsLower := s.Limit.Value > s.NextLimit.Value
personality := ms.Settings.CurrentPersonality()
distanceToReachSpeed := m.CalculateJerkLimitedDistanceSimple(car.VEgo, car.AEgo, offsetNextSpeedLimit, personality.TargetSpeedAccel, personality.TargetSpeedJerk)
if nextIsLower {
distanceToReachSpeed += personality.SpeedLimitDecreaseTargetSpeedTimeOffset * (s.NextLimit.Value + ms.Settings.SpeedLimitSettings.SpeedLimitOffset)
} else {
distanceToReachSpeed += personality.SpeedLimitIncreaseTargetSpeedTimeOffset * (s.NextLimit.Value + ms.Settings.SpeedLimitSettings.SpeedLimitOffset)
}
if s.NextLimit.TriggerDistance > distanceToReachSpeed {
distanceToReachSpeed = s.NextLimit.TriggerDistance
}
if distanceToReachSpeed > s.NextLimit.TriggerDistance {
s.NextLimit.TriggerDistance = distanceToReachSpeed + 10
}
if !nextIsLower && personality.SpeedUpForNextSpeedLimit && s.NextLimit.Distance < distanceToReachSpeed {
slSuggestedSpeed = float32(offsetNextSpeedLimit)
} else if nextIsLower && personality.SlowDownForNextSpeedLimit && s.NextLimit.Distance < distanceToReachSpeed {
slSuggestedSpeed = float32(offsetNextSpeedLimit)
}
}
return slSuggestedSpeed
}
func ParseMaxSpeed(maxspeed string) float64 {
splitSpeed := strings.Split(maxspeed, " ")
if len(splitSpeed) == 0 {
return 0
}
numeric, err := strconv.ParseUint(splitSpeed[0], 10, 64)
if err != nil {
return 0
}
if len(splitSpeed) == 1 {
return ms.KPH_TO_MS * float64(numeric)
}
if splitSpeed[1] == "kph" || splitSpeed[1] == "km/h" || splitSpeed[1] == "kmh" {
return ms.KPH_TO_MS * float64(numeric)
} else if splitSpeed[1] == "mph" {
return ms.MPH_TO_MS * float64(numeric)
} else if splitSpeed[1] == "knots" {
return ms.KNOTS_TO_MS * float64(numeric)
}
return 0
}
func checkWayForSpeedLimitChange(state *State, parent *Upcoming[float32], way maps.NextWayResult) (valid bool, val float32) {
nextMaxSpeed := way.Way.MaxSpeed()
if way.IsForward && way.Way.MaxSpeedForward() > 0 {
nextMaxSpeed = way.Way.MaxSpeedForward()
} else if !way.IsForward && way.Way.MaxSpeedBackward() > 0 {
nextMaxSpeed = way.Way.MaxSpeedBackward()
}
if ms.Settings.ConditionalSpeedLimitControlEnabled {
rules := way.Way.ConditionalSpeedRules(way.IsForward)
if conditional := maps.ConditionalSpeedAt(rules, time.Now()); conditional > 0 {
nextMaxSpeed = conditional
}
}
if nextMaxSpeed != state.CurrentWay.EffectiveMaxSpeed() && nextMaxSpeed > 0 {
return true, float32(nextMaxSpeed)
}
return false, parent.DefaultValue
}
func checkWayForAdvisorySpeedChange(state *State, parent *Upcoming[float32], way maps.NextWayResult) (valid bool, val float32) {
nextAdvisorySpeed := way.Way.AdvisorySpeed()
if nextAdvisorySpeed != state.CurrentWay.Way.AdvisorySpeed() && nextAdvisorySpeed > 0 {
return true, float32(nextAdvisorySpeed)
}
return false, parent.DefaultValue
}