Coverage for pygeodesy/namedTuples.py: 97%

202 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2024-05-25 12:04 -0400

1 

2# -*- coding: utf-8 -*- 

3 

4u'''Named tuples. 

5 

6Tuples returned by C{pygeodesy} functions and class methods 

7are all instances of some C{Named...Tuple} class, all sub-classes 

8of C{_NamedTuple} defined in C{pygeodesy.named}. 

9''' 

10 

11from pygeodesy.basics import map1, _xinstanceof 

12# from pygeodesy.constants import INT0 # from .units 

13from pygeodesy.errors import _ALL_LAZY, _MODS, _xattr, _xkwds_not # _xkwds 

14from pygeodesy.interns import _1_, _2_, _a_, _A_, _area_, _angle_, _b_, _B_, \ 

15 _band_, _c_, _C_, _datum_, _D_, _distance_, \ 

16 _E_, _easting_, _end_, _fi_, _gamma_, _height_, \ 

17 _h_, _j_, _hemipole_, _initial_, _lam_, _lat_, \ 

18 _lon_, _n_, _northing_, _number_, _outside_, \ 

19 _phi_, _point_, _precision_, _points_, _radius_, \ 

20 _scale_, _start_, _x_, _y_, _z_, _zone_ 

21# from pygeodesy.lazily import _ALL_LAZY, _ALL_MODS as _MODS # from .errors 

22from pygeodesy.named import _NamedTuple, _Pass 

23from pygeodesy.props import deprecated_property_RO, property_RO 

24from pygeodesy.units import Band, Bearing, Degrees, Degrees2, Easting, \ 

25 FIx, Height, Int, INT0, Lam, Lat, Lon, Meter, \ 

26 Meter2, Northing, Number_, Phi, Precision_, \ 

27 Radians, Radius, Scalar, Str 

28 

29__all__ = _ALL_LAZY.namedTuples 

30__version__ = '24.05.18' 

31 

32# __DUNDER gets mangled in class 

33_closest_ = 'closest' 

34_destination_ = 'destination' 

35_elel_ = 'll' 

36_final_ = 'final' 

37_fraction_ = 'fraction' 

38 

39 

40class Bearing2Tuple(_NamedTuple): 

41 '''2-Tuple C{(initial, final)} bearings, both in compass C{degrees360}. 

42 ''' 

43 _Names_ = (_initial_, _final_) 

44 _Units_ = ( Bearing, Bearing) 

45 

46 

47class Bounds2Tuple(_NamedTuple): # .geohash.py, .latlonBase.py, .points.py 

48 '''2-Tuple C{(latlonSW, latlonNE)} with the bounds' lower-left and 

49 upper-right corner as C{LatLon} instance. 

50 ''' 

51 _Names_ = ('latlonSW', 'latlonNE') 

52 _Units_ = (_Pass, _Pass) 

53 

54 

55class Bounds4Tuple(_NamedTuple): # .geohash.py, .points.py 

56 '''4-Tuple C{(latS, lonW, latN, lonE)} with the bounds' lower-left 

57 C{(LatS, LowW)} and upper-right C{(latN, lonE)} corner lat- and 

58 longitudes. 

59 ''' 

60 _Names_ = ('latS', 'lonW', 'latN', 'lonE') 

61 _Units_ = ( Lat, Lon, Lat, Lon) 

62 

63 def enclosures(self, S_other, *W_N_E): 

64 '''Get the enclosures of this around an other L{Bounds4Tuple}. 

65 

66 @arg S_other: Bottom C{latS} (C{scalar}) or an other 

67 L{Bounds4Tuple} instance. 

68 @arg W_N_E: Left C{lonW}, top C{latN} and right C{lonE}, 

69 each a (C{scalar}) for C{scalar B{S_other}}. 

70 

71 @return: A L{Bounds4Tuple} with the I{margin} at each of 

72 the 4 sides, positive if this side I{encloses} 

73 (is on the I{outside} of) the other, negative 

74 if not or zero if abutting. 

75 ''' 

76 s, w, n, e = self 

77 S, W, N, E = map1(float, S_other, *W_N_E) if W_N_E else S_other 

78 return Bounds4Tuple(map1(float, S - s, W - w, n - N, e - E)) # *map1 

79 

80 def overlap(self, S_other, *W_N_E): 

