import math from typing import Tuple import numpy as np from numpy import arccos, arctan, arctan2, cos, pi, sin, sqrt from numpy.typing import NDArray import jacobian_Ligas from utils_angle import wrap_mhalfpi_halfpi, wrap_mpi_pi class EllipsoidTriaxial: """ Klasse für dreiachsige Ellipsoide Parameter: Formparameter Funktionen: Koordinatenumrechnungen """ def __init__(self, ax: float, ay: float, b: float): self.ax = ax self.ay = ay self.b = b self.ex = sqrt((self.ax**2 - self.b**2) / self.ax**2) self.ey = sqrt((self.ay**2 - self.b**2) / self.ay**2) self.ee = sqrt((self.ax**2 - self.ay**2) / self.ax**2) self.ex_ = sqrt((self.ax**2 - self.b**2) / self.b**2) self.ey_ = sqrt((self.ay**2 - self.b**2) / self.b**2) self.ee_ = sqrt((self.ax**2 - self.ay**2) / self.ay**2) self.Ex = sqrt(self.ax**2 - self.b**2) self.Ey = sqrt(self.ay**2 - self.b**2) self.Ee = sqrt(self.ax**2 - self.ay**2) nenner = sqrt(max(self.ax * self.ax - self.b * self.b, 0.0)) self.k = sqrt(max(self.ay * self.ay - self.b * self.b, 0.0)) / nenner self.k_ = sqrt(max(self.ax * self.ax - self.ay * self.ay, 0.0)) / nenner self.e = sqrt(max(self.ax * self.ax - self.b * self.b, 0.0)) / self.ay @classmethod def init_name(cls, name: str) -> EllipsoidTriaxial: """ Mögliche Ellipsoide: BursaSima1980round, KarneyTest2024, Fiction, BursaFialova1993, BursaSima1980, Eitschberger1978, Bursa1972, Bursa1970 Panou et al (2020) :param name: Name des dreiachsigen Ellipsoids :return: dreiachsiger Ellipsoid """ if name == "BursaFialova1993": ax = 6378171.36 ay = 6378101.61 b = 6356751.84 return cls(ax, ay, b) elif name == "BursaSima1980": ax = 6378172 ay = 6378102.7 b = 6356752.6 return cls(ax, ay, b) elif name == "BursaSima1980round": # Panou 2013 ax = 6378172 ay = 6378103 b = 6356753 return cls(ax, ay, b) elif name == "Eitschberger1978": ax = 6378173.435 ay = 6378103.9 b = 6356754.4 return cls(ax, ay, b) elif name == "Bursa1972": ax = 6378173 ay = 6378104 b = 6356754 return cls(ax, ay, b) elif name == "Bursa1970": ax = 6378173 ay = 6378105 b = 6356754 return cls(ax, ay, b) elif name == "Fiction": ax = 6000000 ay = 4000000 b = 2000000 return cls(ax, ay, b) elif name == "KarneyTest2024": ax = sqrt(2) ay = 1 b = 1 / sqrt(2) return cls(ax, ay, b) else: raise Exception(f"EllipsoidTriaxial.init_name: Name {name} unbekannt") def func_H(self, point: NDArray) -> float: """ Berechnung H Panou, Korakitis 2019 [43] :param point: Punkt :return: H """ x, y, z = point return x ** 2 + y ** 2 / (1 - self.ee ** 2) ** 2 + z ** 2 / (1 - self.ex ** 2) ** 2 def func_n(self, point: NDArray, H: float = None) -> NDArray: """ Berechnung normalen Vektor Panou, Korakitis 2019 [9-12] :param point: Punkt :param H: :return: """ if H is None: H = self.func_H(point) sqrtH = sqrt(H) x, y, z = point return np.array([x / sqrtH, y / ((1 - self.ee ** 2) * sqrtH), z / ((1 - self.ex ** 2) * sqrtH)]) def func_t12(self, point: NDArray) -> Tuple[float, float]: """ Berechnung Wurzeln Panou, Korakitis 2019 [9-12] :param point: Punkt :return: Wurzeln t1, t2 """ x, y, z = point c1 = x ** 2 + y ** 2 + z ** 2 - (self.ax ** 2 + self.ay ** 2 + self.b ** 2) c0 = (self.ax ** 2 * self.ay ** 2 + self.ax ** 2 * self.b ** 2 + self.ay ** 2 * self.b ** 2 - (self.ay ** 2 + self.b ** 2) * x ** 2 - (self.ax ** 2 + self.b ** 2) * y ** 2 - ( self.ax ** 2 + self.ay ** 2) * z ** 2) if c1 ** 2 - 4 * c0 < -1e-9: raise Exception("t1, t2: Negativer Wurzelterm") elif c1 ** 2 - 4 * c0 < 0: t2 = 0 else: t2 = (-c1 + sqrt(c1 ** 2 - 4 * c0)) / 2 if t2 == 0: t2 = 1e-18 t1 = c0 / t2 return t1, t2 def ellu2cart(self, beta: float, lamb: float, u: float) -> NDArray: """ Panou 2014 12ff. :param beta: ellipsoidische Breite :param lamb: ellipsoidische Länge :param u: radiale Koordinate entlang der kleinen Halbachse :return: Punkt in kartesischen Koordinaten """ x = sqrt(u**2 + self.Ex**2) * sqrt(cos(beta)**2 + self.Ee**2/self.Ex**2 * sin(beta)**2) * cos(lamb) y = sqrt(u**2 + self.Ey**2) * cos(beta) * sin(lamb) z = u * sin(beta) * sqrt(1 - self.Ee**2/self.Ex**2 * cos(lamb)**2) return np.array([x, y, z]) def cart2ellu(self, point: NDArray) -> Tuple[float, float, float]: """ Panou 2014 15ff. :param point: Punkt in kartesischen Koordinaten :return: ellipsoidische Breite, ellipsoidische Länge, radiale Koordinate entlang der kleinen Halbachse """ x, y, z = point c2 = self.ax**2 + self.ay**2 + self.b**2 - x**2 - y**2 - z**2 c1 = (self.ax**2 * self.ay**2 + self.ax**2 * self.b**2 + self.ay**2 * self.b**2 - (self.ay**2+self.b**2) * x**2 - (self.ax**2 + self.b**2) * y**2 - (self.ax**2 + self.ay**2) * z**2) c0 = (self.ax**2 * self.ay**2 * self.b**2 - self.ay**2 * self.b**2 * x**2 - self.ax**2 * self.b**2 * y**2 - self.ax**2 * self.ay**2 * z**2) p = (c2**2 - 3*c1) / 9 q = (9*c1*c2 - 27*c0 - 2*c2**3) / 54 omega = arccos(q / sqrt(p**3)) s1 = 2 * sqrt(p) * cos(omega/3) - c2/3 s2 = 2 * sqrt(p) * cos(omega/3 - 2*pi/3) - c2/3 s3 = 2 * sqrt(p) * cos(omega/3 - 4*pi/3) - c2/3 beta = arctan(sqrt((-self.b**2 - s2) / (self.ay**2 + s2))) if abs((-self.ay**2 - s3) / (self.ax**2 + s3)) > 1e-7: lamb = arctan(sqrt((-self.ay**2 - s3) / (self.ax**2 + s3))) else: lamb = 0 u = sqrt(self.b**2 + s1) return beta, lamb, u def ell2cart(self, beta: float | NDArray, lamb: float | NDArray) -> NDArray: """ Panou, Korakitis 2019 2 :param beta: ellipsoidische Breite :param lamb: ellipsoidische Länge :return: Punkt in kartesischen Koordinaten """ beta = np.asarray(beta, dtype=float) lamb = np.asarray(lamb, dtype=float) beta, lamb = np.broadcast_arrays(beta, lamb) beta = np.where( np.isclose(np.abs(beta), pi / 2, atol=1e-15), beta * 8999999999999999 / 9000000000000000, beta ) B = self.Ex ** 2 * cos(beta) ** 2 + self.Ee ** 2 * sin(beta) ** 2 L = self.Ex ** 2 - self.Ee ** 2 * cos(lamb) ** 2 x = self.ax / self.Ex * sqrt(B) * cos(lamb) y = self.ay * cos(beta) * sin(lamb) z = self.b / self.Ex * sin(beta) * sqrt(L) xyz = np.stack((x, y, z), axis=-1) # Pole mask_south = beta == -pi / 2 mask_north = beta == pi / 2 xyz[mask_south] = np.array([0, 0, -self.b]) xyz[mask_north] = np.array([0, 0, self.b]) # Äquator mask_eq = beta == 0 xyz[mask_eq & (lamb == -pi / 2)] = np.array([0, -self.ay, 0]) xyz[mask_eq & (lamb == pi / 2)] = np.array([0, self.ay, 0]) xyz[mask_eq & (lamb == 0)] = np.array([self.ax, 0, 0]) xyz[mask_eq & (lamb == pi)] = np.array([-self.ax, 0, 0]) return xyz def ell2cart_bektas(self, beta: float | NDArray, omega: float | NDArray) -> NDArray: """ Bektas 2015 :param beta: ellipsoidische Breite :param omega: ellipsoidische Länge :return: Punkt in kartesischen Koordinaten """ x = self.ax * cos(omega) * sqrt((self.ax**2 - self.ay**2 * sin(beta)**2 - self.b**2 * cos(beta)**2) / (self.ax**2 - self.b**2)) y = self.ay * cos(beta) * sin(omega) z = self.b * sin(beta) * sqrt((self.ax**2 * sin(omega)**2 + self.ay**2 * cos(omega)**2 - self.b**2) / (self.ax**2 - self.b**2)) return np.array([x, y, z]) def ell2cart_karney(self, beta: float | NDArray, lamb: float | NDArray) -> NDArray: """ Karney 2025 Geographic Lib :param beta: ellipsoidische Breite :param lamb: ellipsoidische Länge :return: Punkt in kartesischen Koordinaten """ k = sqrt(self.ay**2 - self.b**2) / sqrt(self.ax**2 - self.b**2) k_ = sqrt(self.ax**2 - self.ay**2) / sqrt(self.ax**2 - self.b**2) X = self.ax * cos(lamb) * sqrt(k**2*cos(beta)**2+k_**2) Y = self.ay * cos(beta) * sin(lamb) Z = self.b * sin(beta) * sqrt(k**2 + k_**2 * sin(lamb)**2) return np.array([X, Y, Z]) def cart2ell_yFake(self, point: NDArray, delta_y: float = 1e-4) -> Tuple[float, float]: """ Bei Fehlschlagen von cart2ell :param point: Punkt in kartesischen Koordinaten :param delta_y: Startwert für Suche nach kleinstmöglichem delta_y :return: ellipsoidische Breite und Länge """ x, y, z = point best_delta = np.inf while True: try: y1 = y - delta_y beta1, lamb1 = self.cart2ell(np.array([x, y1, z]), noFake=True) point1 = self.ell2cart(beta1, lamb1) y2 = y + delta_y beta2, lamb2 = self.cart2ell(np.array([x, y2, z]), noFake=True) point2 = self.ell2cart(beta2, lamb2) pointM = (point1 + point2) / 2 actual_delta = np.linalg.norm(point - pointM) except: actual_delta = np.inf if actual_delta < best_delta: best_delta = actual_delta delta_y /= 10 else: delta_y *= 10 y1 = y - delta_y beta1, lamb1 = self.cart2ell(np.array([x, y1, z]), noFake=True) return beta1, lamb1 def cart2ell(self, point: NDArray, eps: float = 1e-12, maxI: int = 100, noFake: bool = False) -> Tuple[float, float]: """ Panou, Korakitis 2019 3f. (num) :param point: Punkt in kartesischen Koordinaten :param eps: zu erreichende Genauigkeit :param maxI: maximale Anzahl Iterationen :param noFake: y numerisch anpassen? :return: ellipsoidische Breite und Länge """ x, y, z = point beta, lamb = self.cart2ell_panou(point) delta_ell = np.array([np.inf, np.inf]).T tiny = 1e-30 try: i = 0 while np.linalg.norm(delta_ell) > eps and i < maxI: x0, y0, z0 = self.ell2cart(beta, lamb) delta_l = np.array([x-x0, y-y0, z-z0]).T B = max(self.Ex ** 2 * cos(beta) ** 2 + self.Ee ** 2 * sin(beta) ** 2, tiny) L = max(self.Ex ** 2 - self.Ee ** 2 * cos(lamb) ** 2, tiny) J = np.array([[(-self.ax * self.Ey ** 2) / (2 * self.Ex) * sin(2 * beta) / sqrt(B) * cos(lamb), -self.ax / self.Ex * sqrt(B) * sin(lamb)], [-self.ay * sin(beta) * sin(lamb), self.ay * cos(beta) * cos(lamb)], [self.b / self.Ex * cos(beta) * sqrt(L), (self.b * self.Ee ** 2) / (2 * self.Ex) * sin(beta) * sin(2 * lamb) / sqrt(L)]]) N = J.T @ J det = N[0, 0] * N[1, 1] - N[0, 1] * N[1, 0] N_inv = 1 / det * np.array([[N[1, 1], -N[0, 1]], [-N[1, 0], N[0, 0]]]) delta_ell = N_inv @ J.T @ delta_l # delta_ell, *_ = np.linalg.lstsq(J, delta_l, rcond=None) beta += delta_ell[0] lamb += delta_ell[1] i += 1 if i == maxI: raise Exception("Umrechnung cart2ell: nicht konvergiert") point_n = self.ell2cart(beta, lamb) delta_r = np.linalg.norm(point - point_n, axis=-1) if delta_r > 1e-6: raise Exception("Umrechnung cart2ell: Punktdifferenz") return wrap_mhalfpi_halfpi(beta), wrap_mpi_pi(lamb) except Exception as e: # Wenn die Berechnung fehlschlägt auf Grund von sehr kleinem y, solange anpassen, bis Umrechnung ohne Fehler delta_y = 10 ** math.floor(math.log10(abs(self.ay/1000))) if abs(y) < delta_y and not noFake: return self.cart2ell_yFake(point, delta_y) else: raise e def cart2ell_panou(self, point: NDArray) -> Tuple[float, float]: """ Panou, Korakitis 2019 2f. (analytisch -> Näherung) :param point: Punkt in kartesischen Koordinaten :return: ellipsoidische Breite und Länge """ x, y, z = point eps = 1e-9 if abs(x) < eps and abs(y) < eps: # Punkt in der z-Achse beta = pi / 2 if z > 0 else -pi / 2 lamb = 0.0 return beta, lamb elif abs(x) < eps and abs(z) < eps: # Punkt in der y-Achse beta = 0.0 lamb = pi / 2 if y > 0 else -pi / 2 return beta, lamb elif abs(y) < eps and abs(z) < eps: # Punkt in der x-Achse beta = 0.0 lamb = 0.0 if x > 0 else pi return beta, lamb # ---- Allgemeiner Fall ----- t1, t2 = self.func_t12(point) num_beta = max(t1 - self.b ** 2, 0) den_beta = max(self.ay ** 2 - t1, 1e-30) num_lamb = max(t2 - self.ay ** 2, 0) den_lamb = max(self.ax ** 2 - t2, 1e-30) beta = arctan(sqrt(num_beta / den_beta)) lamb = arctan(sqrt(num_lamb / den_lamb)) if z < 0: beta = -beta if y < 0: lamb = -lamb if x < 0: lamb = pi - lamb if abs(x) < eps: lamb = -pi/2 if y < 0 else pi/2 elif abs(y) < eps: lamb = 0 if x > 0 else pi elif abs(z) < eps: beta = 0 return beta, lamb def cart2ell_bektas(self, point: NDArray, eps: float = 1e-12, maxI: int = 100) -> Tuple[float, float]: """ Bektas 2015 :param point: Punkt in kartesischen Koordinaten :param eps: zu erreichende Genauigkeit :param maxI: maximale Anzahl Iterationen :return: ellipsoidische Breite und Länge """ x, y, z = point phi, lamb = self.cart2para(point) p = sqrt((self.ax**2 - self.ay**2) / (self.ax**2 - self.b**2)) d_phi = np.inf d_lamb = np.inf i = 0 while d_phi > eps and d_lamb > eps and i < maxI: lamb_new = arctan2(self.ax * y * sqrt((p**2-1) * sin(phi)**2 + 1), self.ay * x * cos(phi)) phi_new = arctan2(self.ay * z * sin(lamb), self.b * y * sqrt(1 - p**2 * cos(lamb)**2)) d_phi = abs(phi_new - phi) phi = phi_new d_lamb = abs(lamb_new - lamb) lamb = lamb_new i += 1 if i == maxI: raise Exception("Umrechnung cart2ell: nicht konvergiert") return phi, lamb def geod2cart(self, phi: float | NDArray, lamb: float | NDArray, h: float) -> NDArray: """ Ligas 2012, 250 :param phi: geodätische Breite :param lamb: geodätische Länge :param h: geodätische Höhe :return: kartesische Koordinaten """ v = self.ax / sqrt(1 - self.ex**2*sin(phi)**2-self.ee**2*cos(phi)**2*sin(lamb)**2) xG = (v + h) * cos(phi) * cos(lamb) yG = (v * (1-self.ee**2) + h) * cos(phi) * sin(lamb) zG = (v * (1-self.ex**2) + h) * sin(phi) return np.array([xG, yG, zG]) def cart2geod(self, point: NDArray, mode: str = "ligas3", maxIter: int = 30, maxLoa: float = 0.005) -> Tuple[float, float, float]: """ Ligas 2012 :param mode: ligas1, ligas2, oder ligas3 :param point: Punkt in kartesischen Koordinaten :param maxIter: maximale Anzahl Iterationen :param maxLoa: Level of Accuracy, das erreicht werden soll :return: geodätische Breite, Länge, Höhe """ xG, yG, zG = point eps = 1e-9 if abs(xG) < eps and abs(yG) < eps: # Punkt in der z-Achse phi = pi / 2 if zG > 0 else -pi / 2 lamb = 0.0 h = abs(zG) - self.b return phi, lamb, h elif abs(xG) < eps and abs(zG) < eps: # Punkt in der y-Achse phi = 0.0 lamb = pi / 2 if yG > 0 else -pi / 2 h = abs(yG) - self.ay return phi, lamb, h elif abs(yG) < eps and abs(zG) < eps: # Punkt in der x-Achse phi = 0.0 lamb = 0.0 if xG > 0 else pi h = abs(xG) - self.ax return phi, lamb, h rG = sqrt(xG ** 2 + yG ** 2 + zG ** 2) pE = np.array([self.ax * xG / rG, self.ax * yG / rG, self.ax * zG / rG], dtype=np.float64) E = 1 / self.ax**2 F = 1 / self.ay**2 G = 1 / self.b**2 i = 0 loa = np.inf while i < maxIter and loa > maxLoa: if mode == "ligas1": invJ, fxE = jacobian_Ligas.case1(E, F, G, np.array([xG, yG, zG]), pE) elif mode == "ligas2": invJ, fxE = jacobian_Ligas.case2(E, F, G, np.array([xG, yG, zG]), pE) elif mode == "ligas3": invJ, fxE = jacobian_Ligas.case3(E, F, G, np.array([xG, yG, zG]), pE) else: raise Exception(f"cart2geod: Modus {mode} nicht bekannt") pEi = pE.reshape(-1, 1) - invJ @ fxE.reshape(-1, 1) pEi = pEi.reshape(1, -1).flatten() loa = sqrt((pEi[0]-pE[0])**2 + (pEi[1]-pE[1])**2 + (pEi[2]-pE[2])**2) pE = pEi i += 1 if i == maxIter and loa > maxLoa: act_mode = int(mode[-1]) new_mode = 3 if act_mode == 1 else act_mode - 1 phi, lamb, h = self.cart2geod(point, f"ligas{new_mode}", maxIter, maxLoa) else: phi = arctan((1-self.ee**2) / (1-self.ex**2) * pE[2] / sqrt((1-self.ee**2)**2 * pE[0]**2 + pE[1]**2)) lamb = arctan(1/(1-self.ee**2) * pE[1]/pE[0]) h = np.sign(zG - pE[2]) * np.sign(pE[2]) * sqrt((pE[0] - xG) ** 2 + (pE[1] - yG) ** 2 + (pE[2] - zG) ** 2) if h < -self.ax: act_mode = int(mode[-1]) new_mode = 3 if act_mode == 1 else act_mode - 1 phi, lamb, h = self.cart2geod(point, f"ligas{new_mode}", maxIter, maxLoa) else: if xG < 0 and yG < 0: lamb += -pi elif xG < 0: lamb += pi if abs(zG) < eps: phi = 0 wrap_mhalfpi_halfpi(phi), wrap_mpi_pi(lamb) return wrap_mhalfpi_halfpi(phi), wrap_mpi_pi(lamb), h def para2cart(self, u: float | NDArray, v: float | NDArray) -> NDArray: """ Panou, Korakitits 2020, 4 :param u: parametrische Breite :param v: parametrische Länge :return: Punkt in kartesischen Koordinaten """ x = self.ax * cos(u) * cos(v) y = self.ay * cos(u) * sin(v) z = self.b * sin(u) z = np.broadcast_to(z, np.shape(x)) return np.array([x, y, z]) def cart2para(self, point: NDArray) -> Tuple[float, float]: """ Panou, Korakitits 2020, 4 :param point: Punkt in kartesischen Koordinaten :return: parametrische Breite, Länge """ x, y, z = point u_check1 = z*sqrt(1 - self.ee**2) u_check2 = sqrt(x**2 * (1-self.ee**2) + y**2) * sqrt(1-self.ex**2) if u_check1 <= u_check2: u = arctan2(u_check1, u_check2) else: u = pi/2 - arctan2(u_check2, u_check1) v_check1 = y v_check2 = x*sqrt(1-self.ee**2) v_factor = sqrt(x**2*(1-self.ee**2)+y**2) if v_check1 <= v_check2: v = 2 * arctan2(v_check1, v_check2 + v_factor) else: v = pi/2 - 2 * arctan2(v_check2, v_check1 + v_factor) wrap_mhalfpi_halfpi(u), wrap_mpi_pi(v) return wrap_mhalfpi_halfpi(u), wrap_mpi_pi(v) def ell2para(self, beta: float, lamb: float) -> Tuple[float, float]: """ Umrechung von ellipsoidischen in parametrische Koordinaten (über kartesische Koordinaten) :param beta: ellipsoidische Breite :param lamb: ellipsoidische Länge :return: parametrische Breite, Länge """ cart = self.ell2cart(beta, lamb) return self.cart2para(cart) def para2ell(self, u: float, v: float) -> Tuple[float, float]: """ Umrechung von parametrischen in ellipsoidische Koordinaten (über kartesische Koordinaten) :param u: parametrische Breite :param v: parametrische Länge :return: ellipsoidische Breite, Länge """ cart = self.para2cart(u, v) return self.cart2ell(cart) def para2geod(self, u: float, v: float, mode: str = "ligas3", maxIter: int = 30, maxLoa: float = 0.005) -> Tuple[float, float, float]: """ Umrechung von parametrischen in geodätische Koordinaten (über kartesische Koordinaten) :param u: parametrische Breite :param v: parametrische Länge :param mode: ligas1, ligas2, oder ligas3 :param maxIter: maximale Anzahl Iterationen :param maxLoa: Level of Accuracy, das erreicht werden soll :return: geodätische Breite, Länge, Höhe """ cart = self.para2cart(u, v) return self.cart2geod(cart, mode, maxIter, maxLoa) def geod2para(self, phi: float, lamb: float, h: float) -> Tuple[float, float]: """ Umrechung von geodätischen in parametrische Koordinaten (über kartesische Koordinaten) :param phi: geodätische Breite :param lamb: geodätische Länge :param h: geodätische Höhe :return: parametrische Breite, Länge """ cart = self.geod2cart(phi, lamb, h) return self.cart2para(cart) def ell2geod(self, beta: float, lamb: float, mode: str = "ligas3", maxIter: int = 30, maxLoa: float = 0.005) -> Tuple[float, float, float]: """ Umrechung von ellipsoidischen in geodätische Koordinaten (über kartesische Koordinaten) :param beta: ellipsoidische Breite :param lamb: ellipsoidische Länge :param mode: ligas1, ligas2, oder ligas3 :param maxIter: maximale Anzahl Iterationen :param maxLoa: Level of Accuracy, das erreicht werden soll :return: geodätische Breite, Länge, Höhe """ cart = self.ell2cart(beta, lamb) return self.cart2geod(cart, mode, maxIter, maxLoa) def geod2ell(self, phi: float, lamb: float, h: float) -> Tuple[float, float]: """ Umrechung von geodätischen in ellipsoidische Koordinaten (über kartesische Koordinaten) :param phi: geodätische Breite :param lamb: geodätische Länge :param h: geodätische Höhe :return: ellipsoidische Breite, Länge """ cart = self.geod2cart(phi, lamb, h) return self.cart2ell(cart) def point_on(self, point: NDArray) -> bool: """ Test, ob ein Punkt auf dem Ellipsoid liegt :param point: kartesische 3D-Koordinaten :return: Punkt auf dem Ellispoid? """ value = point[0]**2/self.ax**2 + point[1]**2/self.ay**2 + point[2]**2/self.b**2 if abs(1-value) < 1e-6: return True else: return False def point_onto_ellipsoid(self, point: NDArray) -> NDArray: """ Berechnung des Lotpunktes entlang der Normalkrümmung auf einem Ellipsoiden :param point: Punkt in kartesischen Koordinaten, der gelotet werden soll :return: Lotpunkt in kartesischen Koordinaten """ phi, lamb, h = self.cart2geod(point, "ligas3") p = self. geod2cart(phi, lamb, 0) return p def cart_ellh(self, point: NDArray, h: float) -> NDArray: """ Punkt auf Ellipsoid hoch loten :param point: Punkt auf dem Ellipsoid :param h: Höhe über dem Ellipsoid :return: hochgeloteter Punkt """ phi, lamb, _ = self.cart2geod(point, "ligas3") pointH = self. geod2cart(phi, lamb, h) return pointH if __name__ == "__main__": ell = EllipsoidTriaxial.init_name("KarneyTest2024") # cart = ell.ell2cart(pi/2, 0) # print(cart) # cart = ell.ell2cart(pi/2*8999999999999999/9000000000000000, 0) # print(cart) elli = ell.cart2ell(np.array([0, 0.0, 1/sqrt(2)])) print(elli) # ell = EllipsoidTriaxial.init_name("BursaSima1980") # diff_list = [] # diffs_para = [] # diffs_ell = [] # diffs_geod = [] # points = [] # for v_deg in range(-180, 181, 5): # for u_deg in range(-90, 91, 5): # v = wu.deg2rad(v_deg) # u = wu.deg2rad(u_deg) # point = ell.para2cart(u, v) # points.append(point) # # elli = ell.cart2ell(point) # cart_elli = ell.ell2cart(elli[0], elli[1]) # diff_ell = np.linalg.norm(point - cart_elli, axis=-1) # # para = ell.cart2para(point) # cart_para = ell.para2cart(para[0], para[1]) # diff_para = np.linalg.norm(point - cart_para, axis=-1) # # geod = ell.cart2geod(point, "ligas3") # cart_geod = ell.geod2cart(geod[0], geod[1], geod[2]) # diff_geod3 = np.linalg.norm(point - cart_geod, axis=-1) # # diff_list.append([v_deg, u_deg, diff_ell, diff_para, diff_geod3]) # diffs_ell.append([diff_ell]) # diffs_para.append([diff_para]) # diffs_geod.append([diff_geod3]) # # diff_list = np.array(diff_list) # diffs_ell = np.array(diffs_ell) # diffs_para = np.array(diffs_para) # diffs_geod = np.array(diffs_geod) # # pass # # points = np.array(points) # fig = plt.figure() # ax = fig.add_subplot(projection='3d') # # sc = ax.scatter( # points[:, 0], # points[:, 1], # points[:, 2], # c=diffs_ell, # Farbcode = diff # cmap='viridis', # Colormap # s=10 + 20 * diffs_ell, # optional: Größe abhängig vom diff # alpha=0.8 # ) # # # Farbskala # cbar = plt.colorbar(sc) # cbar.set_label("diff") # # ax.set_xlabel("X") # ax.set_ylabel("Y") # ax.set_zlabel("Z") # # plt.show()