question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

solveCubic needs fixes (or perhaps its algorithm replaced)

See original GitHub issue

I’ve been investigating why Robofab’s correctDirection fails to correctly set the direction of some contours, and I think I found one possible cause: the method uses FontTools’ PointInsidePen which in turn relies on solveCubic. What I found in my exploration is that in some cases solveCubic does not return the correct list roots. Observe these two examples:

from fontTools.misc.bezierTools import solveCubic
print solveCubic(-10.0, -9.0, 48.0, -29.0)     #1
print solveCubic(-9.875, -9.0, 47.625, -28.75) #2

Equation 1: -10x³ - 9x² + 48x - 29 = 0 This equation has two solutions, x = 1 and x = -29 / 10. The output of solveCubic is [-2.9, 0.9999999999999993, 1.000000000000001].

Equation 2: -9.875x³ - 9x² + 47.625x - 28.75 = 0 This equation also has two solutions, x = 1 and x = -230 / 79. The output of solveCubic is [-2.911392405063291].

While the rounding error in the results of the first equation is expected, the missing solution(s) in the output of the second equation is a real problem.

There are several methods for solving cubic functions. I’ve experimented with the method detailed on this page. It yielded several more correct path directions, but wasn’t the silver bullet I was hoping for. Perhaps it’s still not the best algorithm, or there are possibly other bugs in the code path chain.

It’d be great if you guys could have a look at this. Thanks!

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:27 (21 by maintainers)

github_iconTop GitHub Comments

1reaction
behdadcommented, Jun 9, 2016

We should remove the P() abstraction from that and add the pen into fonttools.

1reaction
behdadcommented, Jun 9, 2016

but easier than the “true” area of the bezier curves,

Curve area is really simple. Here’s a standalone area-pen:

"""Calculate the area of a glyph."""

import math
from fontTools.pens.basePen import BasePen
from collections import namedtuple

def struct (name, members):
    cls = namedtuple (name, members)
    cls.__repr__ = lambda self: "%s(%s)" % (name, ','.join(str(s) for s in self))
    return cls

class P (struct ('P', ('x', 'y'))):
    pass


def distance(p0, p1):
  return math.hypot(p0.x - p1.x, p0.y - p1.y)

def interpolate(p0, p1, t):
  return P(p0.x * (1 - t) + p1.x * t, p0.y * (1 - t) + p1.y * t)


def polygon_area(p0, p1):
  return (p1.x - p0.x) * (p1.y + p0.y) * 0.5


def quadratic_curve_area(p0, p1, p2):
  new_p2 = interpolate(p2, p1, 2.0 / 3)
  new_p1 = interpolate(p0, p1, 2.0 / 3)
  return cubic_curve_area(p0, new_p1, new_p2, p2)


def cubic_curve_area(p0, p1, p2, p3):
  x0, y0 = p0.x, p0.y
  x1, y1 = p1.x - x0, p1.y - y0
  x2, y2 = p2.x - x0, p2.y - y0
  x3, y3 = p3.x - x0, p3.y - y0
  return (
      x1 * (   -   y2 -   y3) +
      x2 * (y1        - 2*y3) +
      x3 * (y1 + 2*y2       )
  ) * 0.15


class AreaPen(BasePen):

    def __init__(self, glyphset):
        BasePen.__init__(self, glyphset)
        self.value = 0

    def _moveTo(self, p0):
        pass

    def _lineTo(self, p1):
        p0 = self._getCurrentPoint()
        self.value += polygon_area(P(*p0), P(*p1))

    def _curveToOne(self, p1, p2, p3):
        p0 = self._getCurrentPoint()
        self.value += cubic_curve_area(P(*p0), P(*p1), P(*p2), P(*p3))
        self.value += polygon_area(P(*p0), P(*p3))
Read more comments on GitHub >

github_iconTop Results From Across the Web

Solving Cubic Polynomials
Solve this system by substitution and then assign x := a - b. For example, we might replace a by P. 3b. (using...
Read more >
How to Solve a Cubic Equation Part 2 – The 11 Case
We will use this formula to find the effects of a given set of s, t , u, and v values on the...
Read more >
Cubic equation - Wikipedia
In algebra, a cubic equation in one variable is an equation of the form ... approximations of the roots can be found using...
Read more >
Need better contour winding direction detection algorithm. · Issue ...
Need better contour winding direction detection algorithm. #15 ... solveCubic needs fixes (or perhaps its algorithm replaced) fonttools/fonttools#617.
Read more >
Is there really analytic solution to cubic equation?
So is there some algorithm to analytically solve cubic equation without guessing and rounding (I want to solve it symbolically)? How do the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found