81 '''Intersect this with an other L{Bounds4Tuple}. 

82 

83 @arg S_other: Bottom C{latS} (C{scalar}) or an other 

84 L{Bounds4Tuple} instance. 

85 @arg W_N_E: Left C{lonW}, top C{latN} and right C{lonE}, 

86 each a (C{scalar}) for C{scalar B{S_other}}. 

87 

88 @return: C{None} if the bounds do not overlap, otherwise 

89 the intersection of both as a L{Bounds4Tuple}. 

90 ''' 

91 s, w, n, e = self 

92 S, W, N, E = map1(float, S_other, *W_N_E) if W_N_E else S_other 

93 return None if s > N or n < S or w > E or e < W else \ 

94 Bounds4Tuple(max(s, S), max(w, W), min(n, N), min(e, E)) 

95 

96 

97class Destination2Tuple(_NamedTuple): # .ellipsoidalKarney.py, -Vincenty.py 

98 '''2-Tuple C{(destination, final)}, C{destination} in C{LatLon} 

99 and C{final} bearing in compass C{degrees360}. 

100 ''' 

101 _Names_ = (_destination_, _final_) 

102 _Units_ = (_Pass, Bearing) 

103 

104 

105class Destination3Tuple(_NamedTuple): # .karney.py 

106 '''3-Tuple C{(lat, lon, final)}, destination C{lat}, C{lon} in 

107 C{degrees90} respectively C{degrees180} and C{final} bearing 

108 in compass C{degrees360}. 

109 ''' 

110 _Names_ = (_lat_, _lon_, _final_) 

111 _Units_ = ( Lat, Lon, Bearing) 

112 

113 

114class Distance2Tuple(_NamedTuple): # .datum.py, .ellipsoidalBase.py 

115 '''2-Tuple C{(distance, initial)}, C{distance} in C{meter} and 

116 C{initial} bearing in compass C{degrees360}. 

117 ''' 

118 _Names_ = (_distance_, _initial_) 

119 _Units_ = ( Meter, Bearing) 

120 

121 

122class Distance3Tuple(_NamedTuple): # .ellipsoidalKarney.py, -Vincenty.py 

123 '''3-Tuple C{(distance, initial, final)}, C{distance} in C{meter} 

124 and C{initial} and C{final} bearing, both in compass C{degrees360}. 

125 ''' 

126 _Names_ = (_distance_, _initial_, _final_) 

127 _Units_ = ( Meter, Bearing, Bearing) 

128 

129 

130class Distance4Tuple(_NamedTuple): # .formy.py, .points.py 

131 '''4-Tuple C{(distance2, delta_lat, delta_lon, unroll_lon2)} with 

132 the distance in C{degrees squared}, the latitudinal C{delta_lat 

133 = B{lat2} - B{lat1}}, the wrapped, unrolled and adjusted 

134 longitudinal C{delta_lon = B{lon2} - B{lon1}} and C{unroll_lon2}, 

135 the unrolled or original B{C{lon2}}. 

136 

137 @note: Use Function L{pygeodesy.degrees2m} to convert C{degrees 

138 squared} to C{meter} as M{degrees2m(sqrt(distance2), ...)} 

139 or M{degrees2m(hypot(delta_lat, delta_lon), ...)}. 

140 ''' 

141 _Names_ = ('distance2', 'delta_lat', 'delta_lon', 'unroll_lon2') 

142 _Units_ = ( Degrees2, Degrees, Degrees, Degrees) 

143 

144 

145class EasNor2Tuple(_NamedTuple): # .css, .osgr, .ups, .utm, .utmupsBase 

146 '''2-Tuple C{(easting, northing)}, both in C{meter}, conventionally. 

147 ''' 

148 _Names_ = (_easting_, _northing_) 

149 _Units_ = ( Easting, Northing) 

150 

151 

152class EasNor3Tuple(_NamedTuple): # .css.py, .lcc.py 

153 '''3-Tuple C{(easting, northing, height)}, all in C{meter}, conventionally. 

154 ''' 

155 _Names_ = (_easting_, _northing_, _height_) 

156 _Units_ = ( Easting, Northing, Height) 

157 

158 

159class _Convergence(object): 

160 '''(INTERNAL) DEPRECATED Property C{convergence}, use property C{gamma}.''' 

161 @deprecated_property_RO 

162 def convergence(self): 

163 '''DEPRECATED, use property C{gamma}. 

164 ''' 

165 return self.gamma # PYCHOK self[.] 

166 

167 

168class Forward4Tuple(_NamedTuple, _Convergence): 

