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

Initial Implementation for Pencil Tool (Freehand Drawing) #679

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

Conversation

AshishS-1123
Copy link
Contributor

Summary / How this PR fixes the problem?

The Pencil Tool will allow users to draw freehand shapes and squiggles.

When drawing such a canvas item, all the users pointer events would be captured and stored. When rendering these points, we join them using a polyline. While this makes the task of creating such squiggles easy, storing large amounts of points becomes a problem.

To reduce the number of points, we use Schneider's Algorithm. This algorithm will compress the set of points into a set of bezier curves that are very close to what the user originally drew.

Using this algorithm will do two things-

  1. Reduce the number of points.
  2. Make the drawing more aesthetically pleasing. (because bezier curves are very smooth)..
Reference
  1. The Schneider's Algorithm can be found in the book Graphics Gems I. I found a pdf here
  2. The actual code was a little hard to develop. So I referred this repo. The code here is in JavaScript which I translated to Vala as best as I could. I also ran this implementation and my own one on different inputs and checked their outputs. They matched more or less.

Summary of major changes I made

  • Created Lib.Modes.FreehandMode to get user events for creating freehand drawings.
  • Created Models.FreehandModel to store and process the raw points from user events.
  • Used Schneider's Algorithm* to optimize the number of points needed to represent the drawing. Approximates the raw points into a set of bezier curves.

Steps to Test

  • Press P or use the Insert menu to start the pencil tool.
  • Hold down your mouse button and get crazy.
  • As soon as you are done drawing, release the mouse button. The curve should have formed.
  • Double clicking on this item will show the control points of bezier curves formed.

Screenshots

freehand.mp4

Known Issues / Things To Do

Copy link
Collaborator

@mbfraga mbfraga left a comment

Choose a reason for hiding this comment

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

I have not yet reviewed the FreehandMode. There seems to be some general bugginess with some specific traces. Other times it works really nicely. Not sure what exactly triggers the bad behavior. See the screenshot below, where the blue represents roughly the trace I did with my mouse--and the black the result.
Screenshot from 2021-12-18 14-09-41
.

@@ -72,6 +72,23 @@ public class Akira.Drawables.DrawablePath : Drawable {
cr.curve_to (x0, y0, x2, y2, x1, y1);
cr.curve_to (x1, y1, x3, y3, x4, y4);

point_idx += 4;
} else if (commands[i] == Lib.Modes.PathEditMode.Type.BEZIER) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand the difference between CURVE and Bezier--they are both drawing beziers.

return Geometry.Point (x * val, y * val);
}

public double distance (Point pt) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

we should probably add a distance_squared for distance comparisons--so we don't have to do sqrt when not necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants