Files
Masterprojekt/dashboard.py
2025-12-15 12:33:12 +01:00

438 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from dash import Dash, html, dcc, Input, Output, State, no_update
import dash
import plotly.graph_objects as go
import numpy as np
from GHA_triaxial.panou import gha1_ana
from GHA_triaxial.panou_2013_2GHA_num import gha2_num
from ellipsoide import EllipsoidTriaxial
import winkelumrechnungen as wu
app = Dash(__name__, suppress_callback_exceptions=True)
app.title = "Geodätische Hauptaufgaben"
def abplattung(a, b):
return (a - b) / a
def ellipsoid_figure(ell: EllipsoidTriaxial, title="Dreiachsiges Ellipsoid"):
fig = go.Figure()
# Darstellung
rx, ry, rz = 1.05*ell.ax, 1.05*ell.ay, 1.05*ell.b
fig.update_layout(
title=title,
scene=dict(
xaxis=dict(range=[-rx, rx], title="X [m]"),
yaxis=dict(range=[-ry, ry], title="Y [m]"),
zaxis=dict(range=[-rz, rz], title="Z [m]"),
aspectmode="data"
),
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"},
children=[
html.H1("Geodätische Hauptaufgaben"),
html.H2("für dreiachsige Ellipsoide"),
html.Label("Ellipsoid wählen:"),
dcc.Dropdown(
id="dropdown_ellispoid",
options=[
{"label": "BursaFialova1993", "value": "BursaFialova1993"},
{"label": "BursaSima1980", "value": "BursaSima1980"},
{"label": "BursaSima1980round", "value": "BursaSima1980round"},
{"label": "Eitschberger1978", "value": "Eitschberger1978"},
{"label": "Bursa1972", "value": "Bursa1972"},
{"label": "Bursa1970", "value": "Bursa1970"},
{"label": "Bessel-biaxial", "value": "Bessel-biaxial"},
{"label": "Fiction", "value": "Fiction"},
# {"label": "Ei", "value": "Ei"},
],
value="",
style={"width": "300px", "marginBottom": "20px"},
),
html.Label("Halbachsen:"),
dcc.Input(
id="input_ax",
type="number",
placeholder="ax...[m]",
style={"marginBottom": "10px", "display": "block", "width": "300px"},
),
dcc.Input(
id="input_ay",
type="number",
placeholder="ay...[m]",
style={"marginBottom": "10px", "display": "block", "width": "300px"},
),
dcc.Input(
id="input_b",
type="number",
placeholder="b...[m]",
style={"marginBottom": "20px", "display": "block", "width": "300px"},
),
html.Button(
"Ellipsoid Berechnen",
id="calc-ell",
n_clicks=0,
style={"marginRight": "10px", "marginBottom": "20px"},
),
html.Div(id="output-area", style={"marginBottom": "20px"}),
dcc.Tabs(
id="tabs-GHA",
value="tab-GHA1",
style={"marginRight": "10px", "marginBottom": "20px", "width": "50%"},
children=[
dcc.Tab(label="Erste Hauptaufgabe", value="tab-GHA1"),
dcc.Tab(label="Zweite Hauptaufgabe", value="tab-GHA2"),
],
),
html.Div(
id="tabs-GHA-out",
style={"marginRight": "10px", "marginBottom": "20px", "width": "50%"},
),
html.Div(id="output-gha1", style={"marginBottom": "20px"}),
html.Div(id="output-gha2", style={"marginBottom": "20px"}),
dcc.Graph(
id="ellipsoid-plot",
style={"height": "500px", "width": "700px"},
),
html.P(
"© 2025",
style={
"margin": 0,
"fontSize": "12px",
"color": "gray",
"textAlign": "center",
"padding": "5px 0",
},
),
],
)
@app.callback(
Output("input_ax", "value"),
Output("input_ay", "value"),
Output("input_b", "value"),
Input("dropdown_ellispoid", "value"),
)
def fill_inputs_from_dropdown(selected_ell):
if not selected_ell:
return None, None, None
ell = EllipsoidTriaxial.init_name(selected_ell)
ax = ell.ax
ay = ell.ay
b = ell.b
return ax, ay, b
@app.callback(
Output("output-area", "children"),
Input("calc-ell", "n_clicks"),
State("input_ax", "value"),
State("input_b", "value"),
)
def update_output(n_clicks, ax, b):
if not n_clicks or ax is None or b is None:
return ""
f = abplattung(ax, b)
return f"Abplattung f = {f:.10e}"
@app.callback(
Output("tabs-GHA-out", "children"),
Input("tabs-GHA", "value"),
)
def render_content(tab):
show1 = {"display": "block"} if tab == "tab-GHA1" else {"display": "none"}
show2 = {"display": "block"} if tab == "tab-GHA2" else {"display": "none"}
pane_gha1 = html.Div(
[
dcc.Input(id="input-GHA1-beta1", type="number", placeholder="β1...[°]",
style={"marginBottom": "20px", "display": "block", "width": "300px"}),
dcc.Input(id="input-GHA1-lamb1", type="number", placeholder="λ1...[°]",
style={"marginBottom": "20px", "display": "block", "width": "300px"}),
dcc.Input(id="input-GHA1-s", type="number", placeholder="s...[m]",
style={"marginBottom": "20px", "display": "block", "width": "300px"}),
dcc.Input(id="input-GHA1-a", type="number", placeholder="α...[°]",
style={"marginBottom": "20px", "display": "block", "width": "300px"}),
dcc.Checklist(
id="method-checklist-1",
options=[
{"label": "Analytisch", "value": "analytisch"},
{"label": "Numerisch", "value": "numerisch"},
{"label": "Stochastisch (ES)", "value": "stochastisch"},
],
value=[],
style={"marginBottom": "20px"},
),
html.Div(
[
html.Button(
"Berechnen",
id="button-calc-gha1",
n_clicks=0,
style={"marginRight": "10px"},
),
],
style={"marginBottom": "20px"},
),
],
id="pane-gha1",
style=show1,
)
pane_gha2 = html.Div(
[
dcc.Input(id="input-GHA2-beta1", type="number", placeholder="β1...[°]",
style={"marginBottom": "20px", "display": "block", "width": "300px"}),
dcc.Input(id="input-GHA2-lamb1", type="number", placeholder="λ1...[°]",
style={"marginBottom": "20px", "display": "block", "width": "300px"}),
dcc.Input(id="input-GHA2-beta2", type="number", placeholder="β2...[°]",
style={"marginBottom": "20px", "display": "block", "width": "300px"}),
dcc.Input(id="input-GHA2-lamb2", type="number", 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"},
],
value=[],
style={"marginBottom": "20px"},
),
html.Div(
[
html.Button(
"Berechnen",
id="button-calc-gha2",
n_clicks=0,
style={"marginRight": "10px"},
),
],
style={"marginBottom": "20px"},
),
],
id="pane-gha2",
style=show2,
)
return html.Div([pane_gha1, pane_gha2])
@app.callback(
Output("output-gha1", "children"),
Output("output-gha2", "children"),
Output("ellipsoid-plot", "figure"),
Input("button-calc-gha1", "n_clicks"),
Input("button-calc-gha2", "n_clicks"),
State("input-GHA1-beta1", "value"),
State("input-GHA1-lamb1", "value"),
State("input-GHA1-s", "value"),
State("input-GHA1-a", "value"),
State("input-GHA2-beta1", "value"),
State("input-GHA2-lamb1", "value"),
State("input-GHA2-beta2", "value"),
State("input-GHA2-lamb2", "value"),
State("dropdown_ellispoid", "value"),
prevent_initial_call=True,
)
def calc_and_plot(n1, n2,
beta11, lamb11, s, a_deg,
beta1, lamb1, beta2, lamb2,
ell_name):
if not (n1 or n2):
return no_update, no_update, no_update
if not ell_name:
return "Bitte Ellipsoid wählen.", "", go.Figure()
ell = EllipsoidTriaxial.init_name(ell_name)
if dash.ctx.triggered_id == "button-calc-gha1":
if None in (beta11, lamb11, s, a_deg):
return "Bitte β₁, λ₁, s und α eingeben.", "", go.Figure()
beta_rad = wu.deg2rad(float(beta11))
lamb_rad = wu.deg2rad(float(lamb11))
alpha_rad = wu.deg2rad(float(a_deg))
s_val = float(s)
p1 = tuple(map(float, ell.ell2cart(beta_rad, lamb_rad)))
x2, y2, z2 = gha1_ana(ell, p1, alpha_rad, s_val, 70)
p2 = (float(x2), float(y2), float(z2))
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, "red")])
fig = figure_lines(fig, [(p1, p2, "red")])
out1 = f"x₂={p2[0]:.3f}, y₂={p2[1]:.3f}, z₂={p2[2]:.3f}"
return out1, "", fig
if dash.ctx.triggered_id == "button-calc-gha2":
if None in (beta1, lamb1, beta2, lamb2):
return "", "Bitte β₁, λ₁, β₂, λ₂ eingeben.", 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(beta1)), np.deg2rad(float(lamb1))))
p2 = tuple(ell.ell2cart(np.deg2rad(float(beta2)), np.deg2rad(float(lamb2))))
fig = ellipsoid_figure(ell, title="Zweite Hauptaufgabe - numerisch")
fig = figure_constant_lines(fig, ell, "para")
fig = figure_points(fig, [("P1", p1, "black"), ("P2", p2, "red")])
fig = figure_lines(fig, [(p1, p2, "red")])
out2 = f"a₁₂={np.rad2deg(alpha_1):.6f}°, a₂₁={np.rad2deg(alpha_2):.6f}°, s={s12:.4f} m"
return "", out2, fig
return no_update, no_update, no_update
if __name__ == "__main__":
app.run(debug=False)