169 '''4-Tuple C{(easting, northing, gamma, scale)} in 

170 C{meter}, C{meter}, meridian convergence C{gamma} at 

171 point in C{degrees} and the C{scale} of projection 

172 at point C{scalar}. 

173 ''' 

174 _Names_ = (_easting_, _northing_, _gamma_, _scale_) 

175 _Units_ = ( Easting, Northing, Degrees, Scalar) 

176 

177 

178class Intersection3Tuple(_NamedTuple): # .css.py, .lcc.py 

179 '''3-Tuple C{(point, outside1, outside2)} of an intersection 

180 C{point} and C{outside1}, the position of the C{point}, 

181 C{-1} if before the start, C{+1} if after the end and C{0} 

182 if on or between the start and end point of the first line. 

183 Similarly, C{outside2} is C{-2}, C{+2} or C{0} to indicate 

184 the position of C{point} on the second line or path. If a 

185 path was specified with an initial bearing instead of an 

186 end point, C{outside1} and/or C{outside2} will be C{0} if 

187 the intersection C{point} is on the start point or C{+1} 

188 respectively C{+2} if the intersection C{point} is after 

189 the start point, in the direction of the bearing. 

190 ''' 

191 _Names_ = (_point_, _outside_ + _1_, _outside_ + _2_) 

192 _Units_ = (_Pass, Int, Int) 

193 

194 

195class LatLon2Tuple(_NamedTuple): 

196 '''2-Tuple C{(lat, lon)} in C{degrees90} and C{degrees180}. 

197 ''' 

198 _Names_ = (_lat_, _lon_) 

199 _Units_ = ( Lat, Lon) 

200 

201 def to3Tuple(self, height, **name): 

202 '''Extend this L{LatLon2Tuple} to a L{LatLon3Tuple}. 

203 

204 @arg height: The height to add (C{scalar}). 

205 @kwarg name: Optional C{B{name}=NN} (C{str}), overriding 

206 this name. 

207 

208 @return: A L{LatLon3Tuple}C{(lat, lon, height)}. 

209 

210 @raise ValueError: Invalid B{C{height}}. 

211 ''' 

212 return self._xtend(LatLon3Tuple, height, **name) 

213 

214 def to4Tuple(self, height, datum, **name): 

215 '''Extend this L{LatLon2Tuple} to a L{LatLon4Tuple}. 

216 

217 @arg height: The height to add (C{scalar}). 

218 @arg datum: The datum to add (C{Datum}). 

219 @kwarg name: Optional C{B{name}=NN} (C{str}), overriding 

220 this name. 

221 

222 @return: A L{LatLon4Tuple}C{(lat, lon, height, datum)}. 

223 

224 @raise TypeError: If B{C{datum}} not a C{Datum}. 

225 

226 @raise ValueError: Invalid B{C{height}}. 

227 ''' 

228 return self.to3Tuple(height).to4Tuple(datum, **name) 

229 

230 

231class LatLon3Tuple(_NamedTuple): 

232 '''3-Tuple C{(lat, lon, height)} in C{degrees90}, C{degrees180} 

233 and C{meter}, conventionally. 

234 ''' 

235 _Names_ = (_lat_, _lon_, _height_) 

236 _Units_ = ( Lat, Lon, Height) 

237 

238 def to4Tuple(self, datum, **name): 

239 '''Extend this L{LatLon3Tuple} to a L{LatLon4Tuple}. 

240 

241 @arg datum: The datum to add (C{Datum}). 

242 @kwarg name: Optional C{B{name}=NN} (C{str}), overriding 

243 this name. 

244 

245 @return: A L{LatLon4Tuple}C{(lat, lon, height, datum)}. 

246 

247 @raise TypeError: If B{C{datum}} not a C{Datum}. 

248 ''' 

249 _xinstanceof(_MODS.datums.Datum, datum=datum) 

250 return self._xtend(LatLon4Tuple, datum, **name) 

251 

252 

253class LatLon4Tuple(LatLon3Tuple): # .cartesianBase, .css, .ecef, .lcc 

254 '''4-Tuple C{(lat, lon, height, datum)} in C{degrees90}, 

255 C{degrees180}, C{meter} and L{Datum}. 

256 ''' 

257 _Names_ = (_lat_, _lon_, _height_, _datum_) 

258 _Units_ = ( Lat, Lon, Height, _Pass) 

259 

260 

261def _LL4Tuple(lat, lon, height, datum, LatLon, LatLon_kwds, inst=None, 

262 iteration=None, **name): 

