Add Polygon Select to the Lasso tool
Description
When using the lasso tool, crtl-clicking or shift-clicking a point would draw the selection in a straight line from the last selected point to the next.
This would :
- allow selection of polygonal shapes with perfect edges
- make selecting precise shapes easier
- speed up rough selections
Additional context
Discussed in https://github.com/PintaProject/Pinta/discussions/610
Originally posted by enderpuff December 15, 2023 Pretty self explanatory, but polygon selects are very very useful for editing images, for stuff like isolating objects or removing backgrounds, etc...
Doing this as part of the lasso tool sounds reasonable to me 👍
There could also be an option in the toolbar to switch between the two modes, as an alternative idea to the ctrl/shift hotkeys
Here is the untested source code made with an LLM
using System;
using System.Collections.Generic;
using Cairo;
using ClipperLib;
using Pinta.Core;
namespace Pinta.Tools;
public sealed class LassoSelectTool : BaseTool
{
private readonly IWorkspaceService workspace;
private bool is_drawing = false;
private CombineMode combine_mode;
private SelectionHistoryItem? hist;
private List<IntPoint> polygon_points = new List<IntPoint>();
public LassoSelectTool(IServiceProvider services) : base(services)
{
workspace = services.GetService<IWorkspaceService>();
}
public override string Name => Translations.GetString("Lasso Select");
public override string Icon => Pinta.Resources.Icons.ToolSelectLasso;
public override string StatusBarText => Translations.GetString("Click to set points for a polygonal selection area. Click near the starting point to close the selection.");
public override Gdk.Key ShortcutKey => new(Gdk.Constants.KEY_S);
public override Gdk.Cursor DefaultCursor => Gdk.Cursor.NewFromTexture(Resources.GetIcon("Cursor.LassoSelect.png"), 9, 18, null);
public override int Priority => 17;
protected override void OnBuildToolBar(Gtk.Box tb)
{
base.OnBuildToolBar(tb);
workspace.SelectionHandler.BuildToolbar(tb, Settings);
}
protected override void OnMouseDown(Document document, ToolMouseEventArgs e)
{
PointD pd = document.ClampToImageSize(e.PointDouble);
IntPoint ip = new IntPoint((long)Math.Round(pd.X), (long)Math.Round(pd.Y));
if (!is_drawing)
{
hist = new SelectionHistoryItem(workspace, Icon, Name);
hist.TakeSnapshot();
combine_mode = workspace.SelectionHandler.DetermineCombineMode(e);
polygon_points.Clear();
polygon_points.Add(ip);
is_drawing = true;
document.PreviousSelection = document.Selection.Clone();
}
else
{
polygon_points.Add(ip);
if (polygon_points.Count >= 3 && SquaredDistance(polygon_points[polygon_points.Count - 1], polygon_points[0]) < 25)
{
polygon_points.RemoveAt(polygon_points.Count - 1);
document.Selection.SelectionPolygons.Clear();
document.Selection.SelectionPolygons.Add(polygon_points);
SelectionModeHandler.PerformSelectionMode(document, combine_mode, document.Selection.SelectionPolygons);
if (hist != null)
{
document.History.PushNewItem(hist);
hist = null;
}
is_drawing = false;
polygon_points.Clear();
}
}
}
protected override void OnMouseMove(Document document, ToolMouseEventArgs e)
{
if (!is_drawing)
return;
PointD pd = document.ClampToImageSize(e.PointDouble);
IntPoint ip = new IntPoint((long)Math.Round(pd.X), (long)Math.Round(pd.Y));
List<IntPoint> temp_polygon = new List<IntPoint>(polygon_points);
temp_polygon.Add(ip);
document.Selection.SelectionPolygons.Clear();
document.Selection.SelectionPolygons.Add(temp_polygon);
SelectionModeHandler.PerformSelectionMode(document, combine_mode, document.Selection.SelectionPolygons);
document.Workspace.Invalidate();
}
protected override void OnMouseUp(Document document, ToolMouseEventArgs e)
{
// No action needed for polygon lasso
}
private static long SquaredDistance(IntPoint a, IntPoint b)
{
long dx = a.X - b.X;
long dy = a.Y - b.Y;
return dx * dx + dy * dy;
}
}
Can someone please try it?
Replace the LassoSelectTool for a quick test but create both as tools and call this one PolygonLassoSelectTool
I wanna try to tackle this issue.
Although I have some questions on how should this be implemented. Should it use movable control points like the shape tools or once you click you may not move that vertex of the polygon?
Nice !
The way I see it, it would be simpler for the points to not be changeable. Having movable points with handles feels too complex and heavy for Pinta An compromise would be to add the option to backtrack : for example by pressing backspace, you could remove the last points from the selection, and then continue adding more afterwards.
I'd agree with the above - a hotkey to backtrack sounds reasonable and is a lot less complex than building something similar to the shape tools
That sounds good, but wouldn't the backtrack action be redundant to the undo action? My idea was that every time you click and add a new point, a new item is pushed to the history, so you can backtrack with Ctrl+Z.
Alternatively, I could work such that a new item is pushed to the history once the polygon is finalized.
Yeah, I think only adding a new history item once the polygon is finalized would be a good starting point, and consistent with how the existing Lasso select tool works