forked from tormoder/fit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
latlng.go
133 lines (114 loc) · 3.74 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
123
124
125
126
127
128
129
130
131
132
133
package fit
import (
"math"
"strconv"
)
const (
sint32Invalid = 0x7FFFFFFF
stringInvalid = "Invalid"
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
}
// Invalid reports whether l represents an invalid latitude.
func (l Latitude) Invalid() bool {
return l.semicircles == sint32Invalid
}
// 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 stringInvalid
}
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
}
// Invalid reports whether l represents an invalid longitude.
func (l Longitude) Invalid() bool {
return l.semicircles == sint32Invalid
}
// 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 stringInvalid
}
return strconv.FormatFloat(l.Degrees(), 'f', precision, 32)
}