263 '''(INTERNAL) Return a L{LatLon4Tuple} or a B{C{LatLon}} instance. 

264 ''' 

265 if LatLon is None: # ignore LatLon_kwds 

266 r = LatLon4Tuple(lat, lon, height, datum, **name) 

267 else: 

268 kwds = {} if inst is None else _xkwds_not(None, 

269# datum=_xattr(inst, datum=None), 

270 epoch=_xattr(inst, epoch=None), 

271 reframe=_xattr(inst, reframe=None)) # PYCHOK indent 

272 kwds.update(datum=datum, height=height, **name) 

273 if LatLon_kwds: 

274 kwds.update(LatLon_kwds) 

275 r = LatLon(lat, lon, **kwds) 

276 if iteration is not None: # like .named._namedTuple.__new__ 

277 r._iteration = iteration 

278 return r 

279 

280 

281class LatLonDatum3Tuple(_NamedTuple): # .lcc.py, .osgr.py 

282 '''3-Tuple C{(lat, lon, datum)} in C{degrees90}, C{degrees180} 

283 and L{Datum}. 

284 ''' 

285 _Names_ = (_lat_, _lon_, _datum_) 

286 _Units_ = ( Lat, Lon, _Pass) 

287 

288 

289class LatLonDatum5Tuple(LatLonDatum3Tuple, _Convergence): # .ups.py, .utm.py, .utmupsBase.py 

290 '''5-Tuple C{(lat, lon, datum, gamma, scale)} in C{degrees90}, 

291 C{degrees180}, L{Datum}, C{degrees} and C{float}. 

292 ''' 

293 _Names_ = LatLonDatum3Tuple._Names_ + (_gamma_, _scale_) 

294 _Units_ = LatLonDatum3Tuple._Units_ + ( Degrees, Scalar) 

295 

296 

297class LatLonPrec3Tuple(_NamedTuple): # .gars.py, .wgrs.py 

298 '''3-Tuple C{(lat, lon, precision)} in C{degrees}, C{degrees} 

299 and C{int}. 

300 ''' 

301 _Names_ = (_lat_, _lon_, _precision_) 

302 _Units_ = ( Lat, Lon, Precision_) 

303 

304 def to5Tuple(self, height, radius, **name): 

305 '''Extend this L{LatLonPrec3Tuple} to a L{LatLonPrec5Tuple}. 

306 

307 @arg height: The height to add (C{float} or C{None}). 

308 @arg radius: The radius to add (C{float} or C{None}). 

309 @kwarg name: Optional C{B{name}=NN} (C{str}), overriding 

310 this name. 

311 

312 @return: A L{LatLonPrec5Tuple}C{(lat, lon, precision, 

313 height, radius)}. 

314 ''' 

315 return self._xtend(LatLonPrec5Tuple, height, radius, **name) 

316 

317 

318class LatLonPrec5Tuple(LatLonPrec3Tuple): # .wgrs.py 

319 '''5-Tuple C{(lat, lon, precision, height, radius)} in C{degrees}, 

320 C{degrees}, C{int} and C{height} or C{radius} in C{meter} (or 

321 C{None} if missing). 

322 ''' 

323 _Names_ = LatLonPrec3Tuple._Names_ + (_height_, _radius_) 

324 _Units_ = LatLonPrec3Tuple._Units_ + ( Height, Radius) 

325 

326 

327class NearestOn2Tuple(_NamedTuple): # .ellipsoidalBaseDI 

328 '''2-Tuple C{(closest, fraction)} of the C{closest} point 

329 on and C{fraction} along a line (segment) between two 

330 points. The C{fraction} is C{0} if the closest point 

331 is the first or C{1} the second of the two points. 

332 Negative C{fraction}s indicate the closest point is 

333 C{before} the first point. For C{fraction > 1.0} 

334 the closest point is after the second point. 

335 ''' 

336 _Names_ = (_closest_, _fraction_) 

337 _Units_ = (_Pass, _Pass) 

338 

339 

340class NearestOn3Tuple(_NamedTuple): # .points.py, .sphericalTrigonometry 

341 '''3-Tuple C{(closest, distance, angle)} of the C{closest} 

342 point on the polygon, either a C{LatLon} instance or a 

343 L{LatLon3Tuple}C{(lat, lon, height)} and the C{distance} 

344 and C{angle} to the C{closest} point are in C{meter} 

345 respectively compass C{degrees360}. 

346 ''' 

347 _Names_ = (_closest_, _distance_, _angle_) 

