From 0f47be3a9f0c3373461bfa7832ad9487d1baa869 Mon Sep 17 00:00:00 2001 From: "Tammo.Weber" Date: Tue, 16 Dec 2025 16:31:24 +0100 Subject: [PATCH] Berechnungsverfahren und Darstellung --- dashborad.py | 368 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 250 insertions(+), 118 deletions(-) diff --git a/dashborad.py b/dashborad.py index cb72040..971cf70 100644 --- a/dashborad.py +++ b/dashborad.py @@ -4,9 +4,11 @@ import plotly.graph_objects as go import numpy as np from GHA_triaxial.panou import gha1_ana +from GHA_triaxial.panou import gha1_num from GHA_triaxial.panou_2013_2GHA_num import gha2_num from ellipsoide import EllipsoidTriaxial import winkelumrechnungen as wu +import ausgaben as aus app = Dash(__name__, suppress_callback_exceptions=True) @@ -16,72 +18,11 @@ app.title = "Geodätische Hauptaufgaben" def abplattung(a, b): return (a - b) / a -def ellipsoid_figure(ax, ay, b, pts=None, lines=None, title="Dreiachsiges Ellipsoid"): - u = np.linspace(-np.pi/2, np.pi/2, 80) - v = np.linspace(-np.pi, np.pi, 160) - U, V = np.meshgrid(u, v) - X = ax * np.cos(U) * np.cos(V) - Y = ay * np.cos(U) * np.sin(V) - Z = b * np.sin(U) - +def ellipsoid_figure(ell: EllipsoidTriaxial, title="Dreiachsiges Ellipsoid"): fig = go.Figure() - fig.add_trace(go.Surface( - x=X, y=Y, z=Z, showscale=False, opacity=0.7, - surfacecolor=np.zeros_like(X), - colorscale=[[0, "rgb(200,220,255)"], [1, "rgb(200,220,255)"]], - name="Ellipsoid" - )) - meridians_deg = np.arange(0, 360, 15) - lat_line = np.linspace(-np.pi/2, np.pi/2, 240) - for lon_deg in meridians_deg: - lam = np.deg2rad(lon_deg) - phi = lat_line - xm = ax * np.cos(phi) * np.cos(lam) - ym = ay * np.cos(phi) * np.sin(lam) - zm = b * np.sin(phi) - fig.add_trace(go.Scatter3d( - x=xm, y=ym, z=zm, mode="lines", - line=dict(width=1, color="black"), - showlegend=False - )) - parallels_deg = np.arange(-75, 90, 15) - lon_line = np.linspace(0, 2*np.pi, 360) - for lat_deg in parallels_deg: - phi = np.deg2rad(lat_deg) - lam = lon_line - xp = ax * np.cos(phi) * np.cos(lam) - yp = ay * np.cos(phi) * np.sin(lam) - zp = b * np.sin(phi) * np.ones_like(lam) - fig.add_trace(go.Scatter3d( - x=xp, y=yp, z=zp, mode="lines", - line=dict(width=1, color="black"), - showlegend=False - )) - - if pts: - for name, (px, py, pz), color in pts: - fig.add_trace(go.Scatter3d( - x=[px], y=[py], z=[pz], - mode="markers+text", - marker=dict(size=6, color=color), - text=[name], textposition="top center", - name=name, showlegend=False - )) - - if lines: - for (p1, p2) in lines: - xline = [p1[0], p2[0]] - yline = [p1[1], p2[1]] - zline = [p1[2], p2[2]] - fig.add_trace(go.Scatter3d( - x=xline, y=yline, z=zline, - mode="lines", - line=dict(width=4, color="red"), - showlegend=False - )) - - rx, ry, rz = 1.05*ax, 1.05*ay, 1.05*b + # Darstellung + rx, ry, rz = 1.05*ell.ax, 1.05*ell.ay, 1.05*ell.b fig.update_layout( title=title, scene=dict( @@ -92,11 +33,127 @@ def ellipsoid_figure(ax, ay, b, pts=None, lines=None, title="Dreiachsiges Ellips ), margin=dict(l=0, r=0, t=40, b=0), ) + + # Ellipsoid + u = np.linspace(-np.pi/2, np.pi/2, 80) + v = np.linspace(-np.pi, np.pi, 160) + U, V = np.meshgrid(u, v) + X, Y, Z = ell.para2cart(U, V) + fig.add_trace(go.Surface( + x=X, y=Y, z=Z, showscale=False, opacity=0.7, + surfacecolor=np.zeros_like(X), + colorscale=[[0, "rgb(200,220,255)"], [1, "rgb(200,220,255)"]], + name="Ellipsoid" + )) + + return fig + +def figure_constant_lines(fig, ell: EllipsoidTriaxial, coordsystem: str = "para"): + if coordsystem == "para": + constants_u = wu.deg2rad(np.arange(0, 360, 15)) + all_v = np.linspace(-np.pi / 2, np.pi / 2, 361) + for u in constants_u: + xm, ym, zm = ell.para2cart(u, all_v) + fig.add_trace(go.Scatter3d( + x=xm, y=ym, z=zm, mode="lines", + line=dict(width=1, color="black"), + showlegend=False + )) + + all_u = np.linspace(0, 2 * np.pi, 361) + constants_v = wu.deg2rad(np.arange(-75, 90, 15)) + for v in constants_v: + x, y, z = ell.para2cart(all_u, v) + fig.add_trace(go.Scatter3d( + x=x, y=y, z=z, mode="lines", + line=dict(width=1, color="black"), + showlegend=False + )) + + elif coordsystem == "ell": + constants_beta = wu.deg2rad(np.arange(-75, 90, 15)) + all_lamb = np.linspace(0, 2 * np.pi, 361) + for beta in constants_beta: + xyz = ell.ell2cart(beta, all_lamb) + fig.add_trace(go.Scatter3d( + x=xyz[:, 0], y=xyz[:, 1], z=xyz[:, 2], mode="lines", + line=dict(width=1, color="black"), + showlegend=False + )) + + all_beta = np.linspace(-np.pi / 2, np.pi / 2, 361) + constants_lamb = wu.deg2rad(np.arange(0, 360, 15)) + for lamb in constants_lamb: + xyz = ell.ell2cart(all_beta, lamb) + fig.add_trace(go.Scatter3d( + x=xyz[:, 0], y=xyz[:, 1], z=xyz[:, 2], mode="lines", + line=dict(width=1, color="black"), + showlegend=False + )) + + elif coordsystem == "geod": + constants_phi = wu.deg2rad(np.arange(-75, 90, 15)) + all_lamb = np.linspace(0, 2 * np.pi, 361) + for phi in constants_phi: + x, y, z = ell.geod2cart(phi, all_lamb, 0) + fig.add_trace(go.Scatter3d( + x=x, y=y, z=z, mode="lines", + line=dict(width=1, color="black"), + showlegend=False + )) + + all_phi = np.linspace(-np.pi / 2, np.pi / 2, 361) + constants_lamb = wu.deg2rad(np.arange(0, 360, 15)) + for lamb in constants_lamb: + x, y, z = ell.geod2cart(all_phi, lamb, 0) + fig.add_trace(go.Scatter3d( + x=x, y=y, z=z, mode="lines", + line=dict(width=1, color="black"), + showlegend=False + )) + + return fig + +def figure_points(fig, points): + """ + + :param fig: plotly.graph_objects.Figure + :param points: Punktliste [(name, (x,y,z), color)] + :return: plotly.graph_objects.Figure + """ + for name, (px, py, pz), color in points: + fig.add_trace(go.Scatter3d( + x=[px], y=[py], z=[pz], + mode="markers+text", + marker=dict(size=6, color=color), + text=[name], textposition="top center", + name=name, showlegend=False + )) + return fig + +def figure_lines(fig, lines): + """ + + :param fig: plotly.graph_objects.Figure + :param lines: Linienliste [((x1,y1,z1), (x2,y2,z2), color)] + :return: plotly.graph_objects.Figure + """ + for (p1, p2, color) in lines: + xline = [p1[0], p2[0]] + yline = [p1[1], p2[1]] + zline = [p1[2], p2[2]] + fig.add_trace(go.Scatter3d( + x=xline, y=yline, z=zline, + mode="lines", + line=dict(width=4, color=color), + showlegend=False + )) return fig + app.layout = html.Div( - style={"fontFamily": "Arial", "margin": "40px"}, + style={"fontFamily": "Arial", "padding": "5px", "width": "70%", "margin-left": "auto"}, children=[ html.H1("Geodätische Hauptaufgaben"), html.H2("für dreiachsige Ellipsoide"), @@ -111,7 +168,8 @@ app.layout = html.Div( {"label": "Eitschberger1978", "value": "Eitschberger1978"}, {"label": "Bursa1972", "value": "Bursa1972"}, {"label": "Bursa1970", "value": "Bursa1970"}, - {"label": "Bessel-biaxial", "value": "Bessel-biaxial"}, + {"label": "BesselBiaxial", "value": "BesselBiaxial"}, + {"label": "Fiction", "value": "Fiction"}, #{"label": "Ei", "value": "Ei"}, ], value="", @@ -122,24 +180,27 @@ app.layout = html.Div( dcc.Input( id="input-1", type="number", - placeholder="ax...", + min=0, + placeholder="ax...[m]", style={"marginBottom": "10px", "display": "block", "width": "300px"}, ), dcc.Input( id="input-2", type="number", - placeholder="ay...", + min=0, + placeholder="ay...[m]", style={"marginBottom": "10px", "display": "block", "width": "300px"}, ), dcc.Input( id="input-3", type="number", - placeholder="b...", + min=0, + placeholder="b...[m]", style={"marginBottom": "20px", "display": "block", "width": "300px"}, ), html.Button( - "Ellipsoid Berechnen", + "Ellipsoid berechnen", id="calc-ell", n_clicks=0, style={"marginRight": "10px", "marginBottom": "20px"}, @@ -174,11 +235,9 @@ app.layout = html.Div( html.P( "© 2025", style={ - "margin": 0, "fontSize": "12px", "color": "gray", "textAlign": "center", - "padding": "5px 0", }, ), ], @@ -207,14 +266,18 @@ def fill_inputs_from_dropdown(selected_ell): Output("output-area", "children"), Input("calc-ell", "n_clicks"), State("input-1", "value"), + State("input-2", "value"), State("input-3", "value"), ) -def update_output(n_clicks, ax, b): - if not n_clicks or ax is None or b is None: +def update_output(n_clicks, ax, ay, b): + if not n_clicks: return "" - f = abplattung(ax, b) - return f"Abplattung f = {f:.10e}" - + if n_clicks and ax is None or ay is None or b is None: + return html.Span("Bitte Ellipsoid auswählen!", style={"color": "red"}) + if ay >= ax or b >= ay or ax <= 0 or ay <= 0 or b <= 0: + return html.Span("Eingabe inkorrekt.", style={"color": "red"}) + ell = EllipsoidTriaxial(ax, ay, b) + return f"ex = {round(ell.ex, 6)}, ", f"ey = {round(ell.ey, 6)}, ", f"ee = {round(ell.ee, 6)}" @app.callback( Output("tabs-GHA-out", "children"), @@ -226,13 +289,13 @@ def render_content(tab): pane_gha1 = html.Div( [ - dcc.Input(id="input-GHA1-beta1", type="number", placeholder="β1...[°]", + dcc.Input(id="input-GHA1-beta1", type="number", min=-90, max=90, placeholder="β1...[°]", style={"marginBottom": "20px", "display": "block", "width": "300px"}), - dcc.Input(id="input-GHA1-lamb1", type="number", placeholder="λ1...[°]", + dcc.Input(id="input-GHA1-lamb1", type="number", min=-180, max=180, placeholder="λ1...[°]", style={"marginBottom": "20px", "display": "block", "width": "300px"}), - dcc.Input(id="input-GHA1-s", type="number", placeholder="s...[m]", + dcc.Input(id="input-GHA1-s", type="number", min=0, placeholder="s...[m]", style={"marginBottom": "20px", "display": "block", "width": "300px"}), - dcc.Input(id="input-GHA1-a", type="number", placeholder="α...[°]", + dcc.Input(id="input-GHA1-a", type="number", min=0, max=360, placeholder="α...[°]", style={"marginBottom": "20px", "display": "block", "width": "300px"}), dcc.Checklist( @@ -263,19 +326,18 @@ def render_content(tab): pane_gha2 = html.Div( [ - dcc.Input(id="input-GHA2-beta1", type="number", placeholder="β1...[°]", + dcc.Input(id="input-GHA2-beta1", type="number", min=-90, max=90, placeholder="β1...[°]", style={"marginBottom": "20px", "display": "block", "width": "300px"}), - dcc.Input(id="input-GHA2-lamb1", type="number", placeholder="λ1...[°]", + dcc.Input(id="input-GHA2-lamb1", type="number", min=-180, max=180, placeholder="λ1...[°]", style={"marginBottom": "20px", "display": "block", "width": "300px"}), - dcc.Input(id="input-GHA2-beta2", type="number", placeholder="β2...[°]", + dcc.Input(id="input-GHA2-beta2", type="number", min=-90, max=90, placeholder="β2...[°]", style={"marginBottom": "20px", "display": "block", "width": "300px"}), - dcc.Input(id="input-GHA2-lamb2", type="number", placeholder="λ2...[°]", + dcc.Input(id="input-GHA2-lamb2", type="number", min=-180, max=180, placeholder="λ2...[°]", style={"marginBottom": "20px", "display": "block", "width": "300px"}), dcc.Checklist( id="method-checklist-2", options=[ - {"label": "Analytisch", "value": "analytisch"}, {"label": "Numerisch", "value": "numerisch"}, {"label": "Stochastisch (ES)", "value": "stochastisch"}, ], @@ -315,25 +377,31 @@ def render_content(tab): State("input-GHA2-lamb1", "value"), State("input-GHA2-beta2", "value"), State("input-GHA2-lamb2", "value"), - State("my-dropdown", "value"), + State("input-1", "value"), + State("input-2", "value"), + State("input-3", "value"), + State("method-checklist-1", "value"), + State("method-checklist-2", "value"), + prevent_initial_call=True, ) def calc_and_plot(n1, n2, beta11, lamb11, s, a_deg, - beta1, lamb1, beta2, lamb2, - ell_name): + beta21, lamb21, beta22, lamb22, + ax, ay, b, method1, method2): if not (n1 or n2): return no_update, no_update, no_update - if not ell_name: - return "Bitte Ellipsoid wählen.", "", go.Figure() + if not ax or not ay or not b: + return html.Span("Bitte Ellipsoid auswählen!", style={"color": "red"}), "", go.Figure() - ell = EllipsoidTriaxial.init_name(ell_name) + ell = EllipsoidTriaxial(ax, ay, b) if dash.ctx.triggered_id == "button-calc-gha1": if None in (beta11, lamb11, s, a_deg): - return "Bitte β₁, λ₁, s und α eingeben.", "", go.Figure() + + return html.Span("Bitte β₁, λ₁, s und α eingeben.", style={"color": "red"}), "", go.Figure() beta_rad = wu.deg2rad(float(beta11)) lamb_rad = wu.deg2rad(float(lamb11)) @@ -341,40 +409,104 @@ def calc_and_plot(n1, n2, s_val = float(s) p1 = tuple(map(float, ell.ell2cart(beta_rad, lamb_rad))) + out1 = [] - x2, y2, z2 = gha1_ana(ell, p1, alpha_rad, s_val, 70) - p2 = (float(x2), float(y2), float(z2)) + if "analytisch" in method1: + # ana + x2, y2, z2 = gha1_ana(ell, p1, alpha_rad, s_val, 70) + p2_ana = (float(x2), float(y2), float(z2)) + beta2, lamb2 = ell.cart2ell([x2, y2, z2]) - fig = ellipsoid_figure( - ell.ax, ell.ay, ell.b, - pts=[("P1", p1, "black"), ("P2", p2, "red")], - lines=[(p1, p2)], - title="Erste Hauptaufgabe - analystisch" - ) + #out1 += f"kartesisch: x₂={p2[0]:.5f} m, y₂={p2[1]:.5f} m, z₂={p2[2]:.5f} m; ellipsoidisch: {aus.gms("β₂", beta2, 5)}, {aus.gms("λ₂", lamb2, 5)}," + out1.append( + html.Div([ + html.Strong("Analytisch: "), + html.Br(), + html.Span(f"kartesisch: x₂={x2:.4f} m, y₂={y2:.4f} m, z₂={z2:.4f} m"), + html.Br(), + html.Span(f"ellipsoidisch: {aus.gms('β₂', beta2, 4)}, {aus.gms('λ₂', lamb2, 4)}") + ]) + ) - out1 = f"x₂={p2[0]:.3f}, y₂={p2[1]:.3f}, z₂={p2[2]:.3f}" + if "numerisch" in method1: + # num + #p2_num = gha1_num(ell, p1, alpha_rad, s_val, 1000) + p2_num = 5 + + #out1 += f" {p2_num}" + out1.append( + html.Div([ + html.Strong("Numerisch: "), + html.Span(f"{p2_num}") + ]) + ) + + if "stochastisch" in method1: + # stoch + p2_stoch = "noch nicht implementiert.." + + out1.append( + html.Div([ + html.Strong("Stochastisch (ES): "), + html.Span(f"{p2_stoch}") + ]) + ) + + if not method1: + return html.Span("Bitte Berechnungsverfahren auswählen!", style={"color": "red"}), "", go.Figure() + + fig = ellipsoid_figure(ell, title="Erste Hauptaufgabe - analystisch") + #fig = figure_constant_lines(fig, ell, "geod") + fig = figure_constant_lines(fig, ell, "ell") + #fig = figure_constant_lines(fig, ell, "para") + fig = figure_points(fig, [("P1", p1, "black"), ("P2", p2_ana, "red")]) + fig = figure_lines(fig, [(p1, p2_ana, "red")]) + + #out1 = f"kartesisch: x₂={p2[0]:.5f} m, y₂={p2[1]:.5f} m, z₂={p2[2]:.5f} m; ellipsoidisch: {aus.gms("β₂", beta2, 5)}, {aus.gms("λ₂", lamb2, 5)}, {p2_num}" return out1, "", fig if dash.ctx.triggered_id == "button-calc-gha2": - if None in (beta1, lamb1, beta2, lamb2): - return "", "Bitte β₁, λ₁, β₂, λ₂ eingeben.", go.Figure() + if None in (beta21, lamb21, beta22, lamb22): + return html.Span("Bitte β₁, λ₁, β₂, λ₂ eingeben.", style={"color": "red"}), "", go.Figure() - alpha_1, alpha_2, s12 = gha2_num( - ell, - np.deg2rad(float(beta1)), np.deg2rad(float(lamb1)), - np.deg2rad(float(beta2)), np.deg2rad(float(lamb2)) - ) + p1 = tuple(ell.ell2cart(np.deg2rad(float(beta21)), np.deg2rad(float(lamb21)))) + p2 = tuple(ell.ell2cart(np.deg2rad(float(beta22)), np.deg2rad(float(lamb22)))) - p1 = tuple(ell.ell2cart(np.deg2rad(float(beta1)), np.deg2rad(float(lamb1)))) - p2 = tuple(ell.ell2cart(np.deg2rad(float(beta2)), np.deg2rad(float(lamb2)))) + out2 = [] - fig = ellipsoid_figure( - ell.ax, ell.ay, ell.b, - pts=[("P1", p1, "black"), ("P2", p2, "red")], - lines=[(p1, p2)], - title=f"Zweite Hauptaufgabe - numerisch" - ) - out2 = f"a₁₂={np.rad2deg(alpha_1):.6f}°, a₂₁={np.rad2deg(alpha_2):.6f}°, s={s12:.4f} m" + if "numerisch" in method2: + alpha_1, alpha_2, s12 = gha2_num( + ell, + np.deg2rad(float(beta21)), np.deg2rad(float(lamb21)), + np.deg2rad(float(beta22)), np.deg2rad(float(lamb22)) + ) + + out2.append( + html.Div([ + html.Strong("Numerisch: "), + html.Span(f"{aus.gms('α₁₂', alpha_1, 4)}, {aus.gms('α₂₁', alpha_2, 4)}, s = {s12:.4f} m"), + ]) + ) + + if "stochastisch" in method2: + # stoch + a_stoch = "noch nicht implementiert.." + + out2.append( + html.Div([ + html.Strong("Stochastisch (ES): "), + html.Span(f"{a_stoch}") + ]) + ) + + if not method2: + return html.Span("Bitte Berechnungsverfahren auswählen!", style={"color": "red"}), "", go.Figure() + + fig = ellipsoid_figure(ell, title="Zweite Hauptaufgabe") + fig = figure_constant_lines(fig, ell, "ell") + fig = figure_points(fig, [("P1", p1, "black"), ("P2", p2, "red")]) + fig = figure_lines(fig, [(p1, p2, "red")]) + return "", out2, fig return no_update, no_update, no_update