How to find a point (if any) on quadratic Bezier with a given tangent direction?

bezier, math, python

Solution

Using the notation given in http://pomax.github.io/bezierinfo/#extremities, a quadratic Bezier curve is given by:

B(t) = P1*(1-t)**2 + 2*P2*(1-t)*t + P3*t**2

Therefore, (by taking the derivative of `B` with respect to `t`) the tangent to the curve is given by

B'(t) = -2*P1*(1-t) + 2*P2*(1-2*t) + 2*P3*t
      = 2*(P1 - 2*P2 + P3)*t + 2*(-P1 + P2)

Given some tangent direction `V`, solve

B'(t) = V

for `t`. If there is a solution, `t = ts`, then the point on the Bezier curve which has tangent direction `V` is given by `B(ts)`.

We essentially want to know if two vectors (`B'(t)` and `V`) are parallel or anti-parallel. There is a trick to doing that.

Two vectors, `X` and `Y`, are perpendicular if their dot product is zero. If `X = (a,b)` and `Y = (c,d)` then the dot product of `X` and `Y` is given by

a*c + b*d

So, `X` and `Y` are parallel if `X` and `Y_perp` are perpendicular, where `Y_perp` is a vector perpendicular to `Y`.

In 2-dimensions, if in coordinates `Y = (a,b)` then `Y_perp = (-b, a)`. (There are two perpendicular vectors possible, but this one will do.) Notice that -- using the formula above -- the dot product of `Y` and `Y_perp` is

a*(-b) + b*(a) = 0

So indeed, this jibes with the claim that perpendicular vectors have a dot product equal to 0.

Now, to solve our problem: Let

B'(t) = (a*t+b, c*t+d)
V = (e, f)

Then `B'(t)` is parallel (or anti-parallel) to `V` if or when `B'(t)` is perpendicular to `V_perp`, which occurs when

dot product((a*t+b, c*t+d), (-f, e)) = 0
-(a*t+b)*f + (c*t+d)*e = 0

We know `a`, `b`, `c`, `d`, `e` and `f`. Solve for `t`. If `t` lies between 0 and 1, then `B(t)` is part of the Bezier curve segment between `P1` and `P3`.

Problem

I'm currently working on a python library to extract pen strokes from TrueType fonts - Here I'm defining a stroke as a midline running between a test point and its reflected point. I'm using the term reflected point to refer to the closest point on the opposite side of the 'ink' region which under normal circumstances (apart from say at a serif stem) would also have a tangent in the opposite direction to the test point. I'm working in python using fontTools and a bezier library that I rolled from the processing code described at http://pomax.github.io/bezierinfo/#extremities . Where I'm stuck stuck at the moment is on how to find the point on a quadratic bezier curve that has a given tangent, my mathematics skills are pretty rudimentary on a good day with a clear head [which it is not rite now] so I was hoping someone with a sharper mind could point out a birds eye overview on how to achieve this. At the moment the only thing I can think of is to approach it numerically with something similar to the Newton-Raphson root finding algorithm but evaluating the 1st derivative against the target direction values. I am hoping however there is a symbolic solution as this needs to be run on every other curve for each curve in the glyphs contours.

Original source