Coverage for pybelbg / belbgs.py: 96%

226 statements  

« prev     ^ index     » next       coverage.py v7.14.0, created at 2026-08-21 15:07 -0400

1 

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

3 

4u'''Main classes L{Be08LBG}, L{Be72LBG}, L{Be72NLBG}, L{Be72RLBG} and L{Be50LBG} implementing 

5the C{Belgian Lambert 2018}, C{-1972}, C{-1972N}, C{-1972R} respectively C{-1950} conic projection 

6and quasi-geoid heights with bilinear interpolation from C{Belgian hybrid quasi-geoid} U{hBG18 

7<https://DOI.org/10.5880/isg.2018.003>}. 

8 

9Each of the 5 classes provides a C{forward} method to transform a geodetic lat-, longitude and 

10(ellipsoidal) height to local easting, northing and (orthometric) height and a C{reverse} method 

11for converting local to geodetic coordinates and (orthometric to ellipsoidal) height. 

12 

13All classes use the same hybrid quasi-geoid C{hBG18} C{region4} but slighly different C{bounds4} 

14for valid lat- and longitudes. Heights for points outside C{region4} are not interpolated and 

15are C{NAN} or throw a L{BeLBGError} exception. Likewise, lat-, longitudes I{below} C{bounds4} 

16and easting, northing I{below} C{bounds4(asLb)} are considered invalid and replaced with C{NAN} 

17or raise a L{BeLBGError}. 

18''' 

19# make sure int/int division yields float quotient in Py2- 

20from __future__ import division as _; del _ # noqa: E702 ; 

21 

22from pybelbg.__pygeodesy import (BeLBGError, BeLBG7Tuple, Lb4Tuple, 

23 _1_0, _3600_0, _isNAN, _name_, 

24 _ALL_DOCS, _ALL_OTHER, _FOR_DOCS, 

25 _isinside, _NamedBase, _NamedTuple) 

26from pybelbg.__pygeodesy import _COMMA_, _SPACE_ # PYCHOK used! 

27from pygeodesy import (typename, NAN, NN, # "consterns" 

28 Conics, Bounds4Tuple, LatLonNgeoid3Tuple, # lcc, namedTuples 

29 property_RO, property_ROver, # props 

30 Degrees, Easting, Height, Lat, Lon, Northing) # units 

31 

32from math import ceil, floor 

33 

34__all__ = () 

35__version__ = '26.08.18' 

36 

37_bounds__ = ' bounds ' 

38_forward_ = 'forward' 

39_outside__ = 'outside ' 

40_region4hBG = Bounds4Tuple(48.5, 1.0, 52.5, 7.0, name='hBG18 region ') # <https://EPSG.io/4937> 

41_reverse_ = 'reverse' 

42_Uccle_ = 'Uccle' # PYCHOK == _BelBGbase.Uccle.name 

43 

44 

45class _BeLBGbase(_NamedBase): 

46 '''(INTERNAL) C{Be*LBG} base class. 

47 ''' 

48 _bounds2 = None # overloaded 

49 _conic = None # overloaded 

50 _latD = Lat(latD=36 / _3600_0) # 36" in degrees 

51 _lonD = Lon(lonD=54 / _3600_0) # 54" in degrees 

52 _raiser = False 

53 

54 def __init__(self, datum=None, raiser=False, **name): 

55 '''New C{Be*LBG} transformer instance, optionally with a different C{conic}'s datum. 

56 

57 @kwarg datum: Conic's datum to use (C{pygeodesy.Datums}, I{ellipsoidal} only). 

58 @kwarg raiser: If C{True} raise a L{BeLBGError} for lat- or longitudes 

59 outside L{region4} or below L{bounds4} (C{bool}). 

60 @kwarg name: Optional name C{B{name}=NN} (C{str}). 

61 ''' 

62 if datum: 

63 c = self._conic.toDatum(datum) 

64 if self._conic is not c: 

65 self._conic = c 

66# E = self.datum.ellipsoid 

67# if not E.isOblate: 

68# raise BeLBGError(repr(E), txt='not oblate') 

69 if raiser: 

70 self.raiser = True 

71# T = self.datum.transform 

72# if not T.isunity: 

73# raise BeLBGError(repr(T), txt='not unity') 

74 if name: 

75 self.name = name # or typename(self) 

76 

77 def _as4Lb(self, t4, name=NN): 

78 # return C{t4} as L{Lb4Tuple} 

79 S, W, N, E = t4 