348 _Units_ = (_Pass, Meter, Degrees) 

349 

350 

351# NearestOn4Tuple DEPRECATED, see .deprecated.classes.NearestOn4Tuple 

352 

353 

354class NearestOn5Tuple(_NamedTuple): 

355 '''5-Tuple C{(lat, lon, distance, angle, height)} all in C{degrees}, 

356 except C{height}. The C{distance} is the L{pygeodesy.equirectangular} 

357 distance between the closest and the reference B{C{point}} in C{degrees}. 

358 The C{angle} from the reference B{C{point}} to the closest point is in 

359 compass C{degrees360}, see function L{pygeodesy.compassAngle}. The 

360 C{height} is the (interpolated) height at the closest point in C{meter} 

361 or C{0}. 

362 ''' 

363 _Names_ = (_lat_, _lon_, _distance_, _angle_, _height_) 

364 _Units_ = ( Lat, Lon, Degrees, Degrees, Meter) 

365 

366 

367class NearestOn6Tuple(_NamedTuple): # .latlonBase.py, .vector3d.py 

368 '''6-Tuple C{(closest, distance, fi, j, start, end)} with the C{closest} 

369 point, the C{distance} in C{meter}, conventionally and the C{start} 

370 and C{end} point of the path or polygon edge. Fractional index C{fi} 

371 (an L{FIx} instance) and index C{j} indicate the path or polygon edge 

372 and the fraction along that edge with the C{closest} point. The 

373 C{start} and C{end} points may differ from the given path or polygon 

374 points at indices C{fi} respectively C{j}, when unrolled (C{wrap} is 

375 C{True}). Also, the C{start} and/or C{end} point may be the same 

376 instance as the C{closest} point, for example when the very first 

377 path or polygon point is the nearest. 

378 ''' 

379 _Names_ = (_closest_, _distance_, _fi_, _j_, _start_, _end_) 

380 _Units_ = (_Pass, Meter, FIx, Number_, _Pass , _Pass) 

381 

382 

383class NearestOn8Tuple(_NamedTuple): # .ellipsoidalBaseDI 

384 '''8-Tuple C{(closest, distance, fi, j, start, end, initial, final)}, 

385 like L{NearestOn6Tuple} but extended with the C{initial} and the 

386 C{final} bearing at the reference respectively the C{closest} 

387 point, both in compass C{degrees}. 

388 ''' 

389 _Names_ = NearestOn6Tuple._Names_ + Distance3Tuple._Names_[-2:] 

390 _Units_ = NearestOn6Tuple._Units_ + Distance3Tuple._Units_[-2:] 

391 

392 

393class PhiLam2Tuple(_NamedTuple): # .frechet, .hausdorff, .latlonBase, .points, .vector3d 

394 '''2-Tuple C{(phi, lam)} with latitude C{phi} in C{radians[PI_2]} 

395 and longitude C{lam} in C{radians[PI]}. 

396 

397 @note: Using C{phi/lambda} for lat-/longitude in C{radians} 

398 follows Chris Veness' U{convention 

399 <https://www.Movable-Type.co.UK/scripts/latlong.html>}. 

400 ''' 

401 _Names_ = (_phi_, _lam_) 

402 _Units_ = ( Phi, Lam) 

403 

404 def to3Tuple(self, height, **name): 

405 '''Extend this L{PhiLam2Tuple} to a L{PhiLam3Tuple}. 

406 

407 @arg height: The height to add (C{scalar}). 

408 @kwarg name: Optional C{B{name}=NN} (C{str}), 

409 overriding this name. 

410 

411 @return: A L{PhiLam3Tuple}C{(phi, lam, height)}. 

412 

413 @raise ValueError: Invalid B{C{height}}. 

414 ''' 

415 return self._xtend(PhiLam3Tuple, height, **name) 

416 

417 def to4Tuple(self, height, datum): 

418 '''Extend this L{PhiLam2Tuple} to a L{PhiLam4Tuple}. 

419 

420 @arg height: The height to add (C{scalar}). 

421 @arg datum: The datum to add (C{Datum}). 

422 

423 @return: A L{PhiLam4Tuple}C{(phi, lam, height, datum)}. 

424 

425 @raise TypeError: If B{C{datum}} not a C{Datum}. 

426 

427 @raise ValueError: Invalid B{C{height}}. 

428 ''' 

429 return self.to3Tuple(height).to4Tuple(datum) 

430 

431 

