Skip to content

Make Vector2D inherit from complex and switch internal path operations to complex

What does the merge request do?

First commit: Vector2d inherits from Complex

This is the minimal changeset required to make paths work nicer with numpy (which then enables faster computation through numpy).

We use the builtin complex as a means to store x and y coordinate, which naturally translates to a numpy datatype.

The change comes with a small performance benefit (although the real benefits will come from vectorizing operations):

master this
a = inkex.Vector2d(1, 2) + inkex.Vector2d(2,3) 2.13us 1.78 us
a = abs(inkex.Vector2d(1, 2)) 1.44 us 463 ns

Second commit: switch internal path operations to complex

Only two functions of the path commands were used by extensions: control_points and end_point. In those cases, I've added a ccontrol_points and cend_point function to use in internal computations such as reversing a path.

Also, I've removed the instance checks for PathCommands because that's ridiculously slow compared to a string comparison.

The entire change makes typical path operations about 2-3 times faster (it's better for absolute-only paths and worse for relative-only paths, but doesn't really seem to be affected by path size):

p = inkex.Path('m 58,88 c -10,2 3,13 10,4 z M 32,67 c 14,-5 23,-3 35,7 m 2,-21 c '*20)"
header master this
p.reverse() 950us 364us
p.to_absolute() 291us 146us

I doesn't really help for to_superpath() since at least for me, about 60% of time is spent in copy.deepcopy. That'll be part of a future MR.

Note: additional speedup of path operations would very likely involve

  • duplicating tiny amounts of code (say properly implement the end_point, to_curve, ... methods for relative path commands to save the creation of the corresponding Absolute command)
  • avoiding duplicate evaluation of end_point, etc

Implementation notes

I had to remove the assign method, but this is not required by any of the stock extensions - actually no extensions unit test was touched.

Implementation detail: Vector2d(1) is now legal, since 1 is a legal complex number (1+0j).

Summary for release notes

Vector2d now derives from complex, simplifying the vectorisation of path operations in Numpy. The assign method has been removed as complex is immutable. Path operations have been sped up by basing their internal computation on complex proper.

Checklist

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

Merge request reports