80 s, w, _ = self._forward3(False, S, W, None) 

81 n, e, _ = self._forward3(False, N, E, None) 

82 return Lb4Tuple(s, w, n, e, name=name or t4.name) 

83 

84 def _belowError(self, raiser, coords, bounds2): 

85 # throw a below bounds2 exception if requested 

86 if raiser or (raiser is None and self.raiser): 

87 raise BeLBGError(coords, txt=_outside__ + bounds2.toRepr()) 

88 return True 

89 

90 @property_RO 

91 def _bounds2Lb(self): # overwrite __class__._bounds2Lb 

92 # get lower-left of C{bounds4} as C{_Lb2Tuple} 

93 b = self.bounds4(True) 

94 b = _Lb2Tuple(b.minE, b.minN, name=b.name) 

95 self.__class__._bounds2Lb = b 

96 return b 

97 

98 def bounds4(self, asLb=False): 

99 '''Get the South, West, North and East bounds of this C{Lambert} conic projection. 

100 

101 @kwarg asLb: Use C{B{asLb}=True} for the bounds in local C{Lambert} easting and 

102 northing, otherwise in geodetic lat- and longitudes (C{bool}). 

103 

104 @return: A L{Bounds4Tuple}C{(latS, lonW, latN, lonE)} with (WGS84) geodetic lat- 

105 and longitudes in C{degrees} or an L{Lb4Tuple}C{(minE, minN, maxE, maxN)} 

106 in C{meter}. 

107 

108 @note: The C{bounds4} cover Belgium, Belgium's U{EEZ<http://MarineRegions.org/mrgid/3293>}, 

109 the Netherlands, the Netherlands' U{EEZ<http://MarineRegions.org/mrgid/5668>} 

110 and Luxemburg. 

111 ''' 

112 return self._bounds4Lb if asLb else self._bounds4 

113 

114 @property_ROver 

115 def _bounds4BeNeLux(self): 

116 # BeNeLux covering BE, BE EEZ, NL, NL EEZ and LU 

117 def _b4(swne): # <http://MarineRegions.org/mrgid/XXXX> 

118 return Bounds4Tuple(*swne.split(_COMMA_)).toUnits() 

119 

120 b = _b4('49 26 50.6N, 5 44 5.6E, 50 10 59.9N, 6 31 49.2E') # Lux <2233> 

121 b = _b4('50 45 5.8N, 3 21 31.3E, 53 33 38.5N, 7 13 37.9E').union(b) # Ne <15> 

122 b = _b4('51 19 48.6N, 2 32 21.6E, 55 45 54.0N, 7 12 37.0E').union(b) # Ne EEZ <5668> 

123 b = _b4('49 29 50.3N, 2 32 47.8E, 51 30 15.1N, 6 24 27.0E').union(b) # Be <14> 

124 b = _b4('51 2 23.1N, 2 14 18.0E, 51 52 34.0N, 4 24 7.3E').union(b) # Be EEZ <3293> 

125 # BeNeLux bounds (latS=49.447389, lonW=2.238333, latN=55.765, lonE=7.227194) 

126 return b.toUnits(name='BeNeLux' + _bounds__) 

127 

128 @property_RO 

129 def _bounds4(self): # overwrite class._bounds4 

130 # get C{bounds4} with lower-left adjusted upward 

131 s, w = self._bounds2 

132 S, W, N, E = self._bounds4BeNeLux 

133 n = typename(self) + _bounds__ 

134 b = Bounds4Tuple(max(s, S), max(w, W), N, E, name=n) 

135 self.__class__._bounds4 = b 

136 return b 

137 

138 @property_RO 

139 def _bounds4Lb(self): # overwrite class._bounds4Lb 

140 # get C{bounds4} as C{Lb4Tuple} 

141 b = self._as4Lb(self._bounds4) 

142 self.__class__._bounds4Lb = b 

143 return b 

144 

145 def _c_f_N_f6(self, lat, lon): 

146 # return (int(ceil), int(floor), Normalized less floor) of C{lat}) + \ 

147 # (int(ceil), int(floor), Normalized less floor) of C{lon}) 

148 S, W, _, _ = _region4hBG 

149 return _c_f_N_f3(lat, S, self._latD) + \ 

150 _c_f_N_f3(lon, W, self._lonD) 

151 

152 @property_RO 

153 def conic(self): 

154 '''Get the C{Lambert} conic (C{pygeodesy.Conic}). 

155 ''' 

156 return self._conic 

157 

158 @property_RO 

