Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(optimizePathOrder): new plugin #1848

Open
wants to merge 36 commits into
base: main
Choose a base branch
from

Conversation

KTibow
Copy link
Contributor

@KTibow KTibow commented Nov 23, 2023

Paths can often be optimized by changing their direction.
Base path: M16 14v-2H8v2Z (14b)
Optimized by changing the start: M8 14h8v-2H8Z (13b)
Optimized by reversing direction and changing the start: M8 12h8v2H8z (12b)
This plugin automatically does that!

Flow of the plugin:

  • For each path, break it down into "parts". Each part is a continuous set of instructions. Parts are "valid" if they contain only instructions that we can move around and reverse properly.
  • Send it off to be optimized
    • Remove the args, we'll recalculate them with coords. Any args that have special meaning go into a special property.
    • Disable changing the start if it has a non-round stroke, or if the part isn't closed.
    • Disable changing the direction if the fill rule is nonzero and there's more than one part in the path.
  • Try with reversing (if available) and without reversing
    • Input: reverse the base and coords, and reverse the order if we're reversing this time
    • Output (mutable): an actual set of path commands.
    • Iterate through the possible orders
      • We essentially want to move the first command to the end
      • Remove the first command
      • Adjust the move command to move to the new first command's base, so that it isn't broken
      • Remove the previous last command and re-add it, except this time it can't be z
      • Add the new last command
      • Estimate the length of this new output. If it's better than anything so far, use it.
  • Reconstruct the path from parts
    • If the optimization gets something better than the original, use that
    • If it doesn't or the part was "invalid", use the original

Closes #1847
Closes #78 (damn thats old)

This is an optional plugin. Recent changes have made it fast enough to run on very large files in 100ms though.

Results

Name Standard Multipass
Arch Linux logo -95b -102b
Blobs -116b -117b
Isometric Madness -1637b -2563b
tldr-pages banner 0b 0b
Wikipedia logo -481b -502b

* Those results are outdated, after merging the latest changes I think something elsewhere changed making it less efficient

@@ -17,7 +17,7 @@ exports.description = 'merges multiple paths in one if possible';
exports.fn = (root, params) => {
const {
force = false,
floatPrecision,
floatPrecision = 3,
Copy link
Contributor Author

@KTibow KTibow Nov 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I don't do this, whenever I set an exact value for an argument it leaks out, despite my plugin having a default set. (js2path stores the value exactly, and if it gets called later with a different precision it overrides.)

@KTibow KTibow changed the title New plugin: optimize path order feat(optimizePathOrder): new plugin Nov 24, 2023
@anthonyryan1
Copy link
Contributor

I just thought I'd chime in. This is the first plugin thing I've seen in years that could improve the compression of a few of my hand-optimized ultra small files.

I had previously thought there was little more optimization potential in them.

Great idea

@KTibow KTibow marked this pull request as ready for review January 6, 2024 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants