Files
meelstorm dec036dbcf 2.0.9
2025-10-15 15:58:27 +02:00

390 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Inspectron.Hawkeye.Vision.Geometry;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Point = System.Drawing.Point;
namespace Lindt.Candybox.Demo
{
public partial class MaskControl : UserControl
{
private Bitmap _backBuffer;
private GrahamConvexHull _hull;
private List<VectorLine> _vectorLines;
private EditMode _currentMode = EditMode.Brush;
private bool _isDrawingLine = false;
private Point _lineStartPoint;
private VectorLine _selectedLine;
private bool _isDraggingLine = false;
private bool _isDraggingVertex = false;
private bool _isDraggingStartVertex = false;
private Point _dragOffset;
public MaskControl()
{
InitializeComponent();
_backBuffer = new Bitmap(1800, 1408);
_hull = new GrahamConvexHull();
_vectorLines = new List<VectorLine>();
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public EditMode CurrentMode
{
get => _currentMode;
set
{
_currentMode = value;
// Clear any ongoing operations when mode changes
_isDrawingLine = false;
_isDraggingLine = false;
_isDraggingVertex = false;
_selectedLine = null;
Invalidate();
}
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public List<VectorLine> VectorLines
{
get => _vectorLines;
set => _vectorLines = value;
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public Bitmap Mask { get; set; } = new Bitmap(1800, 1408);
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public Bitmap Original { get; set; } = new Bitmap(1800, 1408);
protected override void OnPaintBackground(PaintEventArgs e)
{
//base.OnPaintBackground(e);
}
private bool _isDown = false;
private Point _lastMouse;
protected override void OnMouseDown(MouseEventArgs e)
{
_isDown = true;
_lastMouse = ConvertCoordinates(new Point(e.X, e.Y));
switch (_currentMode)
{
case EditMode.DrawLine:
if (!_isDrawingLine)
{
_isDrawingLine = true;
_lineStartPoint = _lastMouse;
}
else
{
// Finish drawing line
var newLine = new VectorLine(_lineStartPoint, _lastMouse);
_vectorLines.Add(newLine);
_isDrawingLine = false;
Invalidate();
}
break;
case EditMode.RemoveLine:
var lineToRemove = _vectorLines.FirstOrDefault(line => line.IsPointOnLine(_lastMouse));
if (lineToRemove != null)
{
_vectorLines.Remove(lineToRemove);
Invalidate();
}
break;
case EditMode.MoveLine:
_selectedLine = _vectorLines.FirstOrDefault(line => line.IsPointOnLine(_lastMouse));
if (_selectedLine != null)
{
_isDraggingLine = true;
_dragOffset = new Point(_lastMouse.X - _selectedLine.StartPoint.X, _lastMouse.Y - _selectedLine.StartPoint.Y);
}
break;
case EditMode.MoveVertices:
foreach (var line in _vectorLines)
{
if (line.IsPointNearVertex(_lastMouse, out bool isStartVertex))
{
_selectedLine = line;
_isDraggingVertex = true;
_isDraggingStartVertex = isStartVertex;
break;
}
}
break;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
_isDown = false;
_isDraggingLine = false;
_isDraggingVertex = false;
}
private Pen _pen = new Pen(Color.White, 30);
private Pen _penBlack = new Pen(Color.Black, 30);
protected override void OnMouseMove(MouseEventArgs e)
{
var currentPoint = ConvertCoordinates(new Point(e.X, e.Y));
// Handle brush mode (existing functionality)
if (_currentMode == EditMode.Brush)
{
if (_isDown && e.Button == MouseButtons.Left)
{
using (Graphics g = Graphics.FromImage(Mask))
{
g.DrawLine(_pen, currentPoint.X, currentPoint.Y, _lastMouse.X, _lastMouse.Y);
g.FillEllipse(Brushes.White, _lastMouse.X - 15, _lastMouse.Y - 15, 30, 30);
}
}
if (_isDown && e.Button == MouseButtons.Right)
{
using (Graphics g = Graphics.FromImage(Mask))
{
g.DrawLine(_penBlack, currentPoint.X, currentPoint.Y, _lastMouse.X, _lastMouse.Y);
g.FillEllipse(Brushes.Black, _lastMouse.X - 15, _lastMouse.Y - 15, 30, 30);
}
}
}
// Handle line dragging
else if (_currentMode == EditMode.MoveLine && _isDraggingLine && _selectedLine != null)
{
var deltaX = currentPoint.X - _lastMouse.X;
var deltaY = currentPoint.Y - _lastMouse.Y;
_selectedLine.StartPoint = new Point(_selectedLine.StartPoint.X + deltaX, _selectedLine.StartPoint.Y + deltaY);
_selectedLine.EndPoint = new Point(_selectedLine.EndPoint.X + deltaX, _selectedLine.EndPoint.Y + deltaY);
}
// Handle vertex dragging
else if (_currentMode == EditMode.MoveVertices && _isDraggingVertex && _selectedLine != null)
{
if (_isDraggingStartVertex)
{
_selectedLine.StartPoint = currentPoint;
}
else
{
_selectedLine.EndPoint = currentPoint;
}
}
_lastMouse = currentPoint;
Invalidate();
}
private Pen _contourPen = new Pen(Color.GreenYellow, 3);
private Pen _vectorLinePen = new Pen(Color.DeepPink, 12);
private Brush _vertexBrush = new SolidBrush(Color.Orange);
protected override void OnPaint(PaintEventArgs e)
{
OnPaintInternal(e);
}
void OnPaintInternal(PaintEventArgs e)
{
var mat = Mask.ToMat().CvtColor(ColorConversionCodes.BGR2GRAY);
var contours = mat.FindContoursAsArray(RetrievalModes.External, ContourApproximationModes.ApproxNone);
LastContours = contours;
using (Graphics g = Graphics.FromImage(_backBuffer))
{
g.Clear(Color.Transparent);
g.DrawImage(Original, 0, 0);
// Draw contours
for (int i = 0; i < contours.Length; i++)
{
if (contours[i].Length > 1)
{
var points = contours[i].Select(x => new System.Drawing.Point(x.X, x.Y)).ToArray();
g.DrawPolygon(_contourPen, points);
}
}
// Draw vector lines
foreach (var line in _vectorLines)
{
// Convert coordinates back to display coordinates
var startDisplay = new Point(line.StartPoint.X, line.StartPoint.Y);
var endDisplay = new Point(line.EndPoint.X, line.EndPoint.Y);
g.DrawLine(_vectorLinePen, startDisplay, endDisplay);
// Draw vertices when in move vertices mode
if (_currentMode == EditMode.MoveVertices)
{
g.FillEllipse(_vertexBrush, startDisplay.X - 5, startDisplay.Y - 5, 10, 10);
g.FillEllipse(_vertexBrush, endDisplay.X - 5, endDisplay.Y - 5, 10, 10);
}
}
// Draw temporary line when drawing
if (_currentMode == EditMode.DrawLine && _isDrawingLine)
{
var startDisplay = new Point(_lineStartPoint.X, _lineStartPoint.Y);
var endDisplay = new Point(_lastMouse.X, _lastMouse.Y);
using (var tempPen = new Pen(Color.DeepPink, 12) { DashStyle = System.Drawing.Drawing2D.DashStyle.Dash })
{
g.DrawLine(tempPen, startDisplay, endDisplay);
}
}
// Draw mouse cursor indicator for brush mode
if (_currentMode == EditMode.Brush)
{
var cursorDisplay = new Point(_lastMouse.X, _lastMouse.Y);
g.DrawEllipse(Pens.Gray, cursorDisplay.X - 15, cursorDisplay.Y - 15, 30, 30);
}
}
e.Graphics.DrawImage(_backBuffer, 0, 0, Width, Height);
}
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public OpenCvSharp.Point[][] LastContours { get; set; }
Point ConvertCoordinates(Point coords)
{
return new Point(coords.X * 2, coords.Y * 2);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
}
}
public enum EditMode
{
Brush,
DrawLine,
RemoveLine,
MoveLine,
MoveVertices
}
public class VectorLine
{
public Point StartPoint { get; set; }
public Point EndPoint { get; set; }
public bool Selected { get; set; }
public VectorLine()
{
}
public VectorLine Scale(float sX, float sY)
{
return new VectorLine(new Point((int)(StartPoint.X * sX), (int)(StartPoint.Y * sY)),
new Point((int)(EndPoint.X * sX), (int)(EndPoint.Y * sY)));
}
public VectorLine Translate(int tX, int tY)
{
return new VectorLine(new Point(StartPoint.X + tX, StartPoint.Y + tY),
new Point(EndPoint.X + tX, EndPoint.Y + tY));
}
public VectorLine Translate(Point point)
{
return Translate(point.X, point.Y);
}
public VectorLine Sub(int tX, int tY)
{
return new VectorLine(new Point(StartPoint.X - tX, StartPoint.Y - tY),
new Point(EndPoint.X - tX, EndPoint.Y - tY));
}
public VectorLine Sub(Point point)
{
return Sub(point.X, point.Y);
}
public VectorLine(Point start, Point end)
{
StartPoint = start;
EndPoint = end;
Selected = false;
}
public bool IsPointOnLine(Point point, int tolerance = 10)
{
// Calculate distance from point to line segment
double A = point.X - StartPoint.X;
double B = point.Y - StartPoint.Y;
double C = EndPoint.X - StartPoint.X;
double D = EndPoint.Y - StartPoint.Y;
double dot = A * C + B * D;
double lenSq = C * C + D * D;
if (lenSq == 0) return Math.Sqrt(A * A + B * B) <= tolerance;
double param = dot / lenSq;
double xx, yy;
if (param < 0)
{
xx = StartPoint.X;
yy = StartPoint.Y;
}
else if (param > 1)
{
xx = EndPoint.X;
yy = EndPoint.Y;
}
else
{
xx = StartPoint.X + param * C;
yy = StartPoint.Y + param * D;
}
double dx = point.X - xx;
double dy = point.Y - yy;
return Math.Sqrt(dx * dx + dy * dy) <= tolerance;
}
public bool IsPointNearVertex(Point point, out bool isStartVertex, int tolerance = 15)
{
isStartVertex = false;
double distToStart = Math.Sqrt(Math.Pow(point.X - StartPoint.X, 2) + Math.Pow(point.Y - StartPoint.Y, 2));
double distToEnd = Math.Sqrt(Math.Pow(point.X - EndPoint.X, 2) + Math.Pow(point.Y - EndPoint.Y, 2));
if (distToStart <= tolerance)
{
isStartVertex = true;
return true;
}
if (distToEnd <= tolerance)
{
isStartVertex = false;
return true;
}
return false;
}
}
}