Re: kleine Mathe-Spielereien
Verfasst: Montag 17. Juli 2023, 17:19
Die Codebeispiele waren nicht von mir.
Seit 2002 Diskussionen rund um die Programmiersprache Python
https://www.python-forum.de/
Code: Alles auswählen
#RICHTOTAL.py
from rich.align import Align
from rich.console import Console
from rich.live import Live
from rich.table import Table
TABLE_DATA = [
[
"[b white]PYTHON KURS [/]: [i]für Anfänger[/]",
"[magenta]ausgebucht",
"[green]TU München[/]",
"demnächst",
],
[
"[b white]SCIPY KURS[/]: [i]für Interessierte[/]",
"[yellow][/]ausgebucht",
"[green] UNI Franfurt[/]",
"2024",
],
[
"[b white]DSA Course[/]: [i für ]Fortgeschrittene[/]",
"[magenta] noch 20 Plätze frei",
"[green] MTI Boston[/]",
"2024",
],
[
"[b white]Operating System für Profis[/]",
"[magenta] keine Angaben",
"[green ]wird demnächst bekannt gegeben[/]",
"unbekannt",
],
]
console = Console()
table = Table(show_footer=False)
table_centered = Align.center(table)
console.clear()
with Live(table_centered, console=console,
screen=False):
table.add_column("Kursbezeichnug", no_wrap=True)
table.add_column("belegt / frei", no_wrap=True)
table.add_column("Organisation", no_wrap=True)
table.add_column("Zeitpunkt", no_wrap=True)
table.add_column("Ein Test mit RICH-CODE", no_wrap=True)
for row in TABLE_DATA:
table.add_row(*row)
table_width = console.measure(table).maximum
table.width = None
Code: Alles auswählen
# RICHTABLEA.py
import time
from rich.live import Live
from rich.table import Table
table = Table()
table.add_column("Row ID")
table.add_column("Description")
table.add_column("Level")
with Live(table, refresh_per_second=4): # update 4 times a second to feel fluid
for row in range(20):
time.sleep(0.4) # arbitrary delay
# update the renderable internally
table.add_row(f"{row}", f"Beschreibung {row}", "[red]größer o. kleiner?")
#Aktualisieren des Renderables¶
#Sie können das Renderbare auch im laufenden Betrieb ändern, indem Sie die update()Methode aufrufen. Dies kann nützlich sein, wenn die Informationen, die Sie anzeigen möchten, zu dynamisch sind, um sie durch Aktualisieren eines einzelnen Renderables zu generieren. Hier ist ein Beispiel:
import random
import time
from rich.live import Live
from rich.table import Table
def generate_table() -> Table:
"""Make a new table."""
table = Table()
table.add_column("ID")
table.add_column("Value")
table.add_column("Status")
for row in range(random.randint(2, 6)):
value = random.random() * 100
table.add_row(
f"{row}", f"{value:3.2f}", "[red] Kleiner als 80 : Falsch" if value < 80 else "[green]Größer als 80 Richtig"
)
return table
with Live(generate_table(), refresh_per_second=4) as live:
for _ in range(40):
time.sleep(0.4)
live.update(generate_table())
Code: Alles auswählen
#RICHLAYOUT.py
from rich import print
from rich.layout import Layout
layout = Layout()
print(layout)
layout.split_column(
Layout(name="upper"),
Layout(name="lower")
)
print(layout)
layout["lower"].split_row(
Layout(name="left"),
Layout(name="right"),
)
print(layout)
Code: Alles auswählen
#Richtextlayout.py
from rich import print
from rich.panel import Panel
from rich.layout import Layout
from rich.prompt import Prompt
def rich_ui():
while True:
layout = Layout()
layout.split_column(
Layout(name="banner"),
Layout(name="recipe" ),
Layout(name="search")
)
layout['banner'].update(Panel('Brot backen', padding=1))
layout['banner'].size = 5
layout['recipe'].split_row(
Layout(name="Zutaten:\
Roggenmehl,\
Dinkelmehl,\
Weizenmeh,\
Salz und Wasser"),
Layout(name="Herstellung:\
Teig zubereiten,\
bei 230° 1 Stunde backen.")
)
layout['search'].update(Panel(Prompt.ask('> '), title='Suche nach einem Rezept'))
layout['search'].size = 5
print(layout)
if __name__ == '__main__':
rich_ui()
Code: Alles auswählen
│ │
│ Brot backen │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ 'Zutaten: Roggenmehl, ─╮╭─ 'Herstellung: Teig zubere─╮
│ ││ │
│ ││ │
│ ││ │
│ Layout( ││ │
│ name='Zutaten: ││ Layout( │
│ Roggenmehl, Dinkelmehl, ││ name='Herstellung: │
│ Weizenmeh, Salz und ││ Teig zubereiten, bei 230° │
│ Wasser' ││ 1 Stunde backen.' │
│ ) ││ ) │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
╰──────────────────────────────────────╯╰──────────────────────────────────────╯
╭────────────────────────── Suche nach einem Rezept ───────────────────────────╮
│ Hallo │
│ │
│ │
╰──────────────────────────────────────────────────────────────────────────────╯
> :
Code: Alles auswählen
mport time
from rich.progress import track
for _ in track(range(20), description="Processing..."):
time.sleep(0.5) # Simulate work being done
import time
from rich.progress import Progress
with Progress() as progress:
_ = progress.add_task("Loading...", total=None)
while True:
time.sleep(0.01)
from time import monotonic
from textual.reactive import reactive
from textual.widgets import Static
class TimeDisplay(Static):
"""A widget to display elapsed time."""
start_time = reactive(monotonic)
time = reactive(0.0)
total = reactive(0.0)
def on_mount(self) -> None:
"""Event handler called when widget is added to the app."""
self.update_timer = self.set_interval(1 / 60, self.update_time, pause=True)
def update_time(self) -> None:
"""Method to update time to current."""
self.time = self.total + (monotonic() - self.start_time)
def watch_time(self, time: float) -> None:
"""Called when the time attribute changes."""
minutes, seconds = divmod(time, 60)
hours, minutes = divmod(minutes, 60)
self.update(f"{hours:02,.0f}:{minutes:02.0f}:{seconds:05.2f}")
from rich.progress import Progress, BarColumn
from textual.app import App, ComposeResult
from textual.widgets import Static
class IndeterminateProgress(Static):
def __init__(self):
super().__init__("")
self._bar = Progress(BarColumn())
self._bar.add_task("", total=None)
def on_mount(self) -> None:
# When the widget is mounted start updating the display regularly.
self.update_render = self.set_interval(
1 / 60, self.update_progress_bar
)
def update_progress_bar(self) -> None:
self.update(self._bar)
class MyApp(App):
def compose(self) -> ComposeResult:
yield IndeterminateProgress()
if __name__ == "__main__":
app = MyApp()
app.run()
Code: Alles auswählen
#TestC.py
from urllib.request import Request, urlopen
from rich.text import Text
from textual import work
from textual.app import App, ComposeResult
from textual.containers import VerticalScroll
from textual.widgets import Input, Static
from textual.worker import Worker, get_current_worker
class WeatherApp(App):
"""App to display the current weather."""
CSS_PATH = "weather.css"
def compose(self) -> ComposeResult:
yield Input(placeholder="Enter a City")
with VerticalScroll(id="weather-container"):
yield Static(id="weather")
async def on_input_changed(self, message: Input.Changed) -> None:
"""Called when the input changes"""
self.update_weather(message.value)
@work(exclusive=True)
def update_weather(self, city: str) -> None:
"""Update the weather for the given city."""
weather_widget = self.query_one("#weather", Static)
worker = get_current_worker()
if city:
# Query the network API
url = f"https://wttr.in/{city}"
request = Request(url)
request.add_header("User-agent", "CURL")
response_text = urlopen(request).read().decode("utf-8")
weather = Text.from_ansi(response_text)
if not worker.is_cancelled:
self.call_from_thread(weather_widget.update, weather)
else:
# No city, so just blank out the weather
if not worker.is_cancelled:
self.call_from_thread(weather_widget.update, "")
def on_worker_state_changed(self, event: Worker.StateChanged) -> None:
"""Called when the worker state changes."""
self.log(event)
if __name__ == "__main__":
app = WeatherApp()
app.run()
Code: Alles auswählen
# Python program to illustrate a stop watch
# using Tkinter
#importing the required libraries
import tkinter as Tkinter
from datetime import datetime
counter = 66600
running = False
def counter_label(label):
def count():
if running:
global counter
# To manage the initial delay.
if counter== 0:
display="Weiter......."
else:
tt = datetime.fromtimestamp(counter)
string = tt.strftime("%H:%M:%S")
display=string
label['text']=display # Or label.config(text=display)
# label.after(arg1, arg2) delays by
# first argument given in milliseconds
# and then calls the function given as second argument.
# Generally like here we need to call the
# function in which it is present repeatedly.
# Delays by 1000ms=1 seconds and call count again.
label.after(1000, count)
counter +=1
# Triggering the start of the counter.
count()
# start function of the stopwatch
def Start(label):
global running
running=True
counter_label(label)
start['state']='disabled'
stop['state']='normal'
reset['state']='normal'
# Stop function of the stopwatch
def Stop():
global running
start['state']='normal'
stop['state']='disabled'
reset['state']='normal'
running = False
# Reset function of the stopwatch
def Reset(label):
global counter
counter= 0
# If rest is pressed after pressing stop.
if running==False:
reset['state']='disabled'
label['text']='Es geht los!'
# If reset is pressed while the stopwatch is running.
else:
label['text']='J e t z t ........'
root = Tkinter.Tk()
root.title("Stoppuhr")
# Fixing the window size.
root.minsize(width=350, height=70)
label = Tkinter.Label(root, text="Willkommen bei Python", fg="red", font="Verdana 30 bold")
label.pack()
f = Tkinter.Frame(root)
start = Tkinter.Button(f, text='Start', width=6, command=lambda:Start(label))
stop = Tkinter.Button(f, text='Stop',width=6,state='disabled', command=Stop)
reset = Tkinter.Button(f, text='Reset',width=6, state='disabled', command=lambda:Reset(label))
f.pack(anchor = 'center',pady=5)
start.pack(side="left")
stop.pack(side ="left")
reset.pack(side="left")
root.mainloop()
Code: Alles auswählen
#ORIGINAL.py
from rich.progress import Progress, BarColumn
from rich.spinner import Spinner
import PYTHONSTOPPUHR.py
from textual.app import App, ComposeResult, RenderableType
from textual.containers import Grid, Horizontal, Vertical
from textual.widgets import Button, Static
class IntervalUpdater(Static):
_renderable_object: RenderableType
def update_rendering(self) -> None:
self.update(self._renderable_object)
def on_mount(self) -> None:
self.interval_update = self.set_interval(1 / 60, self.update_rendering)
def pause(self) -> None:
self.interval_update.pause()
def resume(self) -> None:
self.interval_update.resume()
class IndeterminateProgressBar(IntervalUpdater):
"""Basic indeterminate progress bar widget based on rich.progress.Progress."""
def __init__(self) -> None:
super().__init__("")
self._renderable_object = Progress(BarColumn())
self._renderable_object.add_task("", total=None)
class SpinnerWidget(IntervalUpdater):
"""Basic spinner widget based on rich.spinner.Spinner."""
def __init__(self, style: str) -> None:
super().__init__("")
self._renderable_object = Spinner(style)
class LiveDisplayApp(App[None]):
"""App showcasing some widgets that update regularly."""
PYTHON_PATH = "C:/PYTJON310/PYTHONSTOPPUHR.py"
def compose(self) -> ComposeResult:
yield Vertical(
Grid(
SpinnerWidget("moon"),
IndeterminateProgressBar(),
SpinnerWidget("aesthetic"),
SpinnerWidget("bouncingBar"),
SpinnerWidget("earth"),
SpinnerWidget("dots8Bit"),
),
Horizontal(
Button("Pause", id="pause"),
Button("Resume", id="resume", disabled=True),
),
)
def on_button_pressed(self, event: Button.Pressed) -> None:
pressed_id = event.button.id
assert pressed_id is not None
for widget in self.query(IntervalUpdater):
getattr(widget, pressed_id)()
for button in self.query(Button):
if button.id == pressed_id:
button.disabled = True
else:
button.disabled = False
LiveDisplayApp().run()
class IntervalUpdater(Static):
# ...
def update_rendering(self) -> None:
self.update(self._renderable_object)
class IntervalUpdater(Static):
_renderable_object: RenderableType
def __init__(self, renderable_object: RenderableType) -> None:
super().__init__(renderable_object)
def on_mount(self) -> None:
self.interval_update = self.set_interval(1 / 60, self.refresh)
class Spinner:
# ...
def __rich_console__(
self, console: "Console", options: "ConsoleOptions"
) -> "RenderResult":
yield self.render(console.get_time())
# ...
def render(self, time: float) -> "RenderableType":
# ...
frame_no = ((time - self.start_time) * self.speed) / (
self.interval / 1000.0
) + self.frame_no_offset
Code: Alles auswählen
######################################################
import OSWALD.py
from rich.progress import Progress, BarColumn
from rich.spinner import Spinner
from textual.app import App, ComposeResult, RenderableType
from textual.containers import Grid, Horizontal, Vertical
from textual.widgets import Button, Static
class IntervalUpdater(Static):
_renderable_object: RenderableType
def update_rendering(self) -> None:
self.update(self._renderable_object)
def on_mount(self) -> None:
self.interval_update = self.set_interval(1 / 60, self.update_rendering)
def pause(self) -> None:
self.interval_update.pause()
def resume(self) -> None:
self.interval_update.resume()
class IndeterminateProgressBar(IntervalUpdater):
"""Basic indeterminate progress bar widget based on rich.progress.Progress."""
def __init__(self) -> None:
super().__init__("")
self._renderable_object = Progress(BarColumn())
self._renderable_object.add_task("", total=None)
class SpinnerWidget(IntervalUpdater):
"""Basic spinner widget based on rich.spinner.Spinner."""
def __init__(self, style: str) -> None:
super().__init__("")
self._renderable_object = Spinner(style)
class LiveDisplayApp(App[None]):
"""App showcasing some widgets that update regularly."""
PYTHON_PATH = "C:/oswald.py"
def compose(self) -> ComposeResult:
yield Vertical(
Grid(
SpinnerWidget("moon"),
IndeterminateProgressBar(),
SpinnerWidget("aesthetic"),
SpinnerWidget("bouncingBar"),
SpinnerWidget("earth"),
SpinnerWidget("dots8Bit"),
),
Horizontal(
Button("Pause", id="pause"),
Button("Resume", id="resume", disabled=True),
),
)
def on_button_pressed(self, event: Button.Pressed) -> None:
pressed_id = event.button.id
assert pressed_id is not None
for widget in self.query(IntervalUpdater):
getattr(widget, pressed_id)()
for button in self.query(Button):
if button.id == pressed_id:
button.disabled = True
else:
button.disabled = False
LiveDisplayApp().run()
class IntervalUpdater(Static):
# ...
def update_rendering(self) -> None:
self.update(self._renderable_object)
class IntervalUpdater(Static):
_renderable_object: RenderableType
def __init__(self, renderable_object: RenderableType) -> None:
super().__init__(renderable_object)
def on_mount(self) -> None:
self.interval_update = self.set_interval(1 / 60, self.refresh)
class Spinner:
# ...
def __rich_console__(
self, console: "Console", options: "ConsoleOptions"
) -> "RenderResult":
yield self.render(console.get_time())
# ...
def render(self, time: float) -> "RenderableType":
# ...
frame_no = ((time - self.start_time) * self.speed) / (
self.interval / 1000.0
) + self.frame_no_offset
################################################
####################################################
from tkinter import *
import subprocess
from subprocess import *
from tkinter.filedialog import askopenfilename
def code1():
subprocess.call(["C:/windows/system32/mspaint.exe"])
def code2():
subprocess.call(["C:/windows/system32/calc.exe"])
def code3():
subprocess.call(["C:/Program Files/Internet Explorer/iexplore.exe"])
def code4():
subprocess.call( [ "C:\Program Files\Google\Chrome\Application\chrome.exe" ])
def About():
print("Beispiel für ein Menue" )
window = Tk()
window.geometry("450x450")
window.title("Bitte wählen Sie aus dem Menue")
menu = Menu(window)
window.config(menu=menu)
filemenu = Menu(menu)
menu.add_cascade(label="File", menu=filemenu)
filemenu.add_command(label="P a i n t", command=code1)
filemenu.add_command(label= "C a l c ", command=code2)
filemenu.add_command(label= "E x p l o r e " ,command =code3)
filemenu.add_command(label= "G o o g l e" , command = code4)
filemenu.add_command(label="Exit", command=window.quit)
helpmenu = Menu(menu)
menu.add_cascade(label="Help", menu=helpmenu)
helpmenu.add_command(label="About...", command=About)
mainloop()
[/code
Code: Alles auswählen
# Python program to illustrate a stop watch
# using Tkinter
#importing the required libraries
import tkinter as Tkinter
from datetime import datetime
counter = 66600
running = False
# using Tkinter
#importing the required libraries
import tkinter as Tkinter
from datetime import datetime
counter = 66600
running = False
def counter_label(label):
def count():
if running:
global counter
# To manage the initial delay.
if counter== 0:
display="Weiter......."
else:
tt = datetime.fromtimestamp(counter)
string = tt.strftime("%H:%M:%S")
display=string
label['text']=display # Or label.config(text=display)
# label.after(arg1, arg2) delays by
# first argument given in milliseconds
# and then calls the function given as second argument.
# Generally like here we need to call the
# function in which it is present repeatedly.
# Delays by 1000ms=1 seconds and call count again.
label.after(1000, count)
counter +=1
# Triggering the start of the counter.
count()
# start function of the stopwatch
def Start(label):
global running
running=True
counter_label(label)
start['state']='disabled'
stop['state']='normal'
reset['state']='normal'
# Stop function of the stopwatch
def Stop():
global running
start['state']='normal'
stop['state']='disabled'
reset['state']='normal'
running = False
# Reset function of the stopwatch
def Reset(label):
global counter
counter= 0
# If rest is pressed after pressing stop.
if running==False:
reset['state']='disabled'
label['text']='Es geht los!'
# If reset is pressed while the stopwatch is running.
else:
label['text']='J e t z t ........'
root = Tkinter.Tk()
root.title("Stoppuhr")
# Fixing the window size.
root.minsize(width=350, height=70)
label = Tkinter.Label(root, text="Willkommen bei Python", fg="red", font="Verdana 30 bold")
label.pack()
f = Tkinter.Frame(root)
start = Tkinter.Button(f, text='Start', width=6, command=lambda:Start(label))
stop = Tkinter.Button(f, text='Stop',width=6,state='disabled', command=Stop)
reset = Tkinter.Button(f, text='Reset',width=6, state='disabled', command=lambda:Reset(label))
f.pack(anchor = 'center',pady=5)
start.pack(side="left")
stop.pack(side ="left")
reset.pack(side="left")
root.mainloop()
def counter_label(label):
def count():
if running:
global counter
# To manage the initial delay.
if counter== 0:
display="Weiter......."
else:
tt = datetime.fromtimestamp(counter)
string = tt.strftime("%H:%M:%S")
display=string
label['text']=display # Or label.config(text=display)
# label.after(arg1, arg2) delays by
# first argument given in milliseconds
# and then calls the function given as second argument.
# Generally like here we need to call the
# function in which it is present repeatedly.
# Delays by 1000ms=1 seconds and call count again.
label.after(1000, count)
counter +=1
# Triggering the start of the counter.
count()
# start function of the stopwatch
def Start(label):
global running
running=True
counter_label(label)
start['state']='disabled'
stop['state']='normal'
reset['state']='normal'
# Stop function of the stopwatch
def Stop():
global running
start['state']='normal'
stop['state']='disabled'
reset['state']='normal'
running = False
# Reset function of the stopwatch
def Reset(label):
global counter
counter= 0
# If rest is pressed after pressing stop.
if running==False:
reset['state']='disabled'
label['text']='Es geht los!'
# If reset is pressed while the stopwatch is running.
else:
label['text']='J e t z t ........'
root = Tkinter.Tk()
root.title("Stoppuhr")
# Fixing the window size.
root.minsize(width=350, height=70)
label = Tkinter.Label(root, text="Willkommen bei Python", fg="red", font="Verdana 30 bold")
label.pack()
f = Tkinter.Frame(root)
start = Tkinter.Button(f, text='Start', width=6, command=lambda:Start(label))
stop = Tkinter.Button(f, text='Stop',width=6,state='disabled', command=Stop)
reset = Tkinter.Button(f, text='Reset',width=6, state='disabled', command=lambda:Reset(label))
f.pack(anchor = 'center',pady=5)
start.pack(side="left")
stop.pack(side ="left")
reset.pack(side="left")
root.mainloop()
Code: Alles auswählen
###########################################
##################################
from time import monotonic
from textual.app import App, ComposeResult
from textual.containers import ScrollableContainer
from textual.reactive import reactive
from textual.widgets import Button, Footer, Header, Static
class TimeDisplay(Static):
"""A widget to display elapsed time."""
start_time = reactive(monotonic)
time = reactive(0.0)
total = reactive(0.0)
def on_mount(self) -> None:
"""Event handler called when widget is added to the app."""
self.update_timer = self.set_interval(1 / 60, self.update_time, pause=True)
def update_time(self) -> None:
"""Method to update time to current."""
self.time = self.total + (monotonic() - self.start_time)
def watch_time(self, time: float) -> None:
"""Called when the time attribute changes."""
minutes, seconds = divmod(time, 60)
hours, minutes = divmod(minutes, 60)
self.update(f"{hours:02,.0f}:{minutes:02.0f}:{seconds:05.2f}")
def start(self) -> None:
"""Method to start (or resume) time updating."""
self.start_time = monotonic()
self.update_timer.resume()
def stop(self):
"""Method to stop the time display updating."""
self.update_timer.pause()
self.total += monotonic() - self.start_time
self.time = self.total
def reset(self):
"""Method to reset the time display to zero."""
self.total = 0
self.time = 0
class Stopwatch(Static):
"""A stopwatch widget."""
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Event handler called when a button is pressed."""
button_id = event.button.id
time_display = self.query_one(TimeDisplay)
if button_id == "start":
time_display.start()
self.add_class("started")
elif button_id == "stop":
time_display.stop()
self.remove_class("started")
elif button_id == "reset":
time_display.reset()
def compose(self) -> ComposeResult:
"""Create child widgets of a stopwatch."""
yield Button("Start", id="start", variant="success")
yield Button("Stop", id="stop", variant="error")
yield Button("Reset", id="reset")
yield TimeDisplay()
class StopwatchApp(App):
"""A Textual app to manage stopwatches."""
CSS_PATH = "PYTHON310\\stopwatch.css"
BINDINGS = [
("d", "toggle_dark", "Toggle dark mode"),
("a", "add_stopwatch", "Add"),
("r", "remove_stopwatch", "Remove"),
]
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Header()
yield Footer()
yield ScrollableContainer(Stopwatch(), Stopwatch(), Stopwatch(), id="timers")
def action_add_stopwatch(self) -> None:
"""An action to add a timer."""
new_stopwatch = Stopwatch()
self.query_one("#timers").mount(new_stopwatch)
new_stopwatch.scroll_visible()
def action_remove_stopwatch(self) -> None:
"""Called to remove a timer."""
timers = self.query("Stopwatch")
if timers:
timers.last().remove()
def action_toggle_dark(self) -> None:
"""An action to toggle dark mode."""
self.dark = not self.dark
if __name__ == "__main__":
app = StopwatchApp()
app.run()
Code: Alles auswählen
######Mechanik ; Schiefer Wurf
print("Schiefer Wurf mit Luftwiderstand")
print(" Luftwiderstand prop v^2")
print("Abschusswinkel alpha ")
import math
from math import sin,cos, pi
g = 9.81 # Erdbeschleunigung (m/s^2)
dt = 0.5 # Zeitschritt (s)
m = 8.8e-3 # Kugelmasse (kg)
rho = 1.06e-3 # Reibungskoeffizient
# Anfangsbedingungen:
t = 0
v0 = 20 # Anfangsgeschwindigkeit (m/s)
#alpha = Abschusswinkel (Grad)
alpha = 45 / 180 * pi # Bogenmass
vx = v0 * cos(alpha)
vy = v0 * sin(alpha)
while t < 5:
print ("%4.1f%8.2f%8.2f" %(t, vy, v0))
v0 = v0 - g * dt
vy = vy + v0 * dt
t = t + dt
print(" meter ",vx)
print(" mm/sec ",v0)
print(" sec von 0 -> Ziel","bei Meter ", t)
print("Abschusswinkel in Grad "", vy ")