
# catenoid.py
# Andrew Davison, Nov 2025, ad@coe.psu.ac.th

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.widgets import Slider
import math
import numpy as np


def catenoid(a):
  xs = [[a * math.cosh(v/a) * math.cos(u) for u in us] for v in vs]
  ys = [[a * math.cosh(v/a) * math.sin(u) for u in us] for v in vs]
  zs = [[v for u in us] for v in vs]
  return xs, ys, zs


def plotCatenoid(a):
  xs, ys, zs = catenoid(a)
  X = np.array(xs); Y = np.array(ys)
  Z = np.array(zs)
  ax.plot_surface(X, Y, Z, cmap='rainbow', edgecolor='k', alpha=0.8)
  ax.set_xlabel('x'); ax.set_ylabel('y')
  ax.set_zlabel('z')
  ax.set_xlim(-3, 3); ax.set_ylim(-3, 3)
  ax.set_zlim(-1.5, 1.5)
  ax.set_title(f"Catenoid with a = {a:.2f}")


def update(val):
  ax.clear()
  plotCatenoid(sliderA.val)
  fig.canvas.draw_idle()


# ---------------------------
uSteps = 20
vSteps = 20
us = [2*math.pi * i/(uSteps - 1) for i in range(uSteps)]
vs = [-1 + 2*i/(vSteps - 1) for i in range(vSteps)]
a_init = 1

fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')

plotCatenoid(a_init)

plt.subplots_adjust(bottom=0.25)
ax_a = plt.axes([0.25, 0.1, 0.5, 0.03])
sliderA = Slider(ax_a, 'a', 0.3, 2.0, valinit=a_init, valstep=0.01)
sliderA.on_changed(update)

plt.show()