159 def datum(self): 

160 '''Get the C{Lambert} conic's datum (C{pygeodesy.Datum}). 

161 ''' 

162 return self.conic.datum 

163 

164 def _EasNor5(self, e, n, raiser=None, name=_reverse_): 

165 # return e, n, ... if non-NAN and not below bounds2Lb 

166 e, n = t = Easting(e), Northing(n) 

167 if _isNAN(e) or _isNAN(n): 

168 _NAN = True 

169 elif t < self._bounds2Lb: 

170 _NAN = self._belowError(raiser, t, self._bounds2Lb) 

171 else: 

172 _NAN = False 

173 return e, n, _NAN, raiser, name 

174 

175 def forward(self, lat, lon, height=0, **raiser_name): 

176 '''Convert geodetic C{(B{lat}, B{lon})} and (ellipsoidal) B{C{height}} 

177 to C{easting}, C{northing} and (orthometric) height C{H}. 

178 

179 @arg lat: Latitude (C{degrees}, geodetic). 

180 @arg lon: Longitude (C{degrees}, geodetic). 

181 @kwarg height: The (ellipsoidal) height (C{meter}, conventionally) or 

182 C{None} to ignore C{hBGh} interpolation. 

183 @kwarg raiser_name: Use C{B{raiser}=True} to raise a L{BeLBGError} if 

184 B{C{lat}} or B{C{lon}} is outside L{region4} or below 

185 L{bounds4}, overriding property C{raiser} (C{bool}) and 

186 optional C{B{name}='forward'} (C{str}). 

187 

188 @return: A L{BeLBG7Tuple}C{(easting, northing, H, lat, lon, height, beLBG)} 

189 with C{easting}, C{northing} and (orthometric) height C{H} in 

190 C{meter} or C{NAN} and C{beLBG} is this C{Be*LBG} instance. 

191 

192 @raise BeLBGError: If the point is outside the C{BG} region and property 

193 C{raiser is True} or keyword argument C{B{raiser}=True}. 

194 

195 @note: C{H}, C{easting} and C{northing} will all be C{NAN} if B{C{lat}} or 

196 B{C{lon}} is below this converter's L{bounds4}. 

197 

198 @note: Orthometric height C{(H = h - N)} euals ellipsoidal height C{h} 

199 less (hybrid quasi-) geoid height C{N}. 

200 ''' 

201 lat, lon, _NAN, raiser, name = self._LatLon5(lat, lon, **raiser_name) 

202 if _NAN: 

203 e = n = H = NAN 

204 else: 

205 e, n, H = self._forward3(raiser, lat, lon, height) 

206 return BeLBG7Tuple(e, n, H, lat, lon, height, self, name=name) 

207 

208 def _forward3(self, raiser, lat, lon, height): # in .__main__ 

209 # C{forward} core, returning C{(easting, northing, H)} 

210 H = NAN if height is None or _isNAN(height) else ( 

211 Height(height) - self._hBGh(lat, lon, raiser)) 

212 e, n, _ = self._conic.forward3(lat, lon) 

213 return e, n, H 

214 

215 def hBGh(self, lat, lon): 

216 '''Interpolate the hybrid quasi-geoid C{hBG} height for a geodetic point. 

217 

218 @arg lat: Latitude (C{degrees}, geodetic). 

219 @arg lon: Longitude (C{degrees}, geodetic). 

220 

221 @return: Hybrid quasi-geoid C{hBG} height C{N} (C{meter}) or C{NAN} 

222 if B{C{lat}} or B{C{lon}} is outside L{region4}. 

223 ''' 

224 lat, lon, _NAN, _, _ = self._LatLon5(lat, lon, False) 

225 return NAN if _NAN else self._hBGh(lat, lon) 

226 

227 def _hBGh(self, lat, lon, raiser=False): 

228 # interpolate C{N} at C{(lat, lon)} or C{NAN} if 

229 # outside or ... if _isNAN(lat) or _isNAN(lon) 

230 if _isinside(lat, lon, 0, _region4hBG): 

231 c_f_N_f6 = self._c_f_N_f6(lat, lon) 

232 N = _bilinear(self._hBG18, *c_f_N_f6) 

233 N = Height(N=N) 

234 elif raiser or (raiser is None and self._raiser): 

235 raise self._outsidError(lat, lon) 

236 else: 

237 N = NAN 

238 return N 

239 

240 def hBGh3(self, easting, northing): 

241 '''Interpolate the hybrid quasi-geoid C{hBG} height for a local point. 

242 

243 @arg easting: Easting (C{meter}, local). 

244 @arg northing: Northing (C{meter}, local). 

245 

246 @return: L{LatLonNgeoid3Tuple}C{(lat, lon, N)} with the (hybrid 

247 quasi-) geoid C{hBG} height C{N} in C{meter} or C{NAN} 

248 if C{lat} or C{lon} is outside C{region4}. 

249 ''' 

250 r = self.reverse(easting, northing, H=0, raiser=False) 

251 return LatLonNgeoid3Tuple(r.lat, r.lon, r.height, name=self.name) 

252 

253 @property_ROver 

254 def _hBG18(self): # load the hBG18 geoid, I{once} 

255 from pybelbg.hBG18 import _hBG18 as hBG 

256 S, W, N, E = _region4hBG 

257 assert int(_degN(N, S, self._latD) + _1_0) == len(hBG) 

258 assert int(_degN(E, W, self._lonD) + _1_0) == len(hBG) 

259 return hBG 

260 

261 def isinside(self, lat, lon, eps=0): 

262 '''Is geodetic C{(B{lat}, B{lon})} inside the C{hBG} region? 

263 

264 @arg lat: Latitude (C{degrees}, geodetic). 

265 @arg lon: Longitude (C{degrees}, geodetic). 

266 @kwarg eps: Over-/undersize the C{hBG} region (C{degrees}). 

267 

268 @return: C{None} if B{C{lat}} or B{C{lon}} is NAN, C{False} 

269 if outside the C{hBG} region, C{True} otherwise. 

270 

271 @see: Methods C{Bounds4Tuple.isinside} and L{Lb4Tuple.isinside}. 

272 ''' 

273 lat, lon, _NAN, _, _ = self._LatLon5(lat, lon, False) 

274 return None if _NAN else _isinside(lat, lon, Degrees(eps=eps), 

275 _region4hBG) 

276 

277 def _LatLon5(self, lat, lon, raiser=None, name=_forward_): 

278 # return lat, lon, ... if non-NAN and not below bounds2 

279 lat, lon = t = Lat(lat), Lon(lon) 

280 if _isNAN(lat) or _isNAN(lon): 

281 _NAN = True 

282 elif t < self._bounds2: 

283 _NAN = self._belowError(raiser, t, self._bounds2) 

284 else: 

285 _NAN = False 

286 return lat, lon, _NAN, raiser, name 

287 

288 def _outsidError(self, *lat_lon): 

289 # format an BeLBGError for C{lat_lon} outside the C{hBG} region 

290 return BeLBGError(lat_lon, txt=_outside__ + _region4hBG.toRepr()) 

291 

292 @property 

293 def raiser(self): 

294 '''Is an C{BeLBGError} thrown for points outside the C{hBG} region? 

295 ''' 

296 return self._raiser 

297 

298 @raiser.setter # PYCHOK setter! 

299 def raiser(self, raiser): 

300 '''Use C{True} to throw an C{BeLBGError} for points outside the C{hBG} region. 

301 ''' 

302 self._raiser = bool(raiser) 

303 

304 def region4(self, asLb=False): 

305 '''Get the South, West, North and East bounds of the C{hBG} region. 

306 

307 @kwarg asLb: Use C{B{asLb}=True} for the bounds in local C{Lambert} 

308 easting and northing, otherwise in geodetic lat- and 

309 longitudes (C{bool}). 

310 

311 @return: A L{Bounds4Tuple}C{(latS, lonW, latN, lonE)} with (WGS84) 

312 geodetic lat- and longitudes in C{degrees} or an 

313 L{Lb4Tuple}C{(minE, minN, maxE, maxN)} in C{meter}. 

314 

315 @note: The C{hBG} region covers all of Belgium, Luxemburg and the 

316 southern half of the Netherlands. 

317 ''' 

318 return self._region4Lb if asLb else _region4hBG 

319 

320 @property_RO 

321 def _region4Lb(self): # overwrite class._region4Lb 

322 n = _region4hBG.name.split() 

323 n = _SPACE_(typename(self), *n[1:]) 

324 r = self._as4Lb(_region4hBG, name=n) 

325 self.__class__._region4Lb = r 

326 return r 

327 

328 def reverse(self, easting, northing, H=0, **raiser_name): 

329 '''Convert local B{C{easting}}, B{C{northing}} and (orthometric) height 

330 B{C{H}} to geodetic C{lat-}, C{longitude} and (ellipsoidal) C{height}. 

331 

332 @arg easting: Easting (C{meter}, local). 

333 @arg northing: Northing (C{meter}, local). 

334 @kwarg H: The (orthometric) height (C{meter}, conventionally) or C{None} 

335 to ignore C{hBGh} interpolation. 

336 @kwarg raiser_name: Use C{B{raiser}=True} to raise a L{BeLBGError} for 

337 points outside L{region4} or below L{bounds4}, overriding 

338 property C{raiser} (C{bool}) and optional C{B{name}='reverse'} 

339 (C{str}). 

340 

341 @return: A L{BeLBG7Tuple}C{(easting, northing, H, lat, lon, height, beLBG)} 

342 with geodetic C{lat} and C{lon} and (ellipsoidal) C{height} in 

343 C{meter} or C{NAN} and C{beLBG} is this C{Be*LBG} instance. 

344 

345 @raise BeLBGError: If the point is outside the C{hBG} region and property 

346 C{raiser is True} or keyword argument C{B{raiser}=True}. 

347 

348 @note: All C{lon}, C{lat} and C{height} will be C{NAN} if B{C{easting}} or 

349 B{C{northing}} is below this converter's C{bounds4(asLb)}. 

350 

351 @note: Ellipsoidal height C{(h = H + N)} equals orthometric height C{H} 

352 plus (hybrid quasi-) geoid height C{N}. 

353 ''' 

354 e, n, _NAN, raiser, name = self._EasNor5(easting, northing, **raiser_name) 

355 if _NAN: 

356 lat = lon = height = NAN 

357 else: 

358 lat, lon, height = self._reverse3(raiser, e, n, H) 

359 return BeLBG7Tuple(e, n, H, lat, lon, height, self, name=name) 

360 

361 def _reverse3(self, raiser, e, n, H): # in .__main__ 

362 # C{reverse} core, returning C{(lat, lon, height)} 

363 lat, lon, _, _= self._conic.reverse4(e, n) 

364 height = NAN if H is None or _isNAN(H) else ( 

365 Height(H=H) + self._hBGh(lat, lon, raiser)) 

366 return lat, lon, height 

367 

368 def toStr(self, prec=9, **unused): # PYCHOK signature 

369 '''Return this C{Be*LBG} instance as a string. 

370 

371 @kwarg prec: Precision, number of decimal digits (C{int}, 0..9). 

372 

373 @return: This C{Be*LBG} (C{str}). 

374 ''' 

375 return self.attrs(_name_, 'conic', 'raiser', prec=prec) # _datum_, _Uccle_ 

376 

377 @property_RO 

378 def Uccle(self): # overwrite class.Uccle 

379 '''Get C{Uccle<https://ROBinfo.OMA.BE/en/astro-info/geographical-coordinates-of-our-sites>} (aka Ukkel) as L{BeLBG7Tuple}. 

380 ''' 

381 lat, lon, H = self._Uccle3 

382 h = self.hBGh(lat, lon) + H # height=147.815887 Be08LBG 

383 u = self.forward(lat, lon, height=h, name=_Uccle_) # Be08LBG easting=649250.118675, northing=665257.86004 

384 self.__class__.Uccle = u 

385 return u 

386 

387 @property_ROver 

388 def _Uccle3(self): 

389 # # lat=50.797778, lon=4.358111, H=104.9 

390 return Lat('50 47 52N'), Lon('4 21 29.2E'), Height(H=104.9) 

391 

392 

393class Be08LBG(_BeLBGbase): 

394 '''Belgian Lambert 2008 C{pygeodesy.Conics.Be08Lb} transformer. 

395 ''' 

396 @property_ROver 

397 def _conic(self): 

398 return Conics.Be08Lb 

399 

400 @property_ROver 

401 def _bounds2(self): 

402 return _bounds2(44.77, -3.82, self) 

403 

404 

405class Be72LBG(_BeLBGbase): 

406 '''Belgian Lambert 1972 C{pygeodesy.Conics.Be72Lb} transformer. 

407 ''' 

408 @property_ROver 

409 def _conic(self): 

410 return Conics.Be72Lb 

411 

412 @property_ROver 

413 def _bounds2(self): 

414 return _bounds2(49.30, 2.31, self) 

415 

416 

417class Be72NLBG(_BeLBGbase): 

418 '''Belgian Lambert 1972N C{pygeodesy.Conics.Be72NLb} transformer. 

419 ''' 

420 @property_ROver 