432class PhiLam3Tuple(_NamedTuple): # .nvector.py, extends -2Tuple 

433 '''3-Tuple C{(phi, lam, height)} with latitude C{phi} in 

434 C{radians[PI_2]}, longitude C{lam} in C{radians[PI]} and 

435 C{height} in C{meter}. 

436 

437 @note: Using C{phi/lambda} for lat-/longitude in C{radians} 

438 follows Chris Veness' U{convention 

439 <https://www.Movable-Type.co.UK/scripts/latlong.html>}. 

440 ''' 

441 _Names_ = (_phi_, _lam_, _height_) 

442 _Units_ = ( Phi, Lam, Height) 

443 

444 def to4Tuple(self, datum, **name): 

445 '''Extend this L{PhiLam3Tuple} to a L{PhiLam4Tuple}. 

446 

447 @arg datum: The datum to add (C{Datum}). 

448 @kwarg name: Optional C{B{name}=NN} (C{str}), 

449 overriding this name. 

450 

451 @return: A L{PhiLam4Tuple}C{(phi, lam, height, datum)}. 

452 

453 @raise TypeError: If B{C{datum}} not a C{Datum}. 

454 ''' 

455 _xinstanceof(_MODS.datums.Datum, datum=datum) 

456 return self._xtend(PhiLam4Tuple, datum, **name) 

457 

458 

459class PhiLam4Tuple(_NamedTuple): # extends -3Tuple 

460 '''4-Tuple C{(phi, lam, height, datum)} with latitude C{phi} in 

461 C{radians[PI_2]}, longitude C{lam} in C{radians[PI]}, C{height} 

462 in C{meter} and L{Datum}. 

463 

464 @note: Using C{phi/lambda} for lat-/longitude in C{radians} 

465 follows Chris Veness' U{convention 

466 <https://www.Movable-Type.co.UK/scripts/latlong.html>}. 

467 ''' 

468 _Names_ = (_phi_, _lam_, _height_, _datum_) 

469 _Units_ = ( Phi, Lam, Height, _Pass) 

470 

471 

472class Point3Tuple(_NamedTuple): 

473 '''3-Tuple C{(x, y, ll)} in C{meter}, C{meter} and C{LatLon}. 

474 ''' 

475 _Names_ = (_x_, _y_, _elel_) 

476 _Units_ = ( Meter, Meter, _Pass) 

477 

478 

479class Points2Tuple(_NamedTuple): # .formy, .latlonBase 

480 '''2-Tuple C{(number, points)} with the C{number} of points 

481 and -possible reduced- C{list} or C{tuple} of C{points}. 

482 ''' 

483 _Names_ = (_number_, _points_) 

484 _Units_ = ( Number_, _Pass) 

485 

486 

487class Reverse4Tuple(_NamedTuple, _Convergence): 

488 '''4-Tuple C{(lat, lon, gamma, scale)} with C{lat}- and 

489 C{lon}gitude in C{degrees}, meridian convergence C{gamma} 

490 at point in C{degrees} and the C{scale} of projection at 

491 point C{scalar}. 

492 ''' 

493 _Names_ = (_lat_, _lon_, _gamma_, _scale_) 

494 _Units_ = ( Lat, Lon, Degrees, Scalar) 

495 

496 

497class Triangle7Tuple(_NamedTuple): 

498 '''7-Tuple C{(A, a, B, b, C, c, area)} with interior angles C{A}, 

499 C{B} and C{C} in C{degrees}, spherical sides C{a}, C{b} and C{c} 

500 in C{meter} conventionally and the C{area} of a (spherical) 

501 triangle in I{square} C{meter} conventionally. 

502 ''' 

503 _Names_ = (_A_, _a_, _B_, _b_, _C_, _c_, _area_) 

504 _Units_ = ( Degrees, Meter, Degrees, Meter, Degrees, Meter, Meter2) 

505 

506 

507class Triangle8Tuple(_NamedTuple): 

508 '''8-Tuple C{(A, a, B, b, C, c, D, E)} with interior angles C{A}, 

509 C{B} and C{C}, spherical sides C{a}, C{b} and C{c}, the I{spherical 

510 deficit} C{D} and the I{spherical excess} C{E} of a (spherical) 

511 triangle, all in C{radians}. 

512 ''' 

513 _Names_ = (_A_, _a_, _B_, _b_, _C_, _c_, _D_, _E_) 

514 _Units_ = ( Radians, Radians, Radians, Radians, Radians, Radians, Radians, Radians) 

