fuzzyworld

find-stone-beer / files / coord-round.go

coord-round.go

Blame: the commit that last changed each line · file · history

1ab63e54 2023-08-27 Pavel Safronov1package main
2
3import (
4 "fmt"
5 "math"
6 "strings"
7
8 "github.com/jftuga/geodist"
9)
10
11type ImperialDistance struct {
12 Miles float64
13}
14
15func (d ImperialDistance) GetFeet() float64 {
16 feet := d.Miles * 5280
17 return feet
18}
19func (d ImperialDistance) GetInches() float64 {
20 inches := d.GetFeet() * 12
21 return inches
22}
23func (d ImperialDistance) ToString() string {
24 miles := Round(d.Miles, 2)
25 feet := Round(d.GetFeet(), 2)
26 inches := Round(d.GetInches(), 2)
27
28 if miles > 1 {
29 return fmt.Sprintf("%.2fmi", miles)
30 }
31
32 if feet > 1 {
33 return fmt.Sprintf("%.2fft", feet)
34 }
35
36 return fmt.Sprintf("%.2fin", inches)
37}
38
39func GetPrecisionDistance(coord geodist.Coord) (ImperialDistance, error) {
40 latDelta := getDelta(coord.Lat)
41 minLat := coord.Lat - latDelta
42 maxLat := coord.Lat + latDelta
43
44 lonDelta := getDelta(coord.Lon)
45 minLon := coord.Lon - lonDelta
46 maxLon := coord.Lon + lonDelta
47
48 minCoord := geodist.Coord{Lat: minLat, Lon: minLon}
49 maxCoord := geodist.Coord{Lat: maxLat, Lon: maxLon}
50 distMiles, _, err := geodist.VincentyDistance(minCoord, maxCoord)
51 if err != nil {
52 return ImperialDistance{}, err
53 }
54 id := ImperialDistance{Miles: distMiles}
55 return id, nil
56}
57
58func getDelta(f float64) float64 {
59 text := fmt.Sprintf("%g", f)
60 if !strings.Contains(text, ".") {
61 return 1
62 }
63 afterDecimal := strings.Split(text, ".")[1]
64 afterDecimal = strings.TrimRight(afterDecimal, "0")
65 decimals := len(afterDecimal)
66 delta := math.Pow(10, -float64(decimals))
67 return delta
68}
69
70func RoundCoord(c geodist.Coord, id ImperialDistance) (geodist.Coord, error) {
71 var lastRoundedCoord geodist.Coord
72 for decimalPlaces := 1; decimalPlaces < 7; decimalPlaces++ {
73 lat := Round(c.Lat, decimalPlaces)
74 lon := Round(c.Lon, decimalPlaces)
75 roundedCoord := geodist.Coord{Lat: lat, Lon: lon}
76 roundedId, err := GetPrecisionDistance(roundedCoord)
77 if err != nil {
78 return geodist.Coord{}, err
79 }
80 if roundedId.Miles < id.Miles {
81 return lastRoundedCoord, nil
82 }
83 lastRoundedCoord = roundedCoord
84 }
85
86 return geodist.Coord{}, fmt.Errorf("could not round coord: %v", c)
87}
88
89func Round(f float64, places int) float64 {
90 shift := math.Pow(10, float64(places))
91 return math.Round(f*shift) / shift
92}