
# cycloidYT.py
# Andrew Davison, ad@coe.psu.ac.th, Dec. 2025
"""
The cycloid is defined parametrically by

  x = a (t - sin t)
  y = a (1 - cos t)

Since no explicit Cartesian form y(x) exists, the parameter
t must be recovered numerically. 

The cycloid x-equation is rearranged to zero form as
  a (t - sin t) - x = 0

Roots of this equation give the cycloid parameter t

Brent’s method is used
instead of Newton–Raphson because it does not require
derivatives and remains robust at cycloid cusps, where
dx/dt = 0.
"""

import math
from scipy.optimize import brentq



def cycloidYTfromX(x, a):
  archIndex = math.floor(x / archWidth)
  if archIndex != 0:
    # print("Adjusting x to be in first cycloid arch")
    xArch = x - archIndex * archWidth
      # handles negative and too large x values
    # print(f"x = {xArch}")
  else:
    xArch = x
  # cusp handling
  if abs(xArch) < 1e-12 or abs(xArch - archWidth) < 1e-12:
    return 0, 0
  else:
    tMin = 0
    tMax = 2*math.pi
    t = brentq(cycloidT, tMin, tMax, args=(xArch, a))
    y = a * (1 - math.cos(t))
    return y, t + archIndex*2*math.pi


def cycloidT(t, x, a):
  return a * (t - math.sin(t)) - x


# --------------------------------------

a = 1
archWidth = 2*math.pi * a
print(f"a = {a}; archWidth = {archWidth:2f}")

x = float(input("Enter x value: "))

y, t = cycloidYTfromX(x, a)
angle = math.degrees(t)
print(f"y = {y:4f}; t = {angle:.2f} deg")