515 

516 

517class Trilaterate5Tuple(_NamedTuple): # .latlonBase, .nvector 

518 '''5-Tuple C{(min, minPoint, max, maxPoint, n)} with C{min} and C{max} 

519 in C{meter}, the corresponding trilaterated C{minPoint} and C{maxPoint} 

520 as C{LatLon} and the number C{n}. For area overlap, C{min} and C{max} 

521 are the smallest respectively largest overlap found. For perimeter 

522 intersection, C{min} and C{max} represent the closest respectively 

523 farthest intersection margin. Count C{n} is the total number of 

524 trilaterated overlaps or intersections found, C{0, 1, 2...6} with 

525 C{0} meaning concentric. 

526 

527 @see: The C{ellipsoidalKarney-}, C{ellipsoidalVincenty-} and 

528 C{sphericalTrigonometry.LatLon.trilaterate5} method for further 

529 details on corner cases, like concentric or single trilaterated 

530 results. 

531 ''' 

532 _Names_ = (min.__name__, 'minPoint', max.__name__, 'maxPoint', _n_) 

533 _Units_ = (Meter, _Pass, Meter, _Pass, Number_) 

534 

535 

536class UtmUps2Tuple(_NamedTuple): # .epsg.py 

537 '''2-Tuple C{(zone, hemipole)} as C{int} and C{str}, where 

538 C{zone} is C{1..60} for UTM or C{0} for UPS and C{hemipole} 

539 C{'N'|'S'} is the UTM hemisphere or the UPS pole. 

540 ''' 

541 _Names_ = (_zone_, _hemipole_) 

542 _Units_ = ( Number_, Str) 

543 

544 

545class UtmUps5Tuple(_NamedTuple): # .mgrs.py, .ups.py, .utm.py, .utmups.py 

546 '''5-Tuple C{(zone, hemipole, easting, northing, band)} as C{int}, 

547 C{str}, C{meter}, C{meter} and C{band} letter, where C{zone} is 

548 C{1..60} for UTM or C{0} for UPS, C{hemipole} C{'N'|'S'} is the UTM 

549 hemisphere or the UPS pole and C{band} is C{""} or the I{longitudinal} 

550 UTM band C{'C'|'D'|..|'W'|'X'} or I{polar} UPS band C{'A'|'B'|'Y'|'Z'}. 

551 ''' 

552 _Names_ = (_zone_, _hemipole_, _easting_, _northing_, _band_) 

553 _Units_ = ( Number_, Str, Easting, Northing, Band) 

554 

555 def __new__(cls, z, h, e, n, B, Error=None, **name): 

556 if Error is not None: 

557 e = Easting( e, Error=Error) 

558 n = Northing(n, Error=Error) 

559 return _NamedTuple.__new__(cls, z, h, e, n, B, **name) 

560 

561 

562class UtmUps8Tuple(_NamedTuple, _Convergence): # .ups, .utm, .utmups 

563 '''8-Tuple C{(zone, hemipole, easting, northing, band, datum, 

564 gamma, scale)} as C{int}, C{str}, C{meter}, C{meter}, C{band} 

565 letter, C{Datum}, C{degrees} and C{scalar}, where C{zone} is 

566 C{1..60} for UTM or C{0} for UPS, C{hemipole} C{'N'|'S'} is 

567 the UTM hemisphere or the UPS pole and C{band} is C{""} or 

568 the I{longitudinal} UTM band C{'C'|'D'|..|'W'|'X'} or 

569 I{polar} UPS band C{'A'|'B'|'Y'|'Z'}. 

570 ''' 

571 _Names_ = (_zone_, _hemipole_, _easting_, _northing_, 

572 _band_, _datum_, _gamma_, _scale_) 

573 _Units_ = ( Number_, Str, Easting, Northing, 

574 Band, _Pass, Degrees, Scalar) 

575 

576 def __new__(cls, z, h, e, n, B, d, g, s, Error=None, **name): # PYCHOK 11 args 

577 if Error is not None: 

578 e = Easting( e, Error=Error) 

579 n = Northing(n, Error=Error) 

580 g = Degrees(gamma=g, Error=Error) 

581 s = Scalar(scale=s, Error=Error) 

582 return _NamedTuple.__new__(cls, z, h, e, n, B, d, g, s, **name) 

583 

584 

585class UtmUpsLatLon5Tuple(_NamedTuple): # .ups.py, .utm.py, .utmups.py 

