1

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

3

4 u'''Named tuples.

5

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

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

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

9'''

10

11 from pygeodesy.basics import isinstanceof, map1, _xinstanceof

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

13# from pygeodesy.dms import toDMS # _MODS

14 from pygeodesy.errors import _xattr, _xkwds, _xkwds_not, _ALL_LAZY, _MODS

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

16 _band_, _c_, _C_, _D_, _datum_, _distance_, _E_, \

17 _easting_, _end_, _fi_, _gamma_, _h_, _height_, \

18 _hemipole_, _initial_, _j_, _lam_, _lat_, _lon_, \

19 _n_, _northing_, _number_, _outside_, _phi_, \

20 _point_, _precision_, _points_, _radius_, _scale_, \

21 _start_, _x_, _y_, _z_, _zone_

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

23 from pygeodesy.named import _NamedTuple, _Pass

24 from pygeodesy.props import deprecated_property_RO, property_RO

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

26 Height, Int, Lam, Lat, Lon, Meter, Meter2, \

27 Northing, Number_, Phi, Precision_, Radians, \

28 Radius, Scalar, Str, INT0

29

30__all__ = _ALL_LAZY.namedTuples

31__version__ = '24.06.08'

32

33# __DUNDER gets mangled in class

34_closest_ = 'closest'

35_destination_ = 'destination'

36_elel_ = 'll'

37_final_ = 'final'

38_fraction_ = 'fraction'

39

40

41 class Bearing2Tuple(_NamedTuple):

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

43 '''

44 _Names_ = (_initial_, _final_)

45 _Units_ = ( Bearing, Bearing)

46

47

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

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

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

51 '''

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

53 _Units_ = (_Pass, _Pass)

54

55

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

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

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

59 longitudes.

60 '''

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

62 _Units_ = ( Lat, Lon, Lat, Lon)

63

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

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

66

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

68 L{Bounds4Tuple} instance.

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

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

71

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

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

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

75 if not or zero if abutting.

76 '''

77 s, w, n, e = self

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

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

80

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

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

83

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

85 L{Bounds4Tuple} instance.

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

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

88

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

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

91 '''

92 s, w, n, e = self

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

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

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

96

97

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

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

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

101 '''

102 _Names_ = (_destination_, _final_)

103 _Units_ = (_Pass, Bearing)

104

105

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

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

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

109 in compass C{degrees360}.

110 '''

111 _Names_ = (_lat_, _lon_, _final_)

112 _Units_ = ( Lat, Lon, Bearing)

113

114

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

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

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

118 '''

119 _Names_ = (_distance_, _initial_)

120 _Units_ = ( Meter, Bearing)

121

122

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

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

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

126 '''

127 _Names_ = (_distance_, _initial_, _final_)

128 _Units_ = ( Meter, Bearing, Bearing)

129

130

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

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

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

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

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

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

137

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

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

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

141 '''

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

143 _Units_ = ( Degrees2, Degrees, Degrees, Degrees)

144

145

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

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

148 '''

149 _Names_ = (_easting_, _northing_)

150 _Units_ = ( Easting, Northing)

151

152

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

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

155 '''

156 _Names_ = (_easting_, _northing_, _height_)

157 _Units_ = ( Easting, Northing, Height)

158

159

160 class _Convergence(object):

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

162 @deprecated_property_RO

163 def convergence(self):

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

165 '''

166 return self.gamma # PYCHOK self[.]

167

168

169 class Forward4Tuple(_NamedTuple, _Convergence):

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

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

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

173 at point C{scalar}.

174 '''

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

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

177

178

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

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

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

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

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

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

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

186 path was specified with an initial bearing instead of an

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

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

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

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

191 '''

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

193 _Units_ = (_Pass, Int, Int)

194

195

196 class LatLon2Tuple(_NamedTuple):

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

198 '''

199 _Names_ = (_lat_, _lon_)

200 _Units_ = ( Lat, Lon)

201

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

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

204

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

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

207 this name.

208

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

210

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

212 '''

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

214

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

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

217

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

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

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

221 this name.

222

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

224

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

226

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

228 '''

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

230

231

232 class LatLon3Tuple(_NamedTuple):

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

234 and C{meter}, conventionally.

235 '''

236 _Names_ = (_lat_, _lon_, _height_)

237 _Units_ = ( Lat, Lon, Height)

238

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

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

241

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

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

244 this name.

245

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

247

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

249 '''

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

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

252

253

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

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

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

257 '''

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

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

260

261

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

263 iteration=None, **name):

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

265 '''

266 if LatLon is None: # ignore LatLon_kwds

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

268 else:

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

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

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

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

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

274 if LatLon_kwds:

275 kwds.update(LatLon_kwds)

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

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

278 r._iteration = iteration

279 return r

280

281

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

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

284 and L{Datum}.

285 '''

286 _Names_ = (_lat_, _lon_, _datum_)

287 _Units_ = ( Lat, Lon, _Pass)

288

289

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

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

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

293 '''

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

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

296

297

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

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

300 and C{int}.

301 '''

302 _Names_ = (_lat_, _lon_, _precision_)

303 _Units_ = ( Lat, Lon, Precision_)

304

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

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

307

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

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

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

311 this name.

312

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

314 height, radius)}.

315 '''

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

317

318

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

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

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

322 C{None} if missing).

323 '''

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

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

326

327

328 class _NamedTupleTo(_NamedTuple): # in .testNamedTuples

329 '''(INTERNAL) Base for C{-.toDegrees}, C{-.toRadians}.

330 '''

331 def _Degrees3(self, *xs, **toDMS_kwds):

332 '''(INTERNAL) Convert C{xs} from C{Radians} to C{Degrees} or C{toDMS}.

