
# paraString.py
# Andrew Davison, ad@coe.psu.ac.th, Oct. 2025

"""
Interactive parabola visualization:
- Draws a parabola y = x^2/(4d) with focus (0,d) and directrix y = -d.
- A slider moves a point along the parabola.
- Draws:
    * line from the point to the focus,
    * a vertical line to the directrix,
- Calculates and displays both distances on the graph.
"""

import math
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider


def parabola(x, d):
  return (x * x) / (4 * d)


def drawPoint(px):
  # Update the figure for parabola point x value
  ax.cla()
  ax.set_title("Parabola with Focus and Directrix")

  # draw curve, Focus and directrix 
  ax.plot(xs, ys, color='blue', label='Parabola')
  ax.plot([focus[0]], [focus[1]], 'ro', label='Focus')
  ax.axhline(-d, color='green', linestyle='--', 
                               label='Directrix')

  # draw the point
  py = parabola(px, d)
  ax.plot([px], [py], 'ko', markersize=6, 
                label='Point on parabola')

  # connect p to the focus
  ax.plot([px, focus[0]], [py, focus[1]], 'r-')
  distFocus = math.hypot(px - focus[0], py - focus[1])

  # connect p vertically to the directrix
  ax.plot([px, px], [py, -d], 'g-')
  distDirectrix = abs(py - (-d))

  # draw the distances on the graph (should be the same)
  x1 = (px + focus[0])/2   # focus dist
  y1 = (py + focus[1])/2
  ax.text(x1, y1, f"{distFocus:.2f}", color='red')

  y2 = (py + (-d))/2    # directrix dist
  ax.text(px + 0.2, y2, f"{distDirectrix:.2f}", 
                           color='green')

  ax.legend(loc='upper right')
  ax.set_xlabel('X')
  ax.set_ylabel('Y')
  ax.set_aspect('equal', 'box')
  ax.set_xlim(-10, 10)
  ax.set_ylim(-d - 2, max(ys) + d)


# -------------------------------
# distance from vertex to focus and directrix
d = 3.0
focus = (0, d)

# Parabolic curve coordinates
xs = [i * 0.1 for i in range(-100, 101)]
ys = [parabola(x, d) for x in xs]

fig, ax = plt.subplots(figsize=(8, 6))
plt.subplots_adjust(bottom=0.2)

# slider
sliderAx = fig.add_axes([0.2, 0.05, 0.6, 0.03])
xSlider = Slider(sliderAx, 'x', -8.0, 8.0, 
                   valinit=2.0, valstep=0.1)
xSlider.on_changed(drawPoint)

drawPoint(2.0)  # initial point position
plt.show()