586 '''5-Tuple C{(zone, band, hemipole, lat, lon)} as C{int}, 

587 C{str}, C{str}, C{degrees90} and C{degrees180}, where 

588 C{zone} is C{1..60} for UTM or C{0} for UPS, C{band} is 

589 C{""} or the I{longitudinal} UTM band C{'C'|'D'|..|'W'|'X'} 

590 or I{polar} UPS band C{'A'|'B'|'Y'|'Z'} and C{hemipole} 

591 C{'N'|'S'} is the UTM hemisphere or the UPS pole. 

592 ''' 

593 _Names_ = (_zone_, _band_, _hemipole_, _lat_, _lon_) 

594 _Units_ = ( Number_, Band, Str, Lat, Lon) 

595 

596 def __new__(cls, z, B, h, lat, lon, Error=None, **name): 

597 if Error is not None: 

598 lat = Lat(lat, Error=Error) 

599 lon = Lon(lon, Error=Error) 

600 return _NamedTuple.__new__(cls, z, B, h, lat, lon, **name) 

601 

602 

603class Vector2Tuple(_NamedTuple): 

604 '''2-Tuple C{(x, y)} of (geocentric) components, each in 

605 C{meter} or the same C{units}. 

606 ''' 

607 _Names_ = (_x_, _y_) 

608 _Units_ = ( Scalar, Scalar) 

609 

610 def to3Tuple(self, z=INT0, **name): 

611 '''Extend this L{Vector2Tuple} to a L{Vector3Tuple}. 

612 

613 @kwarg z: The Z component add (C{scalar}). 

614 @kwarg name: Optional C{B{name}=NN} (C{str}), 

615 overriding this name. 

616 

617 @return: A L{Vector3Tuple}C{(x, y, z)}. 

618 

619 @raise ValueError: Invalid B{C{z}}. 

620 ''' 

621 return self._xtend(Vector3Tuple, z, **name) 

622 

623 

624class Vector3Tuple(_NamedTuple): 

625 '''3-Tuple C{(x, y, z)} of (geocentric) components, all in 

626 C{meter} or the same C{units}. 

627 ''' 

628 _Names_ = (_x_, _y_, _z_) 

629 _Units_ = ( Scalar, Scalar, Scalar) 

630 

631 def to4Tuple(self, h=INT0, **name): 

632 '''Extend this L{Vector3Tuple} to a L{Vector4Tuple}. 

633 

634 @arg h: The height to add (C{scalar}). 

635 @kwarg name: Optional C{B{name}=NN} (C{str}), 

636 overriding this name. 

637 

638 @return: A L{Vector4Tuple}C{(x, y, z, h)}. 

639 

640 @raise ValueError: Invalid B{C{h}}. 

641 ''' 

642 return self._xtend(Vector4Tuple, h, **name) 

643 

644 @property_RO 

645 def xyz(self): 

646 '''Get X, Y and Z components (C{Vector3Tuple}). 

647 ''' 

648 return self 

649 

650 

651class Vector4Tuple(_NamedTuple): # .nvector.py 

652 '''4-Tuple C{(x, y, z, h)} of (geocentric) components, all 

653 in C{meter} or the same C{units}. 

654 ''' 

655 _Names_ = (_x_, _y_, _z_, _h_) 

656 _Units_ = ( Scalar, Scalar, Scalar, Height) 

657 

658 def to3Tuple(self): 

659 '''Reduce this L{Vector4Tuple} to a L{Vector3Tuple}. 

660 

661 @return: A L{Vector3Tuple}C{(x, y, z)}. 

662 ''' 

663 return self.xyz 

664 

665 @property_RO 

666 def xyz(self): 

667 '''Get X, Y and Z components (L{Vector3Tuple}). 

668 ''' 

669 return Vector3Tuple(*self[:3]) 

670 

671# **) MIT License 

672# 

673# Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved. 

674# 

675# Permission is hereby granted, free of charge, to any person obtaining a 

676# copy of this software and associated documentation files (the "Software"), 

677# to deal in the Software without restriction, including without limitation 

678# the rights to use, copy, modify, merge, publish, distribute, sublicense, 

679# and/or sell copies of the Software, and to permit persons to whom the 

680# Software is furnished to do so, subject to the following conditions: 

681# 

682# The above copyright notice and this permission notice shall be included 

683# in all copies or substantial portions of the Software. 

684# 

685# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 

686# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

687# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 

688# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 

689# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 

690# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 

691# OTHER DEALINGS IN THE SOFTWARE.