-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgeod.go
237 lines (222 loc) · 8.89 KB
/
geod.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
package geod
// Pure Go re-implementation of https://github.com/chrisveness/geodesy
/**
* Copyright (c) 2020, 2024, Xerra Earth Observation Institute
* All rights reserved. Use is subject to License terms.
* See LICENSE in the root directory of this source tree.
*/
import (
"github.com/starboard-nz/units"
)
// Model defines the Earth model used for calculations.
// The following models are implemented:
//
// geod.SphericalModel - spherical Earth, along great circles
// geod.RhumbModel - spherical Earth, along rhumb lines
// geod.VincentyModel - ellipsoid Earth, high accuracy, slower than SphericalModel
type Model interface {
DistanceTo(ll LatLon) units.Distance
InitialBearingTo(ll LatLon) Degrees
FinalBearingOn(ll LatLon) Degrees
DestinationPoint(distance float64, bearing Degrees) LatLon
MidPointTo(ll LatLon) LatLon
IntermediatePointTo(ll LatLon, fraction float64) LatLon
IntermediatePointsTo(ll LatLon, fractions []float64) []LatLon
LatLon() LatLon
}
type EarthModel func(LatLon, ...interface{}) Model
// MidPoint returns the point halfway between `start` and `end` using the given `model`.
//
// Arguments:
//
// start - starting point
// end - end point (destination)
// model - a function that converts a `LatLon` to a structure appropriate for the `Model` to be used
//
// This is how you select the model you wish to use for the calculations. See the description of `Model`
// for list of available functions.
//
// modelArgs - additional arguments to pass to the `model` function, if needed, for example the `Ellipsoid`
//
// for ellipsoid models.
//
// Returns the halfway point.
// If the point cannot be calculated an invalid point is returned, which can be tested using `LatLon.Valid()`
//
// Example:
// p1 := geod.NewLatLon(10.1, -20.0)
// p2 := geod.NewLatLon(12.1, -23.2)
// mid := geod.MidPoint(p1, p2, geod.SphericalModel)
func MidPoint(start, end LatLon, model EarthModel, modelArgs ...interface{}) LatLon {
p1 := model(start, modelArgs...)
return p1.MidPointTo(end)
}
// Distance returns the distance in `DistanceUnits` between points `start` and `end` using the given `model`.
//
// Arguments:
//
// start - starting point
// end - end point (destination)
// model - a function that converts a `LatLon` to a structure appropriate for the `Model` to be used
//
// This is how you select the model you wish to use for the calculations. See the description of `Model`
// for list of available functions.
//
// modelArgs - additional arguments to pass to the `model` function, if needed, for example the `Ellipsoid`
//
// for ellipsoid models.
//
// Returns the distance in `DistanceUnits`
// If the distance cannot be calculated an invalid is returned, which can be tested using `DistanceUnits.Valid()`
//
// Example:
// p1 := geod.NewLatLon(10.1, -20.0)
// p2 := geod.NewLatLon(12.1, -23.2)
// dist := geod.MidPoint(p1, p2, geod.VincentyModel, WGS84) // WGS84 can be omitted, it's the default and only
//
// `Ellipsoid` currently defined
//
// metres := dist.Metres()
func Distance(start, end LatLon, model EarthModel, modelArgs ...interface{}) units.Distance {
p1 := model(start, modelArgs...)
return p1.DistanceTo(end)
}
// InitialBearing returns the initial bearing going from `start` to `end` using the given `model`.
//
// Arguments:
//
// start - starting point
// end - end point (destination)
// model - a function that converts a `LatLon` to a structure appropriate for the `Model` to be used
//
// This is how you select the model you wish to use for the calculations. See the description of `Model`
// for list of available functions.
//
// modelArgs - additional arguments to pass to the `model` function, if needed, for example the `Ellipsoid`
//
// for ellipsoid models.
//
// Returns the initial bearing in `Degrees` from North
// If the bearing cannot be calculated NaN value is returned, which can be tested using `Degrees.Valid()`
//
// Example:
// p1 := geod.NewLatLon(10.1, -20.0)
// p2 := geod.NewLatLon(12.1, -23.2)
// bearing := geod.InitialBearing(p1, p2, geod.SphericalModel)
func InitialBearing(start, end LatLon, model EarthModel, modelArgs ...interface{}) Degrees {
p1 := model(start, modelArgs...)
return p1.InitialBearingTo(end)
}
// FinalBearing returns the final bearing having travelled from `start` to `end` using the given `model`.
//
// Arguments:
//
// start - starting point
// end - end point (destination)
// model - a function that converts a `LatLon` to a structure appropriate for the `Model` to be used
//
// This is how you select the model you wish to use for the calculations. See the description of `Model`
// for list of available functions.
//
// modelArgs - additional arguments to pass to the `model` function, if needed, for example the `Ellipsoid`
//
// for ellipsoid models.
//
// Returns the final bearing in `Degrees` from North
// If the bearing cannot be calculated NaN value is returned, which can be tested using `Degrees.Valid()`
//
// Example:
// p1 := geod.NewLatLon(10.1, -20.0)
// p2 := geod.NewLatLon(12.1, -23.2)
// bearing := geod.FinalBearing(p1, p2, geod.SphericalModel)
func FinalBearing(start, end LatLon, model EarthModel, modelArgs ...interface{}) Degrees {
p1 := model(start, modelArgs...)
return p1.FinalBearingOn(end)
}
// DestinationPoint returns the destination point going from `start` having travelled `distance` on the given initial bearing,
// using the given `model`.
//
// Arguments:
//
// start - starting point
// distance - distance travelled, in metres -- Note: I might change this to DistanceUnits in the future (FIXME)
// bearing - initial bearing in `Degrees` from North
// model - a function that converts a `LatLon` to a structure appropriate for the `Model` to be used
//
// This is how you select the model you wish to use for the calculations. See the description of `Model`
// for list of available functions.
//
// modelArgs - additional arguments to pass to the `model` function, if needed, for example the `Ellipsoid`
//
// for ellipsoid models.
//
// Returns the final point (destination)
// If the point cannot be calculated an invalid point is returned, which can be tested using `LatLon.Valid()`
//
// Example:
// p1 := geod.NewLatLon(10.1, -20.0)
// bearing := geod.Degrees(23.2)
// p2 := geod.Destination(p1, 100000.0, bearing, geod.RhumbModel) // 100kms from p1 heading 23.2 along a rhumb line
func DestinationPoint(start LatLon, distance float64, bearing Degrees, model EarthModel,
modelArgs ...interface{}) LatLon {
p1 := model(start, modelArgs...)
return p1.DestinationPoint(distance, bearing)
}
// IntermediatePoint returns the point at the given fraction between `start` and `end`.
//
// Arguments:
//
// start - starting point
// end - end point (destination)
// fraction - the fraction between the two points (0.0 = `start`, 1.0 = `end`)
// model - a function that converts a `LatLon` to a structure appropriate for the `Model` to be used
//
// This is how you select the model you wish to use for the calculations. See the description of `Model`
// for list of available functions.
//
// modelArgs - additional arguments to pass to the `model` function, if needed, for example the `Ellipsoid`
//
// for ellipsoid models.
//
// Returns the intermediate point at the given fraction.
// If the point cannot be calculated an invalid point is returned, which can be tested using `LatLon.Valid()`
//
// Example:
// p1 := geod.NewLatLon(10.1, -20.0)
// p2 := geod.NewLatLon(12.1, -23.2)
// pInt := geod.IntermediatePoint(p1, p2, 0.24, geod.VincentyModel)
func IntermediatePoint(start, end LatLon, fraction float64, model EarthModel,
modelArgs ...interface{}) LatLon {
p1 := model(start, modelArgs...)
return p1.IntermediatePointTo(end, fraction)
}
// IntermediatePoints returns a slice of points at the given fractions between `start` and `end`.
// This is far more efficient than multiple `IntermediatePoint` calls in a loop as some of the
// expensive calculations are reused and each franctional point is calculated in parallel.
//
// Arguments:
//
// start - starting point
// end - end point (destination)
// fractions - slice of fractions between the two points (0.0 = `start`, 1.0 = `end`)
// model - a function that converts a `LatLon` to a structure appropriate for the `Model` to be used
//
// This is how you select the model you wish to use for the calculations. See the description of `Model`
// for list of available functions.
//
// modelArgs - additional arguments to pass to the `model` function, if needed, for example the `Ellipsoid`
//
// for ellipsoid models.
//
// Returns slice of intermediate points at the given fractions.
// Points that cannot be calculated are returned as invalid points, can be tested using `LatLon.Valid()`
//
// Example:
// p1 := geod.NewLatLon(10.1, -20.0)
// p2 := geod.NewLatLon(12.1, -23.2)
// pInt := geod.IntermediatePoint(p1, p2, 0.24, geod.VincentyModel)
func IntermediatePoints(start, end LatLon, fractions []float64, model EarthModel,
modelArgs ...interface{}) []LatLon {
p1 := model(start, modelArgs...)
return p1.IntermediatePointsTo(end, fractions)
}