866 lines
29 KiB
Python
866 lines
29 KiB
Python
from dash import Dash, html, dcc, Input, Output, State, no_update
|
|
import plotly.graph_objects as go
|
|
import numpy as np
|
|
import dash_bootstrap_components as dbc
|
|
|
|
import webbrowser
|
|
from threading import Timer
|
|
|
|
from ellipsoide import EllipsoidTriaxial
|
|
import winkelumrechnungen as wu
|
|
import ausgaben as aus
|
|
|
|
from GHA_triaxial.gha1_ana import gha1_ana
|
|
from GHA_triaxial.gha1_num import gha1_num
|
|
from GHA_triaxial.gha1_approx import gha1_approx
|
|
|
|
from GHA_triaxial.gha2_num import gha2_num
|
|
from GHA_triaxial.gha2_ES import gha2_ES
|
|
from GHA_triaxial.gha2_approx import gha2_approx
|
|
|
|
|
|
app = Dash(__name__, suppress_callback_exceptions=True, external_stylesheets=[dbc.themes.BOOTSTRAP])
|
|
app.title = "Geodätische Hauptaufgaben"
|
|
|
|
|
|
def inputfeld(left_text, input_id, right_text="", width=200, min=None, max=None):
|
|
return html.Div(
|
|
children=[
|
|
html.Span(f"{left_text} =", style={"minWidth": 36, "textAlign": "right", "marginRight": 5}),
|
|
dcc.Input(
|
|
id=input_id,
|
|
type="number",
|
|
placeholder=f"{left_text}...[{right_text}]",
|
|
min=min,
|
|
max=max,
|
|
style={"width": width, "display": "block"},
|
|
persistence=True,
|
|
persistence_type="memory", # oder "session"/"local"
|
|
),
|
|
html.Span(right_text, style={"marginLeft": 5}) if right_text else html.Span()
|
|
],
|
|
style={"display": "flex", "alignItems": "center", "marginBottom": "10px"},
|
|
)
|
|
|
|
def method_row(label, cb_id, input_id, placeholder=""):
|
|
if placeholder == "":
|
|
return html.Div(
|
|
[
|
|
dcc.Checklist(
|
|
id=cb_id,
|
|
options=[{"label": "", "value": "on"}],
|
|
value=[],
|
|
style={"margin": "0"},
|
|
persistence=True,
|
|
persistence_type="memory",
|
|
),
|
|
html.Span(label, style={"marginLeft": "6px", "minWidth": "110px"}),
|
|
],
|
|
style={"display": "flex", "alignItems": "center", "gap": "6px",
|
|
"marginLeft": "10px", "marginBottom": "6px"},
|
|
)
|
|
else:
|
|
return html.Div(
|
|
[
|
|
dcc.Checklist(
|
|
id=cb_id,
|
|
options=[{"label": "", "value": "on"}],
|
|
value=[],
|
|
style={"margin": "0"},
|
|
persistence=True,
|
|
persistence_type="memory",
|
|
),
|
|
html.Span(label, style={"marginLeft": "6px", "minWidth": "110px"}),
|
|
|
|
dcc.Input(
|
|
id=input_id,
|
|
type="number",
|
|
placeholder=placeholder,
|
|
style={"width": "80px", "marginLeft": "10px"},
|
|
disabled=True,
|
|
persistence=True,
|
|
persistence_type="memory",
|
|
),
|
|
],
|
|
style={"display": "flex", "alignItems": "center", "gap": "6px",
|
|
"marginLeft": "10px", "marginBottom": "6px"},
|
|
)
|
|
|
|
|
|
|
|
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=10, 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(-90, 91, 15))
|
|
all_v = wu.deg2rad(np.arange(-180, 180, 1))
|
|
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 = wu.deg2rad(np.arange(-90, 91, 1))
|
|
constants_v = wu.deg2rad(np.arange(-180, 180, 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(-90, 91, 15))
|
|
all_lamb = wu.deg2rad(np.arange(-180, 180, 1))
|
|
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 = wu.deg2rad(np.arange(-90, 91, 1))
|
|
all_beta[0] += 1e-8
|
|
all_beta[-1] -= 1e-8
|
|
constants_lamb = wu.deg2rad(np.arange(-180, 180, 15))
|
|
for lamb in constants_lamb:
|
|
if lamb != 0 and abs(lamb) != np.pi:
|
|
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
|
|
))
|
|
else:
|
|
x, y, z = ell.para2cart(wu.deg2rad(np.arange(-90, 91, 1)), lamb)
|
|
fig.add_trace(go.Scatter3d(
|
|
x=x, y=y, z=z, mode="lines",
|
|
line=dict(width=1, color="black"),
|
|
showlegend=False
|
|
))
|
|
|
|
elif coordsystem == "geod":
|
|
constants_phi = wu.deg2rad(np.arange(-90, 91, 15))
|
|
all_lamb = wu.deg2rad(np.arange(-180, 180, 1))
|
|
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 = wu.deg2rad(np.arange(-90, 91, 1))
|
|
constants_lamb = wu.deg2rad(np.arange(-180, 180, 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, line, color):
|
|
"""
|
|
|
|
:param fig: plotly.graph_objects.Figure
|
|
:param line: Punktliste [[x1,y1,z1], [x2,y2,z2]]
|
|
:param color: Farbe
|
|
:return: plotly.graph_objects.Figure
|
|
"""
|
|
|
|
points = np.array(line, dtype=float)
|
|
fig.add_trace(go.Scatter3d(
|
|
x=points[:, 0], y=points[:, 1], z=points[:, 2],
|
|
mode="lines",
|
|
line=dict(width=4, color=color),
|
|
name="Strecke", showlegend=False
|
|
))
|
|
return fig
|
|
|
|
pane_gha1 = html.Div(
|
|
[
|
|
inputfeld("β₀", "input-GHA1-beta0", "°", min=-90, max=90),
|
|
inputfeld("λ₀", "input-GHA1-lamb0", "°", min=-180, max=180),
|
|
inputfeld("s", "input-GHA1-s", "m", min=0),
|
|
inputfeld("α₀", "input-GHA1-a", "°", min=0, max=360),
|
|
|
|
dcc.Checklist(
|
|
id="method-checklist-1",
|
|
options=[
|
|
{"label": "Analytisch", "value": "analytisch"},
|
|
{"label": "Numerisch", "value": "numerisch"},
|
|
{"label": "Approximiert", "value": "approx"},
|
|
],
|
|
value=[],
|
|
style={"marginBottom": "10px", "marginLeft": "10px"},
|
|
persistence=True,
|
|
persistence_type="memory",
|
|
persisted_props=["value"],
|
|
),
|
|
method_row("Analytisch", "cb-ana-1", "input-ana1", ""),
|
|
method_row("Numerisch", "cb-num-1", "input-num-n-1", "n"),
|
|
method_row("Stochastisch", "cb-stoch-1", "input-stoch-n-1", "n"),
|
|
method_row("Approximiert", "cb-approx-1", "input-approx-ds-1", "ds"),
|
|
|
|
|
|
html.Div(
|
|
[
|
|
html.Button(
|
|
"Berechnen",
|
|
id="button-calc-gha1",
|
|
n_clicks=0,
|
|
className="btn btn-secondary btn-lg shadow",
|
|
style={"marginRight": "10px", "marginLeft": "10px", "marginTop": "30px"},
|
|
),
|
|
],
|
|
style={"marginBottom": "20px"},
|
|
),
|
|
|
|
html.Div(id="tabs-GHA1-out", style={"marginBottom": "10px"}),
|
|
|
|
dcc.Loading(html.Div(id="output-gha1-ana")),
|
|
dcc.Loading(html.Div(id="output-gha1-num")),
|
|
dcc.Loading(html.Div(id="output-gha1-stoch")),
|
|
dcc.Loading(html.Div(id="output-gha1-approx")),
|
|
|
|
dcc.Store(id="store-gha1-ana"),
|
|
dcc.Store(id="store-gha1-num"),
|
|
dcc.Store(id="store-gha1-stoch"),
|
|
dcc.Store(id="store-gha1-approx"),
|
|
],
|
|
id="pane-gha1",
|
|
style={"display": "block"},
|
|
)
|
|
|
|
pane_gha2 = html.Div(
|
|
[
|
|
inputfeld("β₀", "input-GHA2-beta0", "°", min=-90, max=90),
|
|
inputfeld("λ₀", "input-GHA2-lamb0", "°", min=-180, max=180),
|
|
inputfeld("β₁", "input-GHA2-beta1", "°", min=-90, max=90),
|
|
inputfeld("λ₁", "input-GHA2-lamb1", "°", min=-180, max=180),
|
|
|
|
dcc.Checklist(
|
|
id="method-checklist-2",
|
|
options=[
|
|
{"label": "Numerisch", "value": "numerisch"},
|
|
{"label": "Stochastisch (ES)", "value": "stochastisch"},
|
|
{"label": "Approximiert", "value": "approx"},
|
|
],
|
|
value=[],
|
|
style={"marginBottom": "10px", "marginLeft": "10px"},
|
|
persistence=True,
|
|
persistence_type="memory",
|
|
persisted_props=["value"],
|
|
),
|
|
html.Div(
|
|
[
|
|
html.Button(
|
|
"Berechnen",
|
|
id="button-calc-gha2",
|
|
n_clicks=0,
|
|
style={"marginRight": "10px", "marginLeft": "10px"},
|
|
),
|
|
],
|
|
style={"marginBottom": "20px"},
|
|
),
|
|
|
|
html.Div(id="tabs-GHA2-out", style={"marginBottom": "10px"}),
|
|
|
|
dcc.Loading(html.Div(id="output-gha2-num")),
|
|
dcc.Loading(html.Div(id="output-gha2-stoch")),
|
|
dcc.Loading(html.Div(id="output-gha2-approx")),
|
|
|
|
dcc.Store(id="store-gha2-num"),
|
|
dcc.Store(id="store-gha2-stoch"),
|
|
dcc.Store(id="store-gha2-approx"),
|
|
],
|
|
id="pane-gha2",
|
|
style={"display": "none"},
|
|
)
|
|
|
|
|
|
# HTML-Elemente
|
|
app.layout = html.Div(
|
|
style={"fontFamily": "Arial", "padding": "10px", "width": "95%", "margin": "0 auto"},
|
|
children=[
|
|
html.H1("Geodätische Hauptaufgaben"),
|
|
html.H2("für dreiachsige Ellipsoide"),
|
|
|
|
html.Div(
|
|
style={
|
|
"display": "flex",
|
|
"alignItems": "flex-start",
|
|
"gap": "24px",
|
|
"flexWrap": "nowrap"
|
|
},
|
|
children=[
|
|
|
|
html.Div(
|
|
style={"flex": "1 1 420px", "maxWidth": "640px"},
|
|
children=[
|
|
|
|
html.Label("Ellipsoid wählen:"),
|
|
dcc.Dropdown(
|
|
id="dropdown-ellipsoid",
|
|
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": "BesselBiaxial", "value": "BesselBiaxial"},
|
|
{"label": "KarneyTest2024", "value": "KarneyTest2024"},
|
|
{"label": "Fiction", "value": "Fiction"},
|
|
|
|
],
|
|
value="",
|
|
style={"width": "300px", "marginBottom": "16px"},
|
|
),
|
|
|
|
html.P("Halbachsen:", style={"marginBottom": "10px"}),
|
|
inputfeld("aₓ", "input-ax", "m", min=0),
|
|
inputfeld("aᵧ", "input-ay", "m", min=0),
|
|
inputfeld("b", "input-b", "m", min=0),
|
|
|
|
dcc.Tabs(
|
|
id="tabs-GHA",
|
|
value="tab-GHA1",
|
|
style={"margin": "20px 0 15px", "width": "100%"},
|
|
children=[
|
|
dcc.Tab(label="Erste Hauptaufgabe", value="tab-GHA1"),
|
|
dcc.Tab(label="Zweite Hauptaufgabe", value="tab-GHA2"),
|
|
],
|
|
),
|
|
|
|
html.Div([pane_gha1, pane_gha2], id="tabs-GHA-out", style={"marginBottom": "10px"}),
|
|
|
|
],
|
|
),
|
|
|
|
html.Div(
|
|
style={
|
|
"flex": "1 1 750px",
|
|
"minWidth": "520px",
|
|
"position": "sticky",
|
|
"top": "0",
|
|
"marginTop": "-50px",
|
|
},
|
|
children=[
|
|
html.Label("Koordinatenart wählen:", style={"marginLeft": "80px"},),
|
|
dcc.Dropdown(
|
|
id="dropdown-coors-type",
|
|
options=[
|
|
{"label": "Ellipsoidisch", "value": "ell"},
|
|
{"label": "Parametrisch", "value": "para"},
|
|
{"label": "Geodätisch", "value": "geod"},
|
|
|
|
],
|
|
value="ell",
|
|
clearable=False,
|
|
style={"width": "200px", "marginLeft": "80px"},
|
|
),
|
|
dcc.Graph(
|
|
id="ellipsoid-plot",
|
|
style={"height": "85vh", "width": "100%"},
|
|
config={"responsive": True}
|
|
)
|
|
],
|
|
),
|
|
],
|
|
),
|
|
|
|
#html.P("© 2026", style={"fontSize": "10px", "color": "gray", "textAlign": "center", "marginTop": "16px"}),
|
|
],
|
|
)
|
|
|
|
# Funktion zur Wahl der Halbachsen
|
|
@app.callback(
|
|
Output("input-ax", "value"),
|
|
Output("input-ay", "value"),
|
|
Output("input-b", "value"),
|
|
Input("dropdown-ellipsoid", "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
|
|
|
|
# Funktion zur Generierung der Tab-Inhalte
|
|
@app.callback(
|
|
Output("pane-gha1", "style"),
|
|
Output("pane-gha2", "style"),
|
|
Input("tabs-GHA", "value"),
|
|
)
|
|
def switch_tabs(tab):
|
|
show1 = {"display": "block"} if tab == "tab-GHA1" else {"display": "none"}
|
|
show2 = {"display": "block"} if tab == "tab-GHA2" else {"display": "none"}
|
|
return show1, show2
|
|
|
|
@app.callback(
|
|
Output("input-approx-ds-1", "disabled"),
|
|
Input("cb-approx-1", "value"),
|
|
)
|
|
def toggle_ds(v):
|
|
return "on" not in (v or [])
|
|
|
|
|
|
|
|
# -- GHA 1 ---
|
|
@app.callback(
|
|
Output("output-gha1-ana", "children"),
|
|
Output("store-gha1-ana", "data"),
|
|
Input("button-calc-gha1", "n_clicks"),
|
|
State("input-GHA1-beta0", "value"),
|
|
State("input-GHA1-lamb0", "value"),
|
|
State("input-GHA1-s", "value"),
|
|
State("input-GHA1-a", "value"),
|
|
State("input-ax", "value"),
|
|
State("input-ay", "value"),
|
|
State("input-b", "value"),
|
|
State("method-checklist-1", "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def compute_gha1_ana(n1, beta0, lamb0, s, a0, ax, ay, b, method1):
|
|
out = html.Div([
|
|
html.H4("Erste Hauptaufgabe"),
|
|
])
|
|
if not n1:
|
|
return no_update, no_update
|
|
if None in (ax, ay, b):
|
|
return html.Span("Bitte Ellipsoid wählen.", style={"color": "red"}), None
|
|
if None in (beta0, lamb0, s, a0):
|
|
return html.Span("Bitte β₀, λ₀, s und α₀ eingeben.", style={"color": "red"}), None
|
|
if not method1:
|
|
return html.Span("Bitte Berechnungsverfahren wählen.", style={"color": "red"}), None
|
|
if "analytisch" not in (method1 or []):
|
|
return out, no_update
|
|
|
|
|
|
ell = EllipsoidTriaxial(ax, ay, b)
|
|
beta_rad = wu.deg2rad(float(beta0))
|
|
lamb_rad = wu.deg2rad(float(lamb0))
|
|
alpha_rad = wu.deg2rad(float(a0))
|
|
s_val = float(s)
|
|
|
|
P0 = ell.ell2cart(beta_rad, lamb_rad)
|
|
P1_ana, alpha2 = gha1_ana(ell, P0, alpha_rad, s_val, 70)
|
|
beta2_ana, lamb2_ana = ell.cart2ell(P1_ana)
|
|
|
|
out = html.Div([
|
|
html.H4("Erste Hauptaufgabe"),
|
|
html.Strong("Analytisch: "),
|
|
html.Br(),
|
|
html.Span(f"kartesisch: x₁={P1_ana[0]:.4f} m, y₁={P1_ana[1]:.4f} m, z₁={P1_ana[2]:.4f} m"),
|
|
html.Br(),
|
|
html.Span(f"ellipsoidisch: {aus.gms('β₁', beta2_ana, 4)}, {aus.gms('λ₁', lamb2_ana, 4)}"),
|
|
html.Br(),
|
|
])
|
|
|
|
store = {
|
|
"points": [("P0", P0, "black"), ("P1 (ana)", P1_ana, "red")],
|
|
"polyline": None,
|
|
"color": "red"
|
|
}
|
|
return out, store
|
|
|
|
@app.callback(
|
|
Output("output-gha1-num", "children"),
|
|
Output("store-gha1-num", "data"),
|
|
Input("button-calc-gha1", "n_clicks"),
|
|
State("input-GHA1-beta0", "value"),
|
|
State("input-GHA1-lamb0", "value"),
|
|
State("input-GHA1-s", "value"),
|
|
State("input-GHA1-a", "value"),
|
|
State("input-ax", "value"),
|
|
State("input-ay", "value"),
|
|
State("input-b", "value"),
|
|
State("method-checklist-1", "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def compute_gha1_num(n1, beta0, lamb0, s, a0, ax, ay, b, method1):
|
|
if not n1:
|
|
return no_update, no_update
|
|
if "numerisch" not in (method1 or []):
|
|
return no_update, no_update
|
|
|
|
ell = EllipsoidTriaxial(ax, ay, b)
|
|
beta_rad = wu.deg2rad(float(beta0))
|
|
lamb_rad = wu.deg2rad(float(lamb0))
|
|
alpha_rad = wu.deg2rad(float(a0))
|
|
s_val = float(s)
|
|
|
|
P0 = ell.ell2cart(beta_rad, lamb_rad)
|
|
|
|
P1_num, alpha1, werte = gha1_num(ell, P0, alpha_rad, s_val, 10000, all_points=True)
|
|
beta2_num, lamb2_num = ell.cart2ell(P1_num)
|
|
|
|
out = html.Div([
|
|
html.Strong("Numerisch: "),
|
|
html.Br(),
|
|
html.Span(f"kartesisch: x₁={P1_num[0]:.4f} m, y₁={P1_num[1]:.4f} m, z₁={P1_num[2]:.4f} m"),
|
|
html.Br(),
|
|
html.Span(f"ellipsoidisch: {aus.gms('β₁', beta2_num, 4)}, {aus.gms('λ₁', lamb2_num, 4)}"),
|
|
html.Br(),
|
|
])
|
|
|
|
polyline = [[x1, y1, z1] for x1, _, y1, _, z1, _ in werte]
|
|
|
|
store = {
|
|
"points": [("P0", P0, "black"), ("P1 (num)", P1_num, "#ff8c00")],
|
|
"polyline": polyline,
|
|
"color": "#ff8c00"
|
|
}
|
|
return out, store
|
|
|
|
@app.callback(
|
|
Output("output-gha1-stoch", "children"),
|
|
Output("store-gha1-stoch", "data"),
|
|
Input("button-calc-gha1", "n_clicks"),
|
|
State("input-GHA1-beta0", "value"),
|
|
State("input-GHA1-lamb0", "value"),
|
|
State("input-GHA1-s", "value"),
|
|
State("input-GHA1-a", "value"),
|
|
State("input-ax", "value"),
|
|
State("input-ay", "value"),
|
|
State("input-b", "value"),
|
|
State("method-checklist-1", "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def compute_gha1_stoch(n1, beta0, lamb0, s, a0, ax, ay, b, method1):
|
|
if not n1:
|
|
return no_update, no_update
|
|
if "stochastisch" not in (method1 or []):
|
|
return no_update, no_update
|
|
|
|
ell = EllipsoidTriaxial(ax, ay, b)
|
|
beta_rad = wu.deg2rad(float(beta0))
|
|
lamb_rad = wu.deg2rad(float(lamb0))
|
|
alpha_rad = wu.deg2rad(float(a0))
|
|
s_val = float(s)
|
|
|
|
betas, lambs, alphas, S_real = gha1_es(
|
|
beta_rad, lamb_rad, alpha_rad,
|
|
s_val,
|
|
10000,
|
|
ell
|
|
)
|
|
beta1_stoch = betas[-1]
|
|
lamb1_stoch = lambs[-1]
|
|
|
|
P0 = ell.ell2cart(beta_rad, lamb_rad)
|
|
P1_stoch = ell.ell2cart(beta1_stoch, lamb1_stoch)
|
|
|
|
out = html.Div([
|
|
html.Strong("Stochastisch: "),
|
|
html.Br(),
|
|
html.Span(f"kartesisch: x₁={P1_stoch[0]:.4f} m, y₁={P1_stoch[1]:.4f} m, z₁={P1_stoch[2]:.4f} m"),
|
|
html.Br(),
|
|
html.Span(f"ellipsoidisch: {aus.gms('β₁', beta1_stoch, 4)}, {aus.gms('λ₁', lamb1_stoch, 4)}"),
|
|
])
|
|
|
|
store = {
|
|
"points": [("P0", P0, "black"), ("P1 (ES)", P1_stoch, "#d62728")],
|
|
"polyline": None,
|
|
"color": "#d62728"
|
|
}
|
|
return out, store
|
|
|
|
@app.callback(
|
|
Output("output-gha1-approx", "children"),
|
|
Output("store-gha1-approx", "data"),
|
|
Input("button-calc-gha1", "n_clicks"),
|
|
State("input-GHA1-beta0", "value"),
|
|
State("input-GHA1-lamb0", "value"),
|
|
State("input-GHA1-s", "value"),
|
|
State("input-GHA1-a", "value"),
|
|
State("input-ax", "value"),
|
|
State("input-ay", "value"),
|
|
State("input-b", "value"),
|
|
State("method-checklist-1", "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def compute_gha1_approx(n1, beta0, lamb0, s, a0, ax, ay, b, method1):
|
|
if not n1:
|
|
return no_update, no_update
|
|
if "approx" not in (method1 or []):
|
|
return no_update, no_update
|
|
|
|
ell = EllipsoidTriaxial(ax, ay, b)
|
|
beta_rad = wu.deg2rad(float(beta0))
|
|
lamb_rad = wu.deg2rad(float(lamb0))
|
|
alpha_rad = wu.deg2rad(float(a0))
|
|
s_val = float(s)
|
|
|
|
P0 = ell.ell2cart(beta_rad, lamb_rad)
|
|
P1_app, alpha1_app, points, alphas = gha1_approx(ell, P0, alpha_rad, s_val, ds=5000, all_points=True)
|
|
|
|
beta1_app, lamb1_app = ell.cart2ell(P1_app)
|
|
|
|
out = html.Div([
|
|
html.Strong("Approximiert: "),
|
|
html.Br(),
|
|
html.Span(f"kartesisch: x₁={P1_app[0]:.4f} m, y₁={P1_app[1]:.4f} m, z₁={P1_app[2]:.4f} m"),
|
|
html.Br(),
|
|
html.Span(f"ellipsoidisch: {aus.gms('β₁', beta1_app, 4)}, {aus.gms('λ₁', lamb1_app, 4)}"),
|
|
])
|
|
|
|
store = {
|
|
"points": [("P0", P0, "black"), ("P1 (approx)", P1_app, "#00c2fc")],
|
|
"polyline": points,
|
|
"color": "#00c2fc"
|
|
}
|
|
return out, store
|
|
|
|
|
|
# --- GHA 2 ---
|
|
@app.callback(
|
|
Output("output-gha2-num", "children"),
|
|
Output("store-gha2-num", "data"),
|
|
Input("button-calc-gha2", "n_clicks"),
|
|
State("input-GHA2-beta0", "value"),
|
|
State("input-GHA2-lamb0", "value"),
|
|
State("input-GHA2-beta1", "value"),
|
|
State("input-GHA2-lamb1", "value"),
|
|
State("input-ax", "value"),
|
|
State("input-ay", "value"),
|
|
State("input-b", "value"),
|
|
State("method-checklist-2", "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def compute_gha2_num(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2):
|
|
out = html.Div([
|
|
html.H4("Zweite Hauptaufgabe"),
|
|
])
|
|
if not n2:
|
|
return no_update, no_update
|
|
if None in (ax, ay, b):
|
|
return html.Span("Bitte Ellipsoid wählen.", style={"color": "red"}), None
|
|
if None in (beta0, lamb0, beta1, lamb1):
|
|
return html.Span("Bitte β₀, λ₀, β₁ und λ₁ eingeben.", style={"color": "red"}), None
|
|
if not method2:
|
|
return html.Span("Bitte Berechnungsverfahren wählen.", style={"color": "red"}), None
|
|
if "numerisch" not in (method2 or []):
|
|
return out, no_update
|
|
|
|
ell = EllipsoidTriaxial(ax, ay, b)
|
|
|
|
beta0_rad = wu.deg2rad(float(beta0))
|
|
lamb0_rad = wu.deg2rad(float(lamb0))
|
|
beta1_rad = wu.deg2rad(float(beta1))
|
|
lamb1_rad = wu.deg2rad(float(lamb1))
|
|
|
|
P0 = ell.ell2cart(beta0_rad, lamb0_rad)
|
|
P1 = ell.ell2cart(beta1_rad, lamb1_rad)
|
|
|
|
a0_num, a1_num, s_num, beta_arr, lamb_arr = gha2_num(ell, beta0_rad, lamb0_rad, beta1_rad, lamb1_rad, all_points=True, n=3000)
|
|
|
|
polyline = []
|
|
for b_rad, l_rad in zip(beta_arr, lamb_arr):
|
|
x, y, z = ell.ell2cart(b_rad, l_rad)
|
|
polyline.append([float(x), float(y), float(z)])
|
|
|
|
out = html.Div([
|
|
html.H4("Zweite Hauptaufgabe"),
|
|
html.Strong("Numerisch: "),
|
|
html.Span(f"{aus.gms('α₀', a0_num, 4)}, {aus.gms('α₁', a1_num, 4)}, s = {s_num:.4f} m"),
|
|
])
|
|
|
|
store = {
|
|
"points": [("P0", P0, "black"), ("P1", P1, "black")],
|
|
"polyline": polyline,
|
|
"color": "#ff8c00",
|
|
}
|
|
return out, store
|
|
|
|
@app.callback(
|
|
Output("output-gha2-stoch", "children"),
|
|
Output("store-gha2-stoch", "data"),
|
|
Input("button-calc-gha2", "n_clicks"),
|
|
State("input-GHA2-beta0", "value"),
|
|
State("input-GHA2-lamb0", "value"),
|
|
State("input-GHA2-beta1", "value"),
|
|
State("input-GHA2-lamb1", "value"),
|
|
State("input-ax", "value"),
|
|
State("input-ay", "value"),
|
|
State("input-b", "value"),
|
|
State("method-checklist-2", "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def compute_gha2_stoch(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2):
|
|
if not n2:
|
|
return no_update, no_update
|
|
if "stochastisch" not in (method2 or []):
|
|
return no_update, no_update
|
|
|
|
ell = EllipsoidTriaxial(ax, ay, b)
|
|
|
|
beta0_rad = wu.deg2rad(float(beta0))
|
|
lamb0_rad = wu.deg2rad(float(lamb0))
|
|
beta1_rad = wu.deg2rad(float(beta1))
|
|
lamb1_rad = wu.deg2rad(float(lamb1))
|
|
|
|
P0 = ell.ell2cart(beta0_rad, lamb0_rad)
|
|
P1 = ell.ell2cart(beta1_rad, lamb1_rad)
|
|
|
|
a0_stoch, a1_stoch, s_stoch, points = gha2_ES(ell, P0, P1, all_points=True)
|
|
|
|
out = html.Div([
|
|
html.Strong("Stochastisch (ES): "),
|
|
html.Span(f"{aus.gms('α₀', a0_stoch, 4)}, α₁ = {a1_stoch}, s = {s_stoch:.4f} m"),
|
|
])
|
|
|
|
|
|
return out, {"points": None, "polyline": None, "color": "#d62728"}
|
|
|
|
@app.callback(
|
|
Output("output-gha2-approx", "children"),
|
|
Output("store-gha2-approx", "data"),
|
|
Input("button-calc-gha2", "n_clicks"),
|
|
State("input-GHA2-beta0", "value"),
|
|
State("input-GHA2-lamb0", "value"),
|
|
State("input-GHA2-beta1", "value"),
|
|
State("input-GHA2-lamb1", "value"),
|
|
State("input-ax", "value"),
|
|
State("input-ay", "value"),
|
|
State("input-b", "value"),
|
|
State("method-checklist-2", "value"),
|
|
prevent_initial_call=True,
|
|
)
|
|
def compute_gha2_approx(n2, beta0, lamb0, beta1, lamb1, ax, ay, b, method2):
|
|
if not n2:
|
|
return no_update, no_update
|
|
if "approx" not in (method2 or []):
|
|
return no_update, no_update
|
|
|
|
ell = EllipsoidTriaxial(ax, ay, b)
|
|
|
|
beta0_rad = wu.deg2rad(float(beta0))
|
|
lamb0_rad = wu.deg2rad(float(lamb0))
|
|
beta1_rad = wu.deg2rad(float(beta1))
|
|
lamb1_rad = wu.deg2rad(float(lamb1))
|
|
|
|
P0 = ell.ell2cart(beta0_rad, lamb0_rad)
|
|
P1 = ell.ell2cart(beta1_rad, lamb1_rad)
|
|
|
|
a0_app, a1_app, s_app, points = gha2_approx(ell, P0, P1, ds=1000, all_points=True)
|
|
|
|
out = html.Div([
|
|
html.Strong("Approximiert: "),
|
|
html.Span(f"{aus.gms('α₀', a0_app, 4)}, {aus.gms('α₁', a1_app, 4)}, s = {s_app:.4f} m"),
|
|
])
|
|
|
|
store = {
|
|
"points": [("P0", P0, "black"), ("P1", P1, "black")],
|
|
"polyline": points,
|
|
"color": "#00c2fc",
|
|
}
|
|
|
|
return out, store
|
|
|
|
# --- Plot ---
|
|
@app.callback(
|
|
Output("ellipsoid-plot", "figure"),
|
|
Input("input-ax", "value"),
|
|
Input("input-ay", "value"),
|
|
Input("input-b", "value"),
|
|
Input("dropdown-coors-type", "value"),
|
|
Input("store-gha1-ana", "data"),
|
|
Input("store-gha1-num", "data"),
|
|
Input("store-gha1-stoch", "data"),
|
|
Input("store-gha1-approx", "data"),
|
|
Input("store-gha2-num", "data"),
|
|
Input("store-gha2-stoch", "data"),
|
|
Input("store-gha2-approx", "data"),
|
|
)
|
|
def render_all(ax, ay, b, coords_type, store_gha1_ana, store_gha1_num, store_gha1_stoch, store_gha1_approx, store_gha2_num, store_gha2_stoch, store_gha2_approx):
|
|
if None in (ax, ay, b):
|
|
return go.Figure()
|
|
|
|
ell = EllipsoidTriaxial(ax, ay, b)
|
|
fig = ellipsoid_figure(ell, title="")
|
|
fig = figure_constant_lines(fig, ell, coords_type)
|
|
|
|
def add_from_store(fig, store):
|
|
if not store:
|
|
return fig
|
|
pts = store.get("points") or []
|
|
if pts:
|
|
fig = figure_points(fig, pts)
|
|
line = store.get("polyline")
|
|
if line:
|
|
fig = figure_lines(fig, line, store.get("color", "#ff8c00"))
|
|
return fig
|
|
|
|
for st in (store_gha1_ana, store_gha1_num, store_gha1_stoch, store_gha1_approx, store_gha2_num, store_gha2_stoch, store_gha2_approx):
|
|
fig = add_from_store(fig, st)
|
|
|
|
return fig
|
|
|
|
if __name__ == "__main__":
|
|
HOST = "127.0.0.1"
|
|
PORT = 8050
|
|
|
|
Timer(1.0, webbrowser.open_new_tab(f"http://{HOST}:{PORT}/")).start
|
|
|
|
app.run(host=HOST, port=PORT, debug=False)
|