-
Notifications
You must be signed in to change notification settings - Fork 2
/
circular.go
77 lines (66 loc) · 2.63 KB
/
circular.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package geo
import (
"fmt"
"math"
"gopkg.in/yaml.v3"
)
type (
// defines a center point and two radii (distances) to define open and close geofences
CircularGeofence struct {
Center Point `yaml:"center"`
CloseDistance float64 `yaml:"close_distance"` // defines a radius from the center point; when vehicle moves from < distance to > distance, garage will close
OpenDistance float64 `yaml:"open_distance"` // defines a radius from the center point; when vehicle moves from > distance to < distance, garage will open
}
)
var circularMqttTopics = []string{"latitude", "longitude"}
func (c *CircularGeofence) GetMqttTopics() []string {
return circularMqttTopics
}
func distance(point1 Point, point2 Point) float64 {
// Calculate the distance between two points using the haversine formula
const radius = 6371 // Earth's radius in kilometers
lat1 := toRadians(point1.Lat)
lat2 := toRadians(point2.Lat)
deltaLat := toRadians(point2.Lat - point1.Lat)
deltaLon := toRadians(point2.Lng - point1.Lng)
a := math.Sin(deltaLat/2)*math.Sin(deltaLat/2) + math.Cos(lat1)*math.Cos(lat2)*math.Sin(deltaLon/2)*math.Sin(deltaLon/2)
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
d := radius * c
return d
}
func toRadians(degrees float64) float64 {
return degrees * math.Pi / 180
}
// gets action based on if there was a relevant distance change
func (c *CircularGeofence) getEventChangeAction(car *Car) (action string) {
if !car.CurrentLocation.IsPointDefined() {
return // need valid lat and lng to check fence
}
// update car's current distance, and store the previous distance in a variable
prevDistance := car.CurDistance
car.CurDistance = distance(car.CurrentLocation, c.Center)
// check if car has crossed a geofence and set an appropriate action
if c.CloseDistance > 0 && // is valid close distance defined
prevDistance <= c.CloseDistance &&
car.CurDistance > c.CloseDistance { // car was within close geofence, but now beyond it (car left geofence)
action = ActionClose
} else if c.OpenDistance > 0 && // is valid open distance defined
prevDistance >= c.OpenDistance &&
car.CurDistance < c.OpenDistance { // car was outside of open geofence, but is now within it (car entered geofence)
action = ActionOpen
}
return
}
func (c *CircularGeofence) parseSettings(config map[string]interface{}) error {
yamlData, err := yaml.Marshal(config)
var settings CircularGeofence
if err != nil {
return fmt.Errorf("failed to marhsal geofence yaml object, error: %v", err)
}
err = yaml.Unmarshal(yamlData, &settings)
if err != nil {
return fmt.Errorf("failed to unmarhsal geofence yaml object, error: %v", err)
}
*c = settings
return nil
}