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 map1, _xinstanceof

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

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

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

15 _B_, _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

22 from pygeodesy.named import _NamedTuple, _Pass

23 from pygeodesy.props import deprecated_property_RO, property_RO

24 from 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__ = '23.12.07'

31

32# __DUNDER gets mangled in class

33_closest_ = 'closest'

34_destination_ = 'destination'

35_elel_ = 'll'

36_final_ = 'final'

37_fraction_ = 'fraction'

38

39

40 class 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

47 class 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

55 class 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

97 class 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

105 class 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

114 class 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

122 class 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

130 class 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

145 class 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

152 class 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

159 class _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

168 class 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

178 class 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

195 class 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 name (C{str}), overriding this name.

206

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

208

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

210 '''

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

212

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

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

215

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

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

218 @kwarg name: Optional name (C{str}), overriding this name.

219

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

221

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

223

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

225 '''

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

227

228

229 class LatLon3Tuple(_NamedTuple):

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

231 and C{meter}, conventionally.

232 '''

233 _Names_ = (_lat_, _lon_, _height_)

234 _Units_ = ( Lat, Lon, Height)

235

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

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

238

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

240 @kwarg name: Optional name (C{str}), overriding this name.

241

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

243

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

245 '''

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

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

248

249

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

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

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

253 '''

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

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

256

257

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

259 iteration=None, name=NN):

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

261 '''

262 if LatLon is None: # ignore LatLon_kwds

263 r = LatLon4Tuple(lat, lon, height, datum, name=name)

264 else:

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

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

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

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

269 kwds.update(datum=datum, height=height, name=name)

270 if LatLon_kwds:

271 kwds.update(LatLon_kwds)

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

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

274 r._iteration = iteration

275 return r

276

277

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

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

280 and L{Datum}.

281 '''

282 _Names_ = (_lat_, _lon_, _datum_)

283 _Units_ = ( Lat, Lon, _Pass)

284

285

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

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

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

289 '''

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

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

292

293

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

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

296 and C{int}.

297 '''

298 _Names_ = (_lat_, _lon_, _precision_)

299 _Units_ = ( Lat, Lon, Precision_)

300

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

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

303

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

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

306 @kwarg name: Optional name (C{str}), overriding this name.

307

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

309 height, radius)}.

310 '''

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

312

313

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

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

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

317 C{None} if missing).

318 '''

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

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

321

322

323 class NearestOn2Tuple(_NamedTuple): # .ellipsoidalBaseDI

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

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

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

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

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

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

330 the closest point is after the second point.

331 '''

332 _Names_ = (_closest_, _fraction_)

333 _Units_ = (_Pass, _Pass)

334

335

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

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

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

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

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

341 respectively compass C{degrees360}.

342 '''

343 _Names_ = (_closest_, _distance_, _angle_)

344 _Units_ = (_Pass, Meter, Degrees)

345

346

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

348

349

350 class NearestOn5Tuple(_NamedTuple):

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

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

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

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

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

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

357 or C{0}.

358 '''

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

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

361

362

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

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

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

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

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

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

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

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

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

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

373 path or polygon point is the nearest.

374 '''

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

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

377

378

379 class NearestOn8Tuple(_NamedTuple): # .ellipsoidalBaseDI

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

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

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

383 point, both in compass C{degrees}.

384 '''

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

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

387

388

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

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

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

392

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

394 follows Chris Veness' U{convention

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

396 '''

397 _Names_ = (_phi_, _lam_)

398 _Units_ = ( Phi, Lam)

399

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

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

402

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

404 @kwarg name: Optional name (C{str}), overriding this name.

405

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

407

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

409 '''

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

411

412 def to4Tuple(self, height, datum):

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

414

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

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

417

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

419

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

421

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

423 '''

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

425

426

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

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

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

430 C{height} in C{meter}.

431

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

433 follows Chris Veness' U{convention

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

435 '''

436 _Names_ = (_phi_, _lam_, _height_)

437 _Units_ = ( Phi, Lam, Height)

438

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

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

441

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

443 @kwarg name: Optional name (C{str}), overriding this name.

444

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

446

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

448 '''

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

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

451

452

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

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

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

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

457

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

459 follows Chris Veness' U{convention

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

461 '''

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

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

464

465

466 class Point3Tuple(_NamedTuple):

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

468 '''

469 _Names_ = (_x_, _y_, _elel_)

470 _Units_ = ( Meter, Meter, _Pass)

471

472

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

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

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

476 '''

477 _Names_ = (_number_, _points_)

478 _Units_ = ( Number_, _Pass)

479

480

481 class Reverse4Tuple(_NamedTuple, _Convergence):

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

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

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

485 point C{scalar}.

486 '''

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

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

489

490

491 class Triangle7Tuple(_NamedTuple):

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

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

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

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

496 '''

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

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

499

500

501 class Triangle8Tuple(_NamedTuple):

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

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

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

505 triangle, all in C{radians}.

506 '''

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

508 _Units_ = ( Radians, Radians, Radians, Radians, Radians, Radians, Radians, Radians)

509

510

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

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

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

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

515 are the smallest respectively largest overlap found. For perimeter

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

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

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

519 C{0} meaning concentric.

520

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

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

523 details on corner cases, like concentric or single trilaterated

524 results.

525 '''

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

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

528

529

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

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

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

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

534 '''

535 _Names_ = (_zone_, _hemipole_)

536 _Units_ = ( Number_, Str)

537

538

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

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

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

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

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

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

545 '''

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

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

548

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

550 if Error is not None:

551 e = Easting( e, Error=Error)

552 n = Northing(n, Error=Error)

553 return _NamedTuple.__new__(cls, z, h, e, n, B, name=name)

554

555

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

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

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

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

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

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

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

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

564 '''

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

566 _band_, _datum_, _gamma_, _scale_)

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

568 Band, _Pass, Degrees, Scalar)

569

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

571 if Error is not None:

572 e = Easting( e, Error=Error)

573 n = Northing(n, Error=Error)

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

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

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

577

578

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

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

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

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

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

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

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

586 '''

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

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

589

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

591 if Error is not None:

592 lat = Lat(lat, Error=Error)

593 lon = Lon(lon, Error=Error)

594 return _NamedTuple.__new__(cls, z, B, h, lat, lon, name=name)

595

596

597 class Vector2Tuple(_NamedTuple):

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

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

600 '''

601 _Names_ = (_x_, _y_)

602 _Units_ = ( Scalar, Scalar)

603

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

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

606

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

608 @kwarg name: Optional name (C{str}), overriding this name.

609

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

611

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

613 '''

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

615

616

617 class Vector3Tuple(_NamedTuple):

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

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

620 '''

621 _Names_ = (_x_, _y_, _z_)

622 _Units_ = ( Scalar, Scalar, Scalar)

623

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

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

626

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

628 @kwarg name: Optional name (C{str}), overriding this name.

629

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

631

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

633 '''

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

635

636 @property_RO

637 def xyz(self):

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

639 '''

640 return self

641

642

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

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

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

646 '''

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

648 _Units_ = ( Scalar, Scalar, Scalar, Height)

649

650 def to3Tuple(self):

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

652

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

654 '''

655 return self.xyz

656

657 @property_RO

658 def xyz(self):

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

660 '''

661 return Vector3Tuple(*self[:3])

662

663# **) MIT License

664#

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

666#

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

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

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

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

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

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

673#

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

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

676#

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

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

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

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

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

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

683# OTHER DEALINGS IN THE SOFTWARE.