Skip to content

Reducing the dependency on CubicSuperPath

What does the merge request do?

CubicSuperPath is a crutch that allows extension authors to think little, but get imperfect results in return (e.g. ambiguity of closed subpaths, approximation with varying / inconsistent number of subpaths for arcs, ill-defined gradient for lines converted to Cubic, etc.) In this MR I add a new API to reduce our dependency on it, and still don't offload much of the lowlevel work to userland code. Three extensions have been ported to show this (plus XAML import, which requires a separate MR).

  • The first commit splits the path.py file into a module with unchanged external API.
  • The second commit adds member functions to PathCommand to compute gradient, normal, curvature, point-from-t, t-from-point, splitting, length. The numerical algorithms are partially taken from bezier.py, partially from svgpathtools (marked in the code). The API will be extended in the future (e.g. PathCommand.intersects()).
  • The other three commits port the Measure extension (the Length part of it), the AddNodes extension and the Convert2Dashes extension, fixing various bugs along the way.

Fixes partially #333, closes #489 (closed)

Implementation notes

Here's a list of the remaining extensions to upgrade (not part of this MR):

Easy to upgrade

Plugin Superpath Bezier Can be expressed without to_curves() Missing functionality
distribute_along_path x x yes
jitternodes x ? what to do with arcs? Needs some usability testing
ink2canvas x yes Arcs are differently parametrized in HTML5
path_mesh_m2p x x
to_absolute x x
longshadow x x probably extension is somewhat broken, I’ll try to repair it

A bit more difficult, but doable and worth it

Plugin Superpath Bezier Can be expressed without to_curves() Missing functionality
measure x x yes COG and area for arcs
dxf_outlines x x yes properly implemented flatten for all curve types
dxf12_outlines x x yes properly implemented flatten for all curve types
flatten x x yes properly implemented flatten for all curve types ( will help #163, which propagates to all the others in the list)
hpgl_encoder x x yes properly implemented flatten for all curve types

Fundamentally impossible to express without to_curves()

Plugin Superpath Bezier Can be expressed without to_curves() Missing functionality
path_mesh_p2m x no Meshgradient Patches only support cubic beziers
interpolate x x ? Probably best left alone (interoplation between arc and bezier, anyone?)

Outside of my expertise

Plugin Superpath Bezier Can be expressed without to_curves() Missing functionality
print_win32 x yes need to convert Arc parameters + World transform. Probably not worth the effort.
gcodetools x x no I’m not going to touch that. There’s about 1000 LOC partially-obsolete path mathematics in there. Some of it might be useful, probably not.

Diffeomorphisms

They always were incorrect on superpaths (particularly lines) as well → commonly it was recommended to „add nodes“ first, but it would be interesting (as in: a master thesis in computational geometry) to implement them properly.

Plugin Superpath Bezier Can be expressed without to_curves() Missing functionality
path_envelope x ? Should be doable. Perspective transform of a bezier is a rational bezier, which can then be approximated again. Perspective transform of an arc is an arc (?)
perspective x ? Same
rubberstretch x ? general diffeomorphisms where straight lines become curved are probably out of range for a proper implementation
patternalongpath x ? Same
twirl x ? Same

Summary for release notes

  • Improve the API for working with path segments, such as: length, split at length, gradient/normal, curvature. Accessible through path.proxy_iterator(), the new methods facilitate a lot of what bezier.py is traditionally used for, but without the loss of information that inherently happens when converting to CubicSuperPath.
  • The Add Nodes extension now gives symmetric results on arcs, and also splits arcs into smaller arcs.
  • The Measure tool (Length measurement) is now more precise for paths containing arcs, e.g. an arc with radius 50mm now has its length reported as 314.1593 (correct value: 314.15926...) instead of 314.1602
  • The Convert to dashes extension is now also more precise for arcs and furthermore doesn't visually change the output for closed subpaths where a dash crosses over the closing position.

Checklist

  • Add unit tests (if applicable)
  • Changes to inkex/ are well documented
  • Clean merge request history
Edited by Jonathan Neuhauser

Merge request reports