333 '''

334 if toDMS_kwds:

335 toDMS_kwds = _xkwds(toDMS_kwds, ddd=1, pos=NN)

336 toDMS, s = _MODS.dms.toDMS, None

337 else:

338 toDMS, s = None, self

339 for x in xs:

340 if not isinstanceof(x, Degrees):

341 x, s = x.toDegrees(), None

342 yield toDMS(x, **toDMS_kwds) if toDMS else x

343 yield s

344

345 def _Radians3(self, *xs, **unused):

346 '''(INTERNAL) Convert C{xs} from C{Degrees} to C{Radians}.

347 '''

348 s = self

349 for x in xs:

350 if not isinstanceof(x, Radians):

351 x, s = x.toRadians(), None

352 yield x

353 yield s

354

355

356 class NearestOn2Tuple(_NamedTuple): # .ellipsoidalBaseDI

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

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

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

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

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

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

363 the closest point is after the second point.

364 '''

365 _Names_ = (_closest_, _fraction_)

366 _Units_ = (_Pass, _Pass)

367

368

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

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

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

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

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

374 respectively compass C{degrees360}.

375 '''

376 _Names_ = (_closest_, _distance_, _angle_)

377 _Units_ = (_Pass, Meter, Degrees)

378

379

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

381

382

383 class NearestOn5Tuple(_NamedTuple):

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

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

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

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

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

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

390 or C{0}.

391 '''

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

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

394

395

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

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

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

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

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

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

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

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

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

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

406 path or polygon point is the nearest.

407 '''

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

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

410

411

412 class NearestOn8Tuple(_NamedTuple): # .ellipsoidalBaseDI

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

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

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

416 point, both in compass C{degrees}.

417 '''

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

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

420

421

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

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

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

425

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

427 follows Chris Veness' U{convention

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

429 '''

430 _Names_ = (_phi_, _lam_)

431 _Units_ = ( Phi, Lam)

432

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

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

435

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

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

438 overriding this name.

439

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

441

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

443 '''

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

445

446 def to4Tuple(self, height, datum):

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

448

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

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

451

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

453

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

455

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

457 '''

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

459

460

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

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

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

464 C{height} in C{meter}.

465

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

467 follows Chris Veness' U{convention

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

469 '''

470 _Names_ = (_phi_, _lam_, _height_)

471 _Units_ = ( Phi, Lam, Height)

472

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

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

475

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

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

478 overriding this name.

479

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

481

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

483 '''

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

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

486

487

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

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

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

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

492

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

494 follows Chris Veness' U{convention

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

496 '''

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

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

499

500

501 class Point3Tuple(_NamedTuple):

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

503 '''

504 _Names_ = (_x_, _y_, _elel_)

505 _Units_ = ( Meter, Meter, _Pass)

506

507

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

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

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

511 '''

512 _Names_ = (_number_, _points_)

513 _Units_ = ( Number_, _Pass)

514

515

516 class Reverse4Tuple(_NamedTuple, _Convergence):

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

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

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

520 point C{scalar}.

521 '''

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

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

524

525

526 class Triangle7Tuple(_NamedTuple):

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

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

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

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

531 '''

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

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

534

535

536 class Triangle8Tuple(_NamedTuple):

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

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

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

540 triangle, all in C{radians}.

541 '''

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

543 _Units_ = ( Radians, Radians, Radians, Radians, Radians, Radians, Radians, Radians)

544

545

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

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

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

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

550 are the smallest respectively largest overlap found. For perimeter

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

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

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

554 C{0} meaning concentric.

555

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

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

558 details on corner cases, like concentric or single trilaterated

559 results.

560 '''

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

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

563

564

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

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

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

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

569 '''

570 _Names_ = (_zone_, _hemipole_)

571 _Units_ = ( Number_, Str)

572

573

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

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

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

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

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

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

580 '''

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

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

583

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

585 if Error is not None:

586 e = Easting( e, Error=Error)

587 n = Northing(n, Error=Error)

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

589

590

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

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

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

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

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

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

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

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

599 '''

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

601 _band_, _datum_, _gamma_, _scale_)

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

603 Band, _Pass, Degrees, Scalar)

604

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

606 if Error is not None:

607 e = Easting( e, Error=Error)

608 n = Northing(n, Error=Error)

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

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

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

612

613

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

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

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

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

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

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

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

621 '''

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

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

624

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

626 if Error is not None:

627 lat = Lat(lat, Error=Error)

628 lon = Lon(lon, Error=Error)

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

630

631

632 class Vector2Tuple(_NamedTuple):

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

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

635 '''

636 _Names_ = (_x_, _y_)

637 _Units_ = ( Scalar, Scalar)

638

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

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

641

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

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

644 overriding this name.

645

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

647

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

649 '''

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

651

652

653 class Vector3Tuple(_NamedTuple):

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

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

656 '''

657 _Names_ = (_x_, _y_, _z_)

658 _Units_ = ( Scalar, Scalar, Scalar)

659

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

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

662

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

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

665 overriding this name.

666

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

668

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

670 '''

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

672

673 @property_RO

674 def xyz(self):

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

676 '''

677 return self

678

679

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

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

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

683 '''

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

685 _Units_ = ( Scalar, Scalar, Scalar, Height)

686

687 def to3Tuple(self):

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

689

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

691 '''

692 return self.xyz

693

694 @property_RO

695 def xyz(self):

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

697 '''

698 return Vector3Tuple(*self[:3])

699

700# **) MIT License

701#

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

703#

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

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

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

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

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

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

710#

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

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

713#

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

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

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

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

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

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

720# OTHER DEALINGS IN THE SOFTWARE.