2

Below I have attached a Python script that calculates a 5-point Bezier curve and calculates the normal acceleration of that curve. The result looks as follows:

enter image description here

We see on the right-hand side that the normal acceleration at the start and end of curve is nonzero. Is there anyway to make sure that the normal acceleration is zero at the boundaries and also remains smooth? I have tried setting high weights for the 2nd and 4th point, this works but does not force it to absolute zero.

Note! it's basically similar to, how do we force the curvature to be zero at the boundaries?

import numpy as np
from scipy.special import comb
import matplotlib.pyplot as plt

# Order of bezier curve
N = 5

# Generate points
np.random.seed(2)
points = np.random.rand(N,2)

''' Calculate bezier curve '''
t = np.linspace(0,1,1000)

polys = np.asarray([comb(N-1, i) * ( (1-t)**(N-1-i) ) * t**i for i in range(0,N)])

curve = np.zeros((t.shape[0], 2))
curve[:,0] = points[:,0] @ polys
curve[:,1] = points[:,1] @ polys

''' Calculate normal acceleration '''
velocity     = np.gradient(curve, axis=0) * t.shape[0]
acceleration = np.gradient(velocity, axis=0) * t.shape[0]

a_tangent    = acceleration * velocity / (velocity[:,[0]]**2 + velocity[:,[1]]**2)
a_tangent    = a_tangent * velocity

a_normal = acceleration - a_tangent
a_normal_mag = np.linalg.norm(a_normal,axis=1)

''' Plotting'''
fig,axes = plt.subplots(1,2)
axes[0].scatter(points[:,0], points[:,1])
axes[0].plot(curve[:,0], curve[:,1])
axes[0].set_xlabel('x(t)')
axes[0].set_xlabel('y(t)')
axes[1].plot(t,a_normal_mag)
axes[1].set_xlabel('t')
axes[1].set_ylabel('a_n(t)')

plt.show()
Thomas Wagenaar
  • 6,489
  • 5
  • 30
  • 73
  • But the normal acceleration _is_ non zero. a Bezier curve is a small segment of an infinite curve, and its first, second, etc. derivatives are all defined at the Bezier "end points". Equally by definition, every point on the curve is affected by _all_ control points, so the only way to get a curvature of zero is if all your points are on a straight line, which won't be super useful. What you _can_ do is use a symmetric bias function. E.g multiply the real value by some f(t)->[0,1], yielding a factor 0 at t=0 and t=1 with relatively steep slopes to/from 1 over most of the t interval. – Mike 'Pomax' Kamermans Nov 10 '21 at 17:56
  • @Mike'Pomax'Kamermans Thanks, I thought of something like that, the problem is that in my real application I also arc-length parameterize the curve and this is no longer an option. – Thomas Wagenaar Nov 11 '21 at 07:43
  • If you've reparameterised on arclength, it's the same same bias function but with the input mapped to [0,1] first - although with length you can even go "ramp up over the first 20 pixels, plateau to 100% until end-20, then ramp down" and get the same behaviour across all your curves (except for curves shorter than your ramp up/down period) – Mike 'Pomax' Kamermans Nov 11 '21 at 17:54

1 Answers1

2

If you want the Bezier curve to have zero 2nd derivative or zero curvature at the ends, the control points can no longer be arbitrary and need to follow a certain "pattern".

For a Bezier curve, its first and 2nd derivatives at t=0 are

C'(0)=d(P1-P0)
C"(0)=d(d-1)(P2-2P1+P0)

where d = degree and P0,P1 and P2 are the first 3 control points.

If you want the curvature at t=0 to be zero, you can choose one of the following 3 conditions:

a) force first derivative to be zero ==> P0=P1.
b) force 2nd derivative to be zero ==> P2-2P1+P0 = 0,
c) force first and 2nd derivatives to be parallel to each other ==> P0, P1 and P2 are collinear.

If you choose to force parallel first and 2nd derivatives at both t=0 and t=1, for a Bezier curve of 5 control points, this means that P2 will be at the intersection of Line(P0,P1) and Line(P3,P4).

fang
  • 3,473
  • 1
  • 13
  • 19