abey79 / vpype

The Swiss-Army-knife command-line tool for plotter vector graphics.
https://vpype.readthedocs.io/
MIT License
690 stars 61 forks source link

Add `smooth` command #216

Open abey79 opened 3 years ago

abey79 commented 3 years ago

Discord discussion: https://discord.com/channels/499297341472505858/748589196532514826/815509855749668866

smoothed = 0.5 * (orig[1:] + orig[:-1])
final_path = resample(orig) + k * resample(smoothed)

From @tatarize:

 for (int i = 1, m = series.size() - 1; i < m; i++) {
            if (!getScene().isRunning()) return;
            double distanceSq = Geometry2D.distanceSqBetweenIndex(series, i, touch.getX(), touch.getY());
            if (distanceSq > toolBrush.getRangeSq()) continue;

            double rr = distanceSq / toolBrush.getRangeSq();

            double smoothProximityFactor = 1 - (smoothProximity * rr);
            if (smoothProximity < 0) {
                smoothProximityFactor += smoothProximity;
            }

            float ox = series.getX(i - 1) + series.getX(i + 1);
            float oy = series.getY(i - 1) + series.getY(i + 1);
            if ((Float.isNaN(ox)) || (Float.isNaN(oy))) continue;

            double sff = smoothFactor * smoothProximityFactor;
            double nx = Geometry2D.towards(series.getX(i), ox / 2, sff);
            double ny = Geometry2D.towards(series.getY(i), oy / 2, sff);
            series.setLocation(i, (float) nx, (float) ny);
            node.notifyChange();
        }
tatarize commented 1 year ago

This is easier in numpy. You're just moving midpoint towards middlepoint.

midpoint = (line[2:] + line[:-2]) / 2.0
middlepoint = line[1:-1]
line[1:-1] = amount * (midpoint - middlepoint) + middlepoint)

And that's basically it. Set a value for amount (scalar between 0-1 (though permit negative amounts because it does some cool stuff that causes it to roughen). And allow the user to specify a number of times to apply the smoothing since it nicely propagates.