forked from tormoder/fit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
latlng.go
122 lines (105 loc) · 3.43 KB
/
latlng.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
package fit
import (
"math"
"strconv"
)
const (
sint32Invalid = 0x7FFFFFFF
precision = 5 // 1.1 m
)
var (
semiToDegFactor = 180 / math.Pow(2, 31)
degToSemiFactor = math.Pow(2, 31) / 180
)
// Latitude represents the geographical coordinate latitude.
type Latitude struct {
semicircles int32
}
// NewLatitude returns a new latitude from a semicircle. If semicircles is
// outside the range of a latitude, (math.MinInt32/2, math.MaxInt32/2) then an
// invalid latitude is returned.
func NewLatitude(semicircles int32) Latitude {
if semicircles == sint32Invalid {
return NewLatitudeInvalid()
}
if semicircles < math.MinInt32/2 || semicircles > math.MaxInt32/2 {
return NewLatitudeInvalid()
}
return Latitude{semicircles: semicircles}
}
// NewLatitudeDegrees returns a new latitude from a degree. If degrees is
// outside the range of a latitude (+/- 90°) then an invalid latitude is
// returned.
func NewLatitudeDegrees(degrees float64) Latitude {
if degrees >= 90 || degrees <= -90 {
return NewLatitudeInvalid()
}
return Latitude{semicircles: int32(degrees * degToSemiFactor)}
}
// NewLatitudeInvalid returns an invalid latitude. The underlying storage is
// set to the invalid value of the FIT base type (sint32) used to represent a
// latitude.
func NewLatitudeInvalid() Latitude {
return Latitude{semicircles: sint32Invalid}
}
// Semicircles returns l in semicircles.
func (l Latitude) Semicircles() int32 {
return l.semicircles
}
// Degrees returns l in degrees. If l is invalid then NaN is returned.
func (l Latitude) Degrees() float64 {
if l.semicircles == sint32Invalid {
return math.NaN()
}
return float64(l.semicircles) * semiToDegFactor
}
// String returns a string representation of l in degrees with 5 decimal
// places. If l is invalid then the string "Invalid" is returned.
func (l Latitude) String() string {
if l.semicircles == sint32Invalid {
return "Invalid"
}
return strconv.FormatFloat(l.Degrees(), 'f', precision, 32)
}
// Longitude represents the geographical coordinate longitude.
type Longitude struct {
semicircles int32
}
// NewLongitude returns a new longitude from a semicircle.
func NewLongitude(semicircles int32) Longitude {
return Longitude{semicircles: semicircles}
}
// NewLongitudeDegrees returns a new longitude from a degree. If degrees is
// outside the range of a longitude (+/- 180°) then an invalid longitude is
// returned.
func NewLongitudeDegrees(degrees float64) Longitude {
if degrees >= 180 || degrees <= -180 {
return Longitude{semicircles: sint32Invalid}
}
return Longitude{semicircles: int32(degrees * degToSemiFactor)}
}
// NewLongitudeInvalid returns an invalid longitude. The underlying storage is
// set to the invalid value of the FIT base type (sint32) used to represent a
// longitude.
func NewLongitudeInvalid() Longitude {
return Longitude{semicircles: sint32Invalid}
}
// Semicircles returns l in semicircles.
func (l Longitude) Semicircles() int32 {
return l.semicircles
}
// Degrees returns l in degrees. If l is invalid then NaN is returned.
func (l Longitude) Degrees() float64 {
if l.semicircles == sint32Invalid {
return math.NaN()
}
return float64(l.semicircles) * semiToDegFactor
}
// String returns a string representation of l in degrees with 5 decimal
// places. If l is invalid then the string "Invalid" is returned.
func (l Longitude) String() string {
if l.semicircles == sint32Invalid {
return "Invalid"
}
return strconv.FormatFloat(l.Degrees(), 'f', precision, 32)
}