golang/freetype

raster: stroking unsupported on cubic bezier segments (Add3)

dmoklaf opened this issue · 2 comments

Stroking is unsupported on cubic bezier path segments:
// Add3 adds a cubic segment to the stroker.
func (k *stroker) Add3(b, c, d fixed.Point26_6) {
panic("freetype/raster: stroke unimplemented for cubic segments")
}

There could be 3 alternatives to fix this:

A- Linear flattening: divide the cubic segment into several linear segments before stroking - can be implemented through simple heuristics or through a more evolved subdivision (e.g., http://www.cis.usouthal.edu/~hain/general/Publications/Bezier/BezierFlattening.pdf)

B- Quadratic approx.: subdivide into quadratic segments and stroke them

C- Cubic shifting: subdivide into cubic segments until they are "flat" enough that a simple offset translation is sufficient to generate the stroke curves.

Going forward would require to:
(1) Identify through the litterature the best alternative in terms of rendering quality + execution speed
(2) Implement it

I don't have enough spare time for (1) (already reading 10+ machine learning papers per day!). But, regarding (2), I could implement a simple variant of A (simple subdivisions). B or C would be way too much for my spare time, unless a simple algorithm can be unearthed.

I've always intended to do whatever Skia's software renderer does, since IIRC that's where the quadratic stroking algorithm came from. IIRC it's option C, but it's been years since I've looked at it.

I had the hope that the cubic code would be similar to the quad code, only with more cubic specifics.

So I just had a look to Skia SkStroke.cpp to compare the cubic and the quad code, and indeed they are very similar:
https://www.diffchecker.com/kd8rc3tt

However the quad port to Golang uses a different code structure (clearer but that's only my opinion) which would require me to dig into all the special cases to make sure they are properly ported. I unfortunately dont have the time availability for such a dig :(

For my project I went for B, using http://caffeineowl.com/graphics/2d/vectorial/cubic2quad01.html#the-algo
But this is only a workaround