import math

def roll_off(
    R_bahn,      # Radius der Kreisbahn (bis Schienenmitte)
    r_cyl,       # Zylinder-Radius
    alpha_deg,   # Startwinkel α (vom Kreistop nach unten, in Grad)
    k=0.5,       # Trägheitsfaktor: I = k * m * r_cyl^2  (Vollzylinder=0.5, Ring=1.0)
    g=9.81
):
    """
    Liefert: theta_deg (Austrittswinkel vom Kreistop), v2 (m/s),
             beta_deg (Abwurfwinkel über Horizontaler), x_max, h_max.
    Annahmen: reines Rollen ohne Gleiten bis zum Kontaktverlust; N=0 => v^2 = g*R_s*cos(theta).
    """
    Rs = R_bahn - r_cyl
    if Rs <= 0:
        raise ValueError("R_bahn muss größer als r_cyl sein (für Rs = R_bahn - r_cyl).")

    alpha = math.radians(alpha_deg)

    # Kontaktverlust-Bedingung + Energieerhaltung:
    # cos(theta) = 2/(3+k) * cos(alpha)
    C = (2.0 / (3.0 + k)) * math.cos(alpha)

    # Prüfbarkeit
    if C > 1.0:
        return {"note": "Kein Kontaktverlust vor dem tiefsten Punkt (cos(theta)>1)."}
    if C < 0.0:
        # formal möglich, aber außerhalb der oberen Halbebene
        pass

    theta = math.acos(max(min(C, 1.0), -1.0))
    v2 = math.sqrt(g * Rs * math.cos(theta))  # aus N=0

    # Tangentialrichtung am Austritt (Einheitsvektor). Wir nehmen den „rechten“ Ast (x>0).
    # Parametrisierung: Punkt auf Kreis (vom Top nach rechts): (x, y) = (Rs*sin(theta), Rs*cos(theta))
    # Tangente (Richtung der Bewegung nach oben rechts): t = (cos(theta), -sin(theta))
    vx, vy = v2 * math.cos(theta), -v2 * math.sin(theta)

    # Abwurfwinkel über Horizontaler:
    beta = math.degrees(math.atan2(vy, vx))  # i.d.R. negativ (leicht nach unten), je nach theta

    # Projektil-Reichweite/Maxhöhe relativ zum Austrittspunkt:
    # Standard-Formeln mit (vx, vy)
    if vy >= 0:
        # steigt zunächst – selten in diesem Setup, aber der Vollständigkeit halber
        t_up = vy / g
        h_max = 0.5 * g * t_up**2
    else:
        h_max = 0.0
    if vy >= 0:
        # allgemeine Reichweite (Rückkehr auf y=0 relativ zum Austritt)
        t_flight = (vy + math.sqrt(vy**2 + 2*g*0)) / g
    else:
        t_flight = ( -vy + math.sqrt(vy**2) ) / g  # = 0 – fällt sofort; setze 0
    x_max = vx * t_flight

    return {
        "Rs_m": Rs,
        "theta_deg": math.degrees(theta),
        "v2_m_s": v2,
        "beta_deg": beta,
        "x_max_m": x_max,
        "h_max_m": h_max,
        "check": "cos(theta) = {:.5f}".format(C)
    }

# Beispiel (Vollzylinder):
if __name__ == "__main__":
    res = roll_off(R_bahn=1.0, r_cyl=0.05, alpha_deg=40.0, k=0.5)
    for k,v in res.items():
        print(f"{k}: {v}")
