-
Notifications
You must be signed in to change notification settings - Fork 0
/
liner.go
171 lines (128 loc) · 4.43 KB
/
liner.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package models
import (
"fmt"
"log"
"math"
"time"
gongsim_models "github.com/fullstack-lang/gongsim/go/models"
geo "github.com/kellydunn/golang-geo"
)
// Liner is a moving object
// swagger:model liner
type Liner struct {
Name string
MovingObject // concept
// Agent
// swagger:ignore
gongsim_models.Agent
State LinerStateEnum
// Control of the aircraft
TargetHeading float64
TargetLocationLat float64
TargetLocationLng float64
DistanceToTarget float64
// Max rotational speed, in degrees/seconds
MaxRotationalSpeed float64
// Vertical Speed
VerticalSpeed float64
// time stamps of the liner
timestamp time.Time
Timestampstring string
// history of lat positions at each event
latPositions []float64
lngPositions []float64
updateEventNb int
ReporingLine *OpsLine
}
func (Liner *Liner) Register(engine *gongsim_models.Engine) (res *Liner) {
gongsim_models.AppendToSingloton(engine, Liner)
res = Liner
return
}
// LinerStateEnum ..
// swagger:enum LinerStateEnum
type LinerStateEnum string
// state
const (
EN_ROUTE_NOMINAL LinerStateEnum = "EN_ROUTE_NOMINAL"
LANDED LinerStateEnum = "LANDED"
)
// FireNextEvent fire next Event
func (liner *Liner) FireNextEvent() {
event, _ := liner.GetNextEventAndRemoveIt()
switch event.(type) {
case *gongsim_models.UpdateState:
checkStateEvent := event.(*gongsim_models.UpdateState)
liner.updateEventNb++
// post next event
checkStateEvent.SetFireTime(checkStateEvent.GetFireTime().Add(checkStateEvent.Period))
liner.QueueEvent(checkStateEvent)
//
// Update Speed & Heading
//
// Change heading toward target location
linerPoint := geo.NewPoint(liner.Lat, liner.Lng)
targetLocation := geo.NewPoint(liner.TargetLocationLat, liner.TargetLocationLng)
liner.TargetHeading = linerPoint.BearingTo(targetLocation)
liner.TargetHeading = math.Mod(liner.TargetHeading+360.0, 360.0)
maxNumberOfDegreesPerStep := liner.MaxRotationalSpeed * checkStateEvent.Period.Seconds()
desiredRotation := liner.TargetHeading - liner.Heading
if math.Abs(desiredRotation) > maxNumberOfDegreesPerStep {
desiredRotation = desiredRotation * (maxNumberOfDegreesPerStep / math.Abs(desiredRotation))
}
newHeading := math.Mod(liner.Heading+desiredRotation+360, 360.0)
liner.Heading = newHeading
// log.Printf("Heading %f, New heading %f ", liner.Heading, newHeading)
// Update speed
liner.DistanceToTarget = targetLocation.GreatCircleDistance(linerPoint)
if liner.DistanceToTarget < 10.0 { // 10 km.
liner.Speed = 0.0
if liner.State != LANDED {
log.Printf("Liner %s landed at lat %f lng %f at time %s ",
liner.Name, liner.TargetLocationLat, liner.TargetLocationLng, checkStateEvent.GetFireTime())
liner.State = LANDED
}
}
// update state vector of the liner
orig := geo.NewPoint(liner.Lat, liner.Lng)
elapsedTimeInHours := checkStateEvent.Period.Hours()
distance := liner.Speed * elapsedTimeInHours // since speed is in km/h, the distance in km
nextPoint := orig.PointAtDistanceAndBearing(
distance,
liner.Heading)
liner.Lat = nextPoint.Lat()
liner.Lng = nextPoint.Lng()
if liner.updateEventNb%20 == 0 {
liner.latPositions = append(liner.latPositions, liner.Lat)
liner.lngPositions = append(liner.lngPositions, liner.Lng)
}
liner.timestamp = checkStateEvent.GetFireTime()
liner.Timestampstring = liner.timestamp.String()
case *Order:
order := event.(*Order)
log.Printf("liner %s receives order %s at %s", liner.Name, order.OrderMessage, order.GetFireTime())
default:
err := fmt.Sprintf("unkown event type %T", event)
log.Panic(err)
}
}
// functions to satisty the visual interface for track
func (liner *Liner) GetLat() float64 { return liner.Lat }
func (liner *Liner) GetLng() float64 { return liner.Lng }
func (liner *Liner) GetHeading() float64 { return liner.Heading }
// speed is displayed in tens of nautical miles
func (liner *Liner) GetSpeed() float64 {
return liner.Speed / 18.52
}
func (liner *Liner) GetVerticalSpeed() float64 { return liner.VerticalSpeed }
func (liner *Liner) GetLevel() float64 { return liner.Level }
// specific
// func (liner *Liner) GetColorEnum() ColorEnum { return GREY }
func (liner *Liner) GetDisplay() bool { return true }
func (*Liner) GetLayerGroupName() (name string) { return string(Aircraft_) }
func (liner *Liner) GetLatPositions() []float64 {
return liner.latPositions
}
func (liner *Liner) GetLngPositions() []float64 {
return liner.lngPositions
}