@@ -7,11 +7,11 @@ import (
77 "sync"
88 "time"
99
10+ "github.com/dharmab/collections/deques"
1011 "github.com/dharmab/skyeye/pkg/bearings"
1112 "github.com/dharmab/skyeye/pkg/brevity"
1213 "github.com/dharmab/skyeye/pkg/coalitions"
1314 "github.com/dharmab/skyeye/pkg/spatial"
14- "github.com/gammazero/deque"
1515 "github.com/martinlindhe/unit"
1616 "github.com/paulmach/orb"
1717 "github.com/rs/zerolog/log"
@@ -36,7 +36,7 @@ type Trackfile struct {
3636 // Contact contains identifying information.
3737 Contact Labels
3838 // track is a collection of frames, ordered from most recent to least recent.
39- track deque. Deque [Frame ]
39+ track * deques. Counting [Frame ]
4040 lock sync.RWMutex
4141}
4242
@@ -61,7 +61,7 @@ type Frame struct {
6161func New (labels Labels ) * Trackfile {
6262 return & Trackfile {
6363 Contact : labels ,
64- track : * deque . New [Frame ](),
64+ track : deques. NewCounting [Frame ](maxLength ),
6565 }
6666}
6767
@@ -84,13 +84,10 @@ func (t *Trackfile) String() string {
8484func (t * Trackfile ) Update (f Frame ) {
8585 t .lock .Lock ()
8686 defer t .lock .Unlock ()
87- if t .track .Len () > 0 && f .Time .Before (t . track . Front () .Time ) {
87+ if newest , ok := t .track .Newest (); ok && f .Time .Before (newest .Time ) {
8888 return
8989 }
90- t .track .PushFront (f )
91- for t .track .Len () > maxLength {
92- t .track .PopBack ()
93- }
90+ t .track .Push (f )
9491}
9592
9693// Bullseye returns the bearing and distance from the bullseye to the track's last known position.
@@ -108,16 +105,10 @@ func (t *Trackfile) Bullseye(bullseye orb.Point, opts ...spatial.Option) *brevit
108105func (t * Trackfile ) LastKnown () Frame {
109106 t .lock .RLock ()
110107 defer t .lock .RUnlock ()
111- return t .unsafeLastKnown ()
112- }
113-
114- // unsafeLastKnown is like LastKnown, but it does not acquire a lock. The calling
115- // function must acquire t.lock before calling this function.
116- func (t * Trackfile ) unsafeLastKnown () Frame {
117- if t .track .Len () == 0 {
118- return Frame {}
108+ if f , ok := t .track .Newest (); ok {
109+ return f
119110 }
120- return t . track . Front ()
111+ return Frame {}
121112}
122113
123114// IsLastKnownPointZero returns true if the last known point is at (0, 0).
@@ -126,8 +117,12 @@ func (t *Trackfile) IsLastKnownPointZero() bool {
126117 return spatial .IsZero (t .LastKnown ().Point )
127118}
128119
120+ // bestAvailableDeclination returns the magnetic declination at the track's most recent position, or 0 if unavailable.
129121func (t * Trackfile ) bestAvailableDeclination () unit.Angle {
130- latest := t .unsafeLastKnown ()
122+ latest , ok := t .track .Newest ()
123+ if ! ok {
124+ return 0
125+ }
131126 declincation , err := bearings .Declination (latest .Point , latest .Time )
132127 if err != nil {
133128 return 0
@@ -141,14 +136,22 @@ func (t *Trackfile) bestAvailableDeclination() unit.Angle {
141136func (t * Trackfile ) Course (opts ... spatial.Option ) bearings.Bearing {
142137 t .lock .RLock ()
143138 defer t .lock .RUnlock ()
139+ return t .computeCourse (opts ... )
140+ }
141+
142+ // computeCourse returns the magnetic bearing between the two most recent frames, or the heading if only one frame exists. Caller must hold t.lock.
143+ func (t * Trackfile ) computeCourse (opts ... spatial.Option ) bearings.Bearing {
144+ latest , ok := t .track .Newest ()
145+ if ! ok {
146+ return bearings .NewTrueBearing (0 )
147+ }
144148 if t .track .Len () == 1 {
145149 return bearings .NewTrueBearing (
146- t . track . Front () .Heading ,
150+ latest .Heading ,
147151 ).Magnetic (t .bestAvailableDeclination ())
148152 }
149153
150- latest := t .track .Front ()
151- previous := t .track .At (1 )
154+ previous , _ := t .track .At (1 )
152155
153156 declination := t .bestAvailableDeclination ()
154157 course := spatial .TrueBearing (previous .Point , latest .Point , opts ... ).Magnetic (declination )
@@ -166,18 +169,19 @@ func (t *Trackfile) Direction() brevity.Track {
166169 return brevity .UnknownDirection
167170 }
168171
169- course := t .Course ()
170- return brevity .TrackFromBearing (course )
172+ return brevity .TrackFromBearing (t .computeCourse ())
171173}
172174
173- // groundSpeed returns the approximate speed of the track along the ground (i.e. in two dimensions) .
175+ // groundSpeed returns the approximate ground speed of the track in two dimensions. Caller must hold t.lock .
174176func (t * Trackfile ) groundSpeed (opts ... spatial.Option ) unit.Speed {
175- if t .track .Len () < 2 {
177+ latest , ok := t .track .Newest ()
178+ if ! ok {
179+ return 0
180+ }
181+ previous , ok := t .track .At (1 )
182+ if ! ok {
176183 return 0
177184 }
178-
179- latest := t .track .Front ()
180- previous := t .track .At (1 )
181185
182186 timeDelta := latest .Time .Sub (previous .Time )
183187 if timeDelta == 0 {
@@ -197,12 +201,14 @@ func (t *Trackfile) groundSpeed(opts ...spatial.Option) unit.Speed {
197201func (t * Trackfile ) Speed () unit.Speed {
198202 t .lock .RLock ()
199203 defer t .lock .RUnlock ()
200- if t .track .Len () < 2 {
204+ latest , ok := t .track .Newest ()
205+ if ! ok {
206+ return 0
207+ }
208+ previous , ok := t .track .At (1 )
209+ if ! ok {
201210 return 0
202211 }
203-
204- latest := t .track .Front ()
205- previous := t .track .At (1 )
206212
207213 timeDelta := latest .Time .Sub (previous .Time )
208214 if timeDelta == 0 {
0 commit comments