Calculating Bezier curve speed (= tangents), but something smells fishy

yanone's picture

Dear Bezier masters,

I'm reposting this from here, because it's a different topic and problem now.

I've tried to approach my problem (calculating curve speed) in a more general way, using the general cubic Bezier equation.
I've constructed the first derivative, as suggested. Please correct me, if I made mistakes there. School was a looong time ago. But findings on the internet suggest that I did it right.
The function solveCubic returns as the first argument p1234 (identical to the middle on-curve point calculated by the known splitCubicAtT function, I just skipped the other points for now), then the result of the first derivative.
All are vectors (or coordinates).

The segment used for the results posted below (with t in 0.1 steps) is a quarter of a circle, or a quarter of as close a circle as one can construct with Beziers. The first derivative should then have all equal (more or less) values, right, in case of a circle? In other words, curve speed should be steady at all positions in a circle. Shown in the results in the rightmost column is the absolute value of the vector returned by the first derivative.
But the results differ by 8%. This doesn't look right. I've double-checked for a correct circle pie piece.

Where is the mistake or the misunderstanding?

import numpy, math

def solveCubic(p0, p1, p2, p3, t):
	p0, p1, p2, p3 = numpy.array((p0, p1, p2, p3))

	a = -p0 + 3.0 * p1 - 3.0 * p2 + p3
	b = 3.0 * p0 - 6.0 * p1 + 3.0 * p2
	c = -3.0 * p0 + 3.0 * p1
	d = p0
	
	# Cubic Bezier
	f = a*t**3 + b*t**2 + c*t + d
	
	# First derivative
	f1 = 3*a*t**2 + 2*b*t + c
	
	return f, f1


g = CurrentGlyph()
p1 = (g[0][0].points[0].x, g[0][0].points[0].y)
p2 = (g[0][1].points[0].x, g[0][1].points[0].y)
p3 = (g[0][1].points[1].x, g[0][1].points[1].y)
p4 = (g[0][1].points[2].x, g[0][1].points[2].y)

for t in range(11):

        
    f, f1 = solveCubic(p1, p2, p3, p4, t / 10.0)

    print "t=%s" % (t/10.0), " -  f1=%s=abs %s" % (str(f1).ljust(17), int(math.sqrt( f1[0]**2 + f1[1]**2 )))

The results are:

t=0.0  -  f1=[-327.    0.]        =abs 327
t=0.1  -  f1=[-312.93  -51.33]    =abs 317
t=0.2  -  f1=[-294.72  -98.52]    =abs 310
t=0.3  -  f1=[-272.37 -141.57]    =abs 306
t=0.4  -  f1=[-245.88 -180.48]    =abs 305
t=0.5  -  f1=[-215.25 -215.25]    =abs 304
t=0.6  -  f1=[-180.48 -245.88]    =abs 305
t=0.7  -  f1=[-141.57 -272.37]    =abs 306
t=0.8  -  f1=[ -98.52 -294.72]    =abs 310
t=0.9  -  f1=[ -51.33 -312.93]    =abs 317
t=1.0  -  f1=[   0. -327.]        =abs 327
Syndicate content Syndicate content