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

164 lines
4.8 KiB
Go

package main
import (
"fmt"
"math"
"github.com/pkg/errors"
m "pfeifer.dev/mapd/math"
ms "pfeifer.dev/mapd/settings"
)
func GetStateCurvatures(state *State) ([]m.Curvature, error) {
nodes := state.CurrentWay.Way.Nodes.Slice()
num_points := len(nodes)
all_nodes := [][]m.Position{nodes}
all_nodes_direction := []bool{state.CurrentWay.OnWay.IsForward}
all_nodes_is_merge_or_split := []bool{false}
lastWay := state.CurrentWay.Way
for _, nextWay := range state.NextWays {
nwNodes := nextWay.Way.Nodes.Slice()
if len(nwNodes) > 0 {
num_points += len(nwNodes) - 1
}
all_nodes = append(all_nodes, nwNodes)
all_nodes_direction = append(all_nodes_direction, nextWay.IsForward)
all_nodes_is_merge_or_split = append(all_nodes_is_merge_or_split, lastWay.Lanes() < nextWay.Way.Lanes() || (lastWay.Lanes() > nextWay.Way.Lanes() && !lastWay.OneWay() && nextWay.Way.OneWay()))
lastWay = nextWay.Way
}
positions := make([]m.Position, num_points)
merge_or_split_nodes := []int{}
all_nodes_idx := 0
nodes_idx := 0
for i := 0; i < num_points; i++ {
var index int
forward := all_nodes_direction[all_nodes_idx]
if forward {
index = nodes_idx
if all_nodes_idx > 0 {
index += 1
}
} else {
index = len(all_nodes[all_nodes_idx]) - nodes_idx - 1
if all_nodes_idx > 0 {
index -= 1
}
}
node := all_nodes[all_nodes_idx][index]
positions[i] = node
nodes_idx += 1
if nodes_idx == len(all_nodes[all_nodes_idx]) || (nodes_idx == len(all_nodes[all_nodes_idx])-1 && all_nodes_idx > 0) {
all_nodes_idx += 1
nodes_idx = 0
if all_nodes_idx < len(all_nodes_is_merge_or_split) && all_nodes_is_merge_or_split[all_nodes_idx] {
merge_or_split_nodes = append(merge_or_split_nodes, i)
}
}
}
curvatures, err := GetCurvatures(positions)
if err != nil {
return []m.Curvature{}, errors.Wrap(err, "could not get curvatures from points")
}
// set the merge nodes to be straight to help balance out issues with map representation
for _, merge_or_split_node := range merge_or_split_nodes {
if merge_or_split_node >= 2 {
curvatures[merge_or_split_node-2].Curvature = 0.0015
curvatures[merge_or_split_node-1].Curvature = 0.0015
}
// also include nodes within 15 meters
for i := merge_or_split_node - 3; i >= 0; i-- {
if positions[merge_or_split_node].DistanceTo(positions[i]) > 15 {
break
}
curvatures[i].Curvature = 0.0015
}
// also include forward nodes within 15 meters
for i := merge_or_split_node; i < len(curvatures); i++ {
if positions[merge_or_split_node].DistanceTo(positions[i]) > 15 {
break
}
curvatures[i].Curvature = 0.0015
}
}
average_curvatures, err := GetAverageCurvatures(curvatures)
if err != nil {
return []m.Curvature{}, errors.Wrap(err, "could not get average curvatures from curvatures")
}
return average_curvatures, nil
}
type Velocity struct {
Pos m.Position
Velocity float64
TriggerDistance float32
}
func GetTargetVelocities(curvatures []m.Curvature, previousTargets []Velocity) (velocities []Velocity) {
velocities = make([]Velocity, len(curvatures))
for i, curv := range curvatures {
if curv.Curvature == 0 {
continue
}
velocities[i].Velocity = math.Pow(float64(ms.Settings.CurrentPersonality().MapCurveTargetLatA)/curv.Curvature, 1.0/2)
velocities[i].Pos = curv.Pos
for _, t := range previousTargets {
if velocities[i].Pos.Equals(t.Pos) {
velocities[i].TriggerDistance = t.TriggerDistance
}
}
}
return velocities
}
func GetAverageCurvatures(curvatures []m.Curvature) (average_curvatures []m.Curvature, err error) {
if len(curvatures) < 3 {
return []m.Curvature{}, errors.New("not enough curvatures to average")
}
average_curvatures = make([]m.Curvature, len(curvatures)-2)
for i := 0; i < len(curvatures)-2; i++ {
a := curvatures[i].Curvature
b := curvatures[i+1].Curvature
c := curvatures[i+2].Curvature
al := curvatures[i].ArcLength
bl := curvatures[i+1].ArcLength
cl := curvatures[i+2].ArcLength
if al+bl+cl == 0 {
average_curvatures[i] = curvatures[i+2]
continue
}
avg := m.Curvature{Pos: curvatures[i+1].Pos}
avg.Curvature = (a*al + b*bl + c*cl) / (al + bl + cl)
avg.ArcLength = (curvatures[i].ArcLength + curvatures[i+1].ArcLength + curvatures[i+2].ArcLength) / 3
avg.Angle = (curvatures[i].Angle + curvatures[i+1].Angle + curvatures[i+2].Angle) / 3
average_curvatures[i] = avg
}
return average_curvatures, nil
}
func GetCurvatures(positions []m.Position) (curvatures []m.Curvature, err error) {
if len(positions) < 3 {
return []m.Curvature{}, errors.New(fmt.Sprintf("not enough points to calculate curvatures. len(points): %d", len(positions)))
}
curvatures = make([]m.Curvature, len(positions)-2)
for i := 0; i < len(positions)-2; i++ {
curvature := m.CalculateCurvature(positions[i], positions[i+1], positions[i+2])
curvatures[i] = curvature
}
return curvatures, nil
}