Conditions | 3 |
Total Lines | 101 |
Code Lines | 60 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
1 | import numpy as np |
||
156 | def direct(lats1: 'list', lons1: 'list', brgs: 'list', dists: 'list') -> 'dict': |
||
157 | """ |
||
158 | Direct geodesic using Vincenty approach. |
||
159 | |||
160 | Given a start point, initial bearing (0° is North, clockwise) |
||
161 | and distance in meters, this will calculate the destination point |
||
162 | and final bearing travelling along a (shortest distance) great circle arc. |
||
163 | |||
164 | Bearing in 0-360deg starting from North clockwise. |
||
165 | |||
166 | all variables must be of same length |
||
167 | |||
168 | Ref: |
||
169 | https://www.movable-type.co.uk/scripts/latlong.html |
||
170 | https://www.movable-type.co.uk/scripts/latlong-vincenty.html |
||
171 | """ |
||
172 | |||
173 | lon1, lat1, brg = map(np.radians, [lons1, lats1, brgs]) |
||
174 | |||
175 | # WGS84 |
||
176 | a = 6378137.0 |
||
177 | b = 6356752.314245 |
||
178 | f = 1.0 / 298.257223563 |
||
179 | |||
180 | azi1 = brg |
||
181 | s = dists |
||
182 | |||
183 | sinazi1 = np.sin(azi1) |
||
184 | cosazi1 = np.cos(azi1) |
||
185 | |||
186 | tanU1 = (1 - f) * np.tan(lat1) |
||
187 | cosU1 = 1 / np.sqrt((1 + tanU1 * tanU1)) |
||
188 | sinU1 = tanU1 * cosU1 |
||
189 | |||
190 | # sigma1 = angular distance on the sphere from the equator to P1 |
||
191 | sigma1 = np.arctan2(tanU1, cosazi1) |
||
192 | |||
193 | sinazi = cosU1 * sinazi1 # azi = azimuth of the geodesic at the equator |
||
194 | cosSqazi = 1 - sinazi * sinazi |
||
195 | uSq = cosSqazi * (a * a - b * b) / (b * b) |
||
196 | A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq))) |
||
197 | B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq))) |
||
198 | |||
199 | sigma = s / (b * A) |
||
200 | # sigma = angular distance P₁ P₂ on the sphere |
||
201 | # sigmam = angular distance on the sphere from the equator to |
||
202 | # the midpoint of the line |
||
203 | |||
204 | iterations = 0 |
||
205 | sigmaprime = 0 |
||
206 | |||
207 | while (np.abs(sigma - sigmaprime) > 1e-12).any(): |
||
208 | cos2sigmam = np.cos(2 * sigma1 + sigma) |
||
209 | sinsigma = np.sin(sigma) |
||
210 | cossigma = np.cos(sigma) |
||
211 | deltasigma = ( |
||
212 | B |
||
213 | * sinsigma |
||
214 | * ( |
||
215 | cos2sigmam |
||
216 | + B |
||
217 | / 4 |
||
218 | * ( |
||
219 | cossigma * (-1 + 2 * cos2sigmam * cos2sigmam) |
||
220 | - B |
||
221 | / 6 |
||
222 | * cos2sigmam |
||
223 | * (-3 + 4 * sinsigma * sinsigma) |
||
224 | * (-3 + 4 * cos2sigmam * cos2sigmam) |
||
225 | ) |
||
226 | ) |
||
227 | ) |
||
228 | sigmaprime = sigma |
||
229 | sigma = s / (b * A) + deltasigma |
||
230 | iterations += 1 |
||
231 | if iterations >= 100: |
||
232 | raise Exception('Vincenty formula failed to converge') |
||
233 | |||
234 | x = sinU1 * sinsigma - cosU1 * cossigma * cosazi1 |
||
235 | lat2 = np.arctan2( |
||
236 | sinU1 * cossigma + cosU1 * sinsigma * cosazi1, |
||
237 | (1 - f) * np.sqrt(sinazi * sinazi + x * x), |
||
238 | ) |
||
239 | lambd = np.arctan2( |
||
240 | sinsigma * sinazi1, cosU1 * cossigma - sinU1 * sinsigma * cosazi1 |
||
241 | ) |
||
242 | C = f / 16 * cosSqazi * (4 + f * (4 - 3 * cosSqazi)) |
||
243 | L = lambd - (1 - C) * f * sinazi * ( |
||
244 | sigma |
||
245 | + C |
||
246 | * sinsigma |
||
247 | * (cos2sigmam + C * cossigma * (-1 + 2 * cos2sigmam * cos2sigmam)) |
||
248 | ) |
||
249 | lon2 = lon1 + L |
||
250 | azi2 = np.arctan2(sinazi, -x) |
||
251 | |||
252 | lat2 = wrap90deg(lat2 * 180.0 / np.pi) |
||
253 | lon2 = wrap180deg(lon2 * 180.0 / np.pi) |
||
254 | azi2 = wrap360deg(azi2 * 180.0 / np.pi) |
||
255 | |||
256 | return {'lat2': lat2, 'lon2': lon2, 'azi2': azi2, 'iterations': iterations} |
||
257 |