421 def _conic(self): 

422 return Conics.Be72NLb 

423 

424 @property_ROver 

425 def _bounds2(self): 

426 return _bounds2(49.31, 2.15, self) 

427 

428 

429class Be72RLBG(_BeLBGbase): 

430 '''Belgian Lambert 1972R C{pygeodesy.Conics.Be72RLb} transformer. 

431 ''' 

432 @property_ROver 

433 def _conic(self): 

434 return Conics.Be72RLb 

435 

436 @property_ROver 

437 def _bounds2(self): 

438 return _bounds2(49.21, 2.14, self) 

439 

440 

441class Be50LBG(_BeLBGbase): 

442 '''Belgian Lambert 1950 C{pygeodesy.Conics.Be50Lb} transformer. 

443 ''' 

444 @property_ROver 

445 def _conic(self): 

446 return Conics.Be50Lb 

447 

448 @property_ROver 

449 def _bounds2(self): 

450 return _bounds2(49.31, 5.26, self) 

451 

452 

453class _Bounds2Tuple(_NamedTuple): 

454 '''2-Tuple C{(latS, lonW)} lower-left corner. 

455 ''' 

456 _Names_ = Bounds4Tuple._Names_[:2] 

457 _Units_ = Bounds4Tuple._Units_[:2] 

458 

459 

460class _Lb2Tuple(_NamedTuple): 

461 '''2-Tuple C{(minE, minN)} lower-left corner. 

462 ''' 

463 _Names_ = Lb4Tuple._Names_[:2] 

464 _Units_ = Lb4Tuple._Units_[:2] 

465 

466 

467def _bilinear(hBG, c_latI, f_latI, latN_f, 

468 c_lonI, f_lonI, lonN_f): 

469 # interpolate hybrid quasi-geoid C{hBG} height 

470 Ne, nw = hBG(c_latI, c_lonI, f_lonI) 

471 if c_latI != f_latI or c_lonI != f_lonI: 

472 se, sw = hBG(f_latI, c_lonI, f_lonI) 

473 lonN_f1 = _1_0 - lonN_f # == 1 - (lonN - f_lonN) 

474 Ne = (Ne * lonN_f + nw * lonN_f1) * latN_f + \ 

475 (se * lonN_f + sw * lonN_f1) * (_1_0 - latN_f) 

476 return Ne 

477 

478 

479def _bounds2(latS, lonW, beLBG): 

480 # return the C{beLBG} lower-left bounds 

481 n = typename(beLBG) + _bounds__ 

482 return _Bounds2Tuple(latS, lonW, name=n) 

483 

484 

485def _c_f_N_f3(*deg_SWD): 

486 # return int(ceil) and int(floor) of Normalized 

487 # and (Normalized less floor) of C{deg} degrees 

488 N = _degN(*deg_SWD) 

489 # assert N >= 0, N 

490 f = floor(N) 

491 return int(ceil(N)), int(f), (N - f) 

492 

493 

494def _degN(deg, degSW, degD): 

495 # return C{deg} Normalized 

496 return (deg - degSW) / degD 

497 

498 

499_Be5LBGs = Be08LBG, Be72LBG, Be72NLBG, Be72RLBG, Be50LBG 

500 

501if _FOR_DOCS: # force epydoc to document all ... 

502 for B in _Be5LBGs: # ... public methods 

503 B.__init__ = _BeLBGbase.__init__ 

504 B.bounds4 = _BeLBGbase.bounds4 

505 B.conic = _BeLBGbase.conic 

506 B.datum = _BeLBGbase.datum 

507 B.forward = _BeLBGbase.forward 

508 B.hBGh = _BeLBGbase.hBGh 

509 B.hBGh3 = _BeLBGbase.hBGh3 

510 B.isinside = _BeLBGbase.isinside 

511 B.region4 = _BeLBGbase.region4 

512 B.reverse = _BeLBGbase.reverse 

513 

514__all__ += _ALL_DOCS(_BeLBGbase) 

515__all__ += _ALL_OTHER(Conics, LatLonNgeoid3Tuple, *_Be5LBGs) 

516del _ALL_DOCS, _ALL_OTHER, _Be5LBGs 

517 

518# **) MIT License 

519# 

520# Copyright (C) 2026-2026 -- mrJean1 at Gmail -- All Rights Reserved. 

521# 

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

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

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

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

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

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

528# 

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

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

531# 

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

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

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

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

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

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

538# OTHER DEALINGS IN THE SOFTWARE.