# dragPath.py
# Andrew Davison, Sept. 2025, ad@coe.psu.ac.th

import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch
import bezUtils


# Track which point is being dragged
dragging = {'point': None, 'index': None}


def onPick(ev):
  # Save which point is clicked
  dragging['point'] = ev.artist
  dragging['index'] = pts.index(ev.artist)


def onRelease(ev):
  dragging['point'] = None
  dragging['index'] = None


def onMotion(ev):
  if dragging['point'] is None or not ev.inaxes:
    return

  # Update the dragged point
  i = dragging['index']
  dragging['point'].set_data([ev.xdata], [ev.ydata])

  # Update control points
  ctrlPts[i] = (ev.xdata, ev.ydata)

  # Update the label position
  labels[i].set_position((ev.xdata + 0.02, ev.ydata + 0.02))

  # Update curve
  bezierPatch.set_path(bezUtils.bezPath(ctrlPts))
  fig.canvas.draw_idle()


# -----------------------------------
ctrlPts = [(0.1, 0.1), (0.3, 0.8),
           (0.7, 0.2), (0.9, 0.9)]

fig, ax = plt.subplots()
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_aspect('equal')

# Draw initial curve
bezierPatch = PathPatch(bezUtils.bezPath(ctrlPts), lw=2,
                  facecolor='none', edgecolor='blue')
ax.add_patch(bezierPatch)

# Draw draggable control points with labels
pts = []
labels = []
for i, (x, y) in enumerate(ctrlPts):
  pts.append(ax.plot(x, y, 'ro',
                  markersize=8, picker=5)[0])
  labels.append(ax.text(x + 0.02, y + 0.02, f"p{i}",
                  fontsize=10, color='black'))

# Connect events
fig.canvas.mpl_connect('pick_event', onPick)
fig.canvas.mpl_connect('button_release_event', onRelease)
fig.canvas.mpl_connect('motion_notify_event', onMotion)

plt.title("Dragable Cubic Bézier Curve")
plt.grid(True)
plt.show()
