Files
XplorePlane/XP.ImageProcessing.RoiControl/PolygonAdorner.cs
T
2026-04-13 14:36:18 +08:00

142 lines
5.0 KiB
C#

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace XP.ImageProcessing.RoiControl
{
/// <summary>
/// 多边形装饰器,用于编辑多边形顶点
/// </summary>
public class PolygonAdorner : Adorner
{
private List<ControlThumb> vertexThumbs = new List<ControlThumb>(); // 顶点控制?
private VisualCollection visualChildren;
private double scaleFactor = 1;
private Models.PolygonROI? polygonROI;
public PolygonAdorner(UIElement adornedElement, double scaleFactor = 1, Models.PolygonROI? roiModel = null)
: base(adornedElement)
{
visualChildren = new VisualCollection(this);
this.scaleFactor = scaleFactor;
this.polygonROI = roiModel;
// 使用ROI模型的Points数量而不是Polygon的Points
int pointCount = polygonROI?.Points.Count ?? 0;
// 创建顶点控制?
for (int i = 0; i < pointCount; i++)
{
var thumb = new ControlThumb();
thumb.DragDelta += HandleDrag;
thumb.DragCompleted += HandleDragCompleted;
thumb.MouseRightButtonDown += HandleRightClick;
thumb.Tag = i;
thumb.Cursor = Cursors.Hand;
vertexThumbs.Add(thumb);
visualChildren.Add(thumb);
}
// 不再创建边中点控制点 - 使用智能插入算法代替
// 用户可以直接点击画布,系统会自动找到最近的边并插入顶点
}
private void HandleDrag(object sender, DragDeltaEventArgs args)
{
Thumb? hitThumb = sender as Thumb;
if (hitThumb == null || polygonROI == null) return;
int index = (int)hitThumb.Tag;
// 直接修改ROI模型的Points
if (index < polygonROI.Points.Count)
{
Point currentPoint = polygonROI.Points[index];
Point newPoint = new Point(
currentPoint.X + args.HorizontalChange,
currentPoint.Y + args.VerticalChange
);
// 使用索引器修改ObservableCollection中的元素
polygonROI.Points[index] = newPoint;
}
// 强制重新布局
InvalidateArrange();
}
private void HandleDragCompleted(object sender, DragCompletedEventArgs args)
{
// 拖拽完成后通知模型更新
if (polygonROI != null)
{
polygonROI.OnPropertyChanged(nameof(polygonROI.Points));
}
}
private void HandleRightClick(object sender, MouseButtonEventArgs e)
{
// 右键删除顶点(至少保?个顶点)
if (polygonROI != null && polygonROI.Points.Count > 3)
{
Thumb? hitThumb = sender as Thumb;
if (hitThumb != null)
{
int index = (int)hitThumb.Tag;
// 删除顶点 - ObservableCollection会自动触发CollectionChanged事件
// PolygonRoiCanvas会监听到这个变化并自动更新Adorner
polygonROI.Points.RemoveAt(index);
e.Handled = true;
}
}
}
protected override Size ArrangeOverride(Size finalSize)
{
// 使用ROI模型的Points而不是Polygon的Points
if (polygonROI != null)
{
double thumbSize = 12 * scaleFactor;
// 布局顶点控制?
for (int i = 0; i < vertexThumbs.Count && i < polygonROI.Points.Count; i++)
{
vertexThumbs[i].Arrange(new Rect(
polygonROI.Points[i].X - (thumbSize / 2),
polygonROI.Points[i].Y - (thumbSize / 2),
thumbSize,
thumbSize));
}
}
else
{
// 备用方案:使用Polygon的Points
Polygon poly = (Polygon)AdornedElement;
double thumbSize = 12 * scaleFactor;
for (int i = 0; i < vertexThumbs.Count && i < poly.Points.Count; i++)
{
vertexThumbs[i].Arrange(new Rect(
poly.Points[i].X - (thumbSize / 2),
poly.Points[i].Y - (thumbSize / 2),
thumbSize,
thumbSize));
}
}
return finalSize;
}
protected override int VisualChildrenCount
{ get { return visualChildren.Count; } }
protected override Visual GetVisualChild(int index)
{ return visualChildren[index]; }
}
}