An exact circular arc#
Polynomial Bézier curves cannot represent a nonconstant circular arc exactly. A rational quadratic can. For the unit quarter circle, choose
The first and last points lie on the circle; the middle point is the
intersection of their tangent lines. Providing P and W alone creates
a rational Bézier curve of degree two.
Run python demos/documentation/circular_arc.py, or
download the script.
"""Represent an exact quarter circle with a rational quadratic Bezier."""
import numpy as np
import matplotlib.pyplot as plt
import nurbspy as nrb
nrb.set_plot_options()
P = np.array([[1., 1., 0.],
[0., 1., 1.]])
W = np.array([1., 1 / np.sqrt(2), 1.])
# Without a degree or knot vector, these inputs define rational Bezier.
arc = nrb.NurbsCurve(control_points=P, weights=W)
polynomial = nrb.NurbsCurve(control_points=P)
u = np.linspace(0., 1., 301)
C = arc.get_value(u)
radius_error = np.max(np.abs(np.linalg.norm(C, axis=0) - 1.))
curvature = arc.get_curvature(u)
print(f"Maximum radius error: {radius_error:.2e}")
print(f"Maximum curvature error: {np.max(np.abs(curvature - 1.)):.2e}")
print("Midpoint:", arc.get_value(0.5)[:, 0].round(8))
fig, ax = plt.subplots(figsize=(5.5, 5), layout="constrained")
arc.plot_control_points(fig, ax, color="0.6")
ax.lines[-1].set_label("Control polygon")
polynomial.plot_curve(fig, ax, linestyle="--", color=nrb.COLORS_MATLAB[1])
ax.lines[-1].set_label("Polynomial quadratic")
arc.plot_curve(fig, ax, linewidth=2, color=nrb.COLORS_MATLAB[0])
ax.lines[-1].set_label("Rational quadratic: exact circle")
ax.set(xlabel="x", ylabel="y", title="An exact unit quarter circle")
ax.set_aspect("equal", adjustable="box")
ax.legend(fontsize=12)
ax.grid(alpha=0.2)
plt.show()
Output#
The midpoint is [0.70710678 0.70710678]. The radius and curvature are
both one at every sample, with numerical errors close to machine
precision. Removing the weights produces a polynomial quadratic whose
midpoint is \((0.75,0.75)\), outside the unit circle.
Weights make the rational quadratic follow the circle exactly.#
For other radii, planes, or angle spans, use
nurbspy.nurbs_curve_circular_arc.CircularArc. The constructor
returns a helper object; its .NurbsCurve attribute holds the curve.
Angles are in radians, while the resulting curve is evaluated with a
normalized parameter \(u\in[0,1]\).