Back Original

Parametric half-circle

For my torchlensmaker project, I need to represent lenses surface shapes parameterically. That is, I need equations that give the X and Y coordinates of the surface, as a function of a parameter, usually called t.

The project supports different parametric shapes, but a very popular shape in optics is the arc of circle. So far I had been using the usual polar coordinates parameterization:

X=Rcos(t)+RY=Rsin(t)

This works great, you can represent circles that cross the origin at t=0, and it works for both signs of R (the radius) to represent the two possible curvature directions:

import numpy as np
import matplotlib.pyplot as plt

def half_circle(R, color):
    t = np.linspace(np.pi/2, 3*np.pi/2, 1000)
    X = R * np.cos(t) + R
    Y = R * np.sin(t)
    
    plt.plot(X, Y, color=color)
    plt.gca().set_aspect("equal")

half_circle(10, "orange")
half_circle(-10, "navy")

image1

However, I want to do numerical optimization to find the best possible shape for lenses. This representation has two problems when used for optimization:

The solution I came up with is double:

  1. Use curvature instead of radius. Curvature is the inverse of the radius: K=1/R. This means a line is a circle of curvature zero. Brilliant!

  2. Don't use the angle as the parameter, but the Y coordinate directly. This reduces the shapes we can model to only half-circles, but for optics that's not a problem!

So we know that the Y equation is easy: Y=t. But what about X? Well, I'll spare you the derivation, but here it is:

X=Kt21+1t2K2

And that's a half-circle 🤩! We can also get the derivative with respect to t, which is needed when doing collision detection with Newton's method (more on that in a future article maybe!)

X=Kt1t2K2
import numpy as np
import matplotlib.pyplot as plt

def half_circle(R, color):
    t = np.linspace(-10, 10, 1000)
    K = 1/R
    X = (K * t**2) / (1 + np.sqrt(1 - t**2 * K**2))
    Y = t
    
    plt.plot(X, Y, color=color)
    plt.gca().set_aspect("equal")

half_circle(10, "orange")
half_circle(-10, "navy")

image2

Interestingly, to get some help because I suck at calculus double check my work, I asked both an LLM and Wolfram Alpha to derive the equation. Wolfram Alpha comes out on top with the final form, while LLM gets stuck and can't simplify all the way. They both show step-by-step derivation (although Wolfram Alpha's is behind a paywall).

ChatGPT4o mini (top, derivation not shown) vs Wolfram Alpha (bottom):

image3