尺寸测量功能界面
This commit is contained in:
938
CanFly.Canvas/Shape/FlyShape.cs
Normal file
938
CanFly.Canvas/Shape/FlyShape.cs
Normal file
@ -0,0 +1,938 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CanFly.Canvas.Helper;
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Drawing;
|
||||
|
||||
|
||||
namespace CanFly.Canvas.Shape
|
||||
{
|
||||
[Serializable]
|
||||
public class FlyShape
|
||||
{
|
||||
private const float DFT_VTX_EPSILON = 4f;
|
||||
private float _epsilon = DFT_VTX_EPSILON;
|
||||
|
||||
public float LineWidth { get; set; } = 2f;
|
||||
|
||||
|
||||
#region Shape颜色
|
||||
|
||||
#region drawing
|
||||
public Color line_color = Color.FromArgb(128, 0, 255, 0);
|
||||
public Color fill_color = Color.FromArgb(64, 0, 0, 0);
|
||||
public Color vertex_fill_color = Color.FromArgb(255, 0, 255, 0);
|
||||
#endregion
|
||||
|
||||
#region selecting / hovering
|
||||
public Color select_line_color = Color.FromArgb(255, 255, 255, 255);
|
||||
public Color select_fill_color = Color.FromArgb(64, 0, 255, 0);
|
||||
public Color hvertex_fill_color = Color.FromArgb(255, 255, 255, 255);
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private PointTypeEnum point_type = PointTypeEnum.ROUND;
|
||||
private float point_size = 8.0f;
|
||||
|
||||
private float _scale = 1.0f;
|
||||
private float scale
|
||||
{
|
||||
get
|
||||
{
|
||||
return _scale;
|
||||
}
|
||||
set
|
||||
{
|
||||
_scale = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private ShapeTypeEnum _shape_type;
|
||||
private Matrix _matrix = new Matrix();
|
||||
|
||||
|
||||
|
||||
|
||||
public ShapeTypeEnum ShapeType
|
||||
{
|
||||
get => _shape_type;
|
||||
set { _shape_type = value; }
|
||||
}
|
||||
|
||||
|
||||
public string label = "";
|
||||
public int? group_id = null;
|
||||
private List<PointF> _points
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new List<PointF>();
|
||||
|
||||
public List<PointF> Points
|
||||
{
|
||||
get { return _points; }
|
||||
set
|
||||
{
|
||||
this._points = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<PointF> _pointsRaw = new List<PointF>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 辅助节点
|
||||
/// </summary>
|
||||
public List<PointF> GuidePoints = new List<PointF>();
|
||||
|
||||
public float _currentRotateAngle;
|
||||
private bool _isRotating = false;
|
||||
|
||||
|
||||
public List<int> point_labels = new List<int>();
|
||||
|
||||
|
||||
private ShapeTypeEnum _shape_type_raw;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否填充多边形。使用:select_fill_color 或 fill_color 填充。
|
||||
/// </summary>
|
||||
public bool fill = false;
|
||||
|
||||
|
||||
public bool Selected { get; set; } = false;
|
||||
public object? flags;
|
||||
public string description = "";
|
||||
private List<object> other_data = new List<object>();
|
||||
|
||||
|
||||
private int _highlightIndex = -1;
|
||||
private HighlightModeEnum _highlightMode = HighlightModeEnum.NEAR_VERTEX;
|
||||
|
||||
|
||||
private Dictionary<HighlightModeEnum, HighlightSetting> _highlightSettings = new Dictionary<HighlightModeEnum, HighlightSetting>()
|
||||
{
|
||||
{ HighlightModeEnum.NEAR_VERTEX,new HighlightSetting(4,PointTypeEnum.ROUND)},
|
||||
{ HighlightModeEnum.MOVE_VERTEX,new HighlightSetting(1.5f,PointTypeEnum.SQUARE)},
|
||||
};
|
||||
|
||||
|
||||
private bool _closed = false;
|
||||
private Color _vertex_fill_color;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 当图形是Line时,是否绘制辅助矩形框
|
||||
/// </summary>
|
||||
public bool IsDrawLineVirtualRect { get; set; } = false;
|
||||
/// <summary>
|
||||
/// 画Line时辅助矩形的宽度
|
||||
/// </summary>
|
||||
public float LineVirtualRectWidth = 40;
|
||||
public PointF[] LineVirtualRectPoints = new PointF[4];
|
||||
|
||||
|
||||
public FlyShape()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private PointF ScalePoint(PointF point)
|
||||
{
|
||||
return point;
|
||||
|
||||
//return new PointF(
|
||||
// (float)(point.X * scale),
|
||||
// (float)(point.Y * scale));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void Close()
|
||||
{
|
||||
this._closed = true;
|
||||
}
|
||||
|
||||
|
||||
public void AddPoint(PointF point, int label = 1)
|
||||
{
|
||||
if (_points != null && _points.Count > 0 && point.Equals(_points.ElementAt(0)))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_points.Count > 0 && this[-1].Equals(point))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_points.Add(point);
|
||||
point_labels.Add(label);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public bool CanAddPoint()
|
||||
{
|
||||
return ShapeType == ShapeTypeEnum.Polygon
|
||||
|| ShapeType == ShapeTypeEnum.LineStrip;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public PointF? PopPoint()
|
||||
{
|
||||
if (_points != null && _points.Count > 0)
|
||||
{
|
||||
if (point_labels != null && point_labels.Count > 0)
|
||||
{
|
||||
point_labels.RemoveAt(point_labels.Count - 1);
|
||||
}
|
||||
|
||||
PointF lastPoint = _points[_points.Count - 1];
|
||||
_points.RemoveAt(_points.Count - 1);
|
||||
return lastPoint;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void InsertPoint(int i, PointF point, int label = 1)
|
||||
{
|
||||
_points.Insert(i, point);
|
||||
point_labels.Insert(i, label);
|
||||
}
|
||||
|
||||
|
||||
public void RemovePoint(int i)
|
||||
{
|
||||
if (!CanAddPoint())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ShapeType == ShapeTypeEnum.Polygon && _points.Count <= 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (ShapeType == ShapeTypeEnum.LineStrip && _points.Count <= 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_points.RemoveAt(_points.Count - 1);
|
||||
point_labels.RemoveAt(point_labels.Count - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public bool IsClosed() => _closed;
|
||||
|
||||
|
||||
public void SetOpen() { _closed = false; }
|
||||
|
||||
|
||||
#region 矩形辅助函数
|
||||
|
||||
/// <summary>
|
||||
/// 矩形模式下,选中的点索引
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
private int _rectSelectedVertex = -1;
|
||||
[JsonIgnore]
|
||||
private PointF _rectSelectedMoveVertex;
|
||||
[JsonIgnore]
|
||||
private PointF _rectCenterPoint;
|
||||
|
||||
[JsonIgnore]
|
||||
private bool isVertexMoving;
|
||||
|
||||
/// <summary>
|
||||
/// 正在移动节点
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public bool IsVertexMoving
|
||||
{
|
||||
get
|
||||
{
|
||||
return isVertexMoving;
|
||||
}
|
||||
internal set
|
||||
{
|
||||
//float centerX = (_points[0].X + _points[2].X) / 2f;
|
||||
//float centerY = (_points[0].Y + _points[2].Y) / 2f;
|
||||
//_rectCenterVertex = new PointF(centerX, centerY);
|
||||
isVertexMoving = value;
|
||||
}
|
||||
}
|
||||
//private PointF[] TransformPoints(List<PointF> points, PointF center, float angle)
|
||||
//{
|
||||
// PointF[] ptsArray = points.ToArray();
|
||||
// using (Matrix matrix = new Matrix())
|
||||
// {
|
||||
// matrix.RotateAt(angle, center);
|
||||
// matrix.TransformPoints(ptsArray);
|
||||
// }
|
||||
// return ptsArray;
|
||||
//}
|
||||
//GraphicsPath vrtx_path = new GraphicsPath();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public void Paint(Graphics painter)
|
||||
{
|
||||
if (_points == null || _points.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Color color = Selected ? select_line_color : line_color;
|
||||
using Pen pen = new Pen(color, LineWidth);
|
||||
|
||||
// Create paths
|
||||
GraphicsPath line_path = new GraphicsPath();
|
||||
GraphicsPath vrtx_path = new GraphicsPath();
|
||||
GraphicsPath guide_vrtx_path = new GraphicsPath();
|
||||
|
||||
switch (ShapeType)
|
||||
{
|
||||
//case ShapeTypeEnum.Rectangle:
|
||||
// {
|
||||
// if (_points.Count == 2)
|
||||
// {
|
||||
// float centerX = (_points[0].X + _points[1].X) / 2f;
|
||||
// float centerY = (_points[0].Y + _points[1].Y) / 2f;
|
||||
// _rectCenterPoint = new PointF(centerX, centerY);
|
||||
|
||||
|
||||
// line_path.StartFigure();
|
||||
|
||||
// if (_points[1].X < _points[0].X)
|
||||
// {
|
||||
// _points[1] = new PointF(_points[0].X + LineWidth / 2f, _points[1].Y);
|
||||
// }
|
||||
// if (_points[1].Y < _points[0].Y)
|
||||
// {
|
||||
// _points[1] = new PointF(_points[1].X, _points[0].Y + LineWidth / 2f);
|
||||
// }
|
||||
|
||||
// //float x = Math.Min(_points[0].X, _points[1].X);
|
||||
// //float y = Math.Min(_points[0].Y, _points[1].Y);
|
||||
|
||||
// float w = Math.Abs(ScalePoint(_points[1]).X - ScalePoint(_points[0]).X);
|
||||
// float h = Math.Abs(ScalePoint(_points[1]).Y - ScalePoint(_points[0]).Y);
|
||||
|
||||
// RectangleF drawRect = new(new PointF(_points[0].X, _points[0].Y), new SizeF(w, h));
|
||||
|
||||
// bool bRotated = false;
|
||||
// NomalizeRotateAngle();
|
||||
|
||||
// Matrix oMatrix = null;
|
||||
|
||||
// if (_currentRotateAngle > 0)
|
||||
// {
|
||||
// // Create rotation matrix
|
||||
// oMatrix = new Matrix();
|
||||
// oMatrix.RotateAt(_currentRotateAngle, _rectCenterPoint, MatrixOrder.Append);
|
||||
// painter.Transform = oMatrix;
|
||||
// bRotated = true;
|
||||
// }
|
||||
// //Store rectangle region
|
||||
// //Region _drawRectRegion = new Region(drawRect);
|
||||
// if (oMatrix != null)
|
||||
// line_path.Transform(oMatrix);
|
||||
|
||||
|
||||
// line_path.AddRectangle(drawRect);
|
||||
|
||||
|
||||
// // Reset transform
|
||||
// if (bRotated)
|
||||
// {
|
||||
// bRotated = false;
|
||||
// painter.ResetTransform();
|
||||
// }
|
||||
// //_matrix.Reset();
|
||||
// //_matrix.RotateAt(_currentRotateAngle, new PointF(
|
||||
// // (_points[0].X + _points[1].X) / 2,
|
||||
// // (_points[0].Y + _points[1].Y) / 2));
|
||||
// //line_path.Transform(_matrix);
|
||||
|
||||
|
||||
// //line_path.AddPolygon(_pointsRaw.ToArray());
|
||||
|
||||
// }
|
||||
|
||||
// if (_regionVertex.Length != _points.Count)
|
||||
// {
|
||||
// _regionVertex = new Region[_points.Count];
|
||||
// }
|
||||
|
||||
|
||||
// for (int i = 0; i < _points.Count; i++)
|
||||
// {
|
||||
// DrawVertex(vrtx_path, i);
|
||||
// }
|
||||
|
||||
// vrtx_path.Transform(_matrix);
|
||||
|
||||
// }
|
||||
|
||||
// break;
|
||||
case ShapeTypeEnum.Rectangle:
|
||||
{
|
||||
if (_points.Count == 2)
|
||||
{
|
||||
float centerX = (_points[0].X + _points[1].X) / 2f;
|
||||
float centerY = (_points[0].Y + _points[1].Y) / 2f;
|
||||
_rectCenterPoint = new PointF(centerX, centerY);
|
||||
|
||||
line_path.StartFigure();
|
||||
|
||||
if (_points[1].X < _points[0].X)
|
||||
{
|
||||
_points[1] = new PointF(_points[0].X + LineWidth / 2f, _points[1].Y);
|
||||
}
|
||||
if (_points[1].Y < _points[0].Y)
|
||||
{
|
||||
_points[1] = new PointF(_points[1].X, _points[0].Y + LineWidth / 2f);
|
||||
}
|
||||
|
||||
float w = Math.Abs(ScalePoint(_points[1]).X - ScalePoint(_points[0]).X);
|
||||
float h = Math.Abs(ScalePoint(_points[1]).Y - ScalePoint(_points[0]).Y);
|
||||
|
||||
RectangleF drawRect = new(new PointF(_points[0].X, _points[0].Y), new SizeF(w, h));
|
||||
|
||||
line_path.AddRectangle(drawRect);
|
||||
|
||||
_matrix.Reset();
|
||||
_matrix.RotateAt(_currentRotateAngle, _rectCenterPoint); // 使用更新后的旋转角度
|
||||
line_path.Transform(_matrix);
|
||||
}
|
||||
|
||||
if (_regionVertex.Length != _points.Count)
|
||||
{
|
||||
_regionVertex = new Region[_points.Count];
|
||||
}
|
||||
|
||||
for (int i = 0; i < _points.Count; i++)
|
||||
{
|
||||
DrawVertex1(vrtx_path, i);
|
||||
}
|
||||
|
||||
vrtx_path.Transform(_matrix);
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
case ShapeTypeEnum.Circle:
|
||||
{
|
||||
if (_points.Count == 2)
|
||||
{
|
||||
float radius = PointHelper.Distance(ScalePoint(_points[0]), ScalePoint(_points[1]));
|
||||
line_path.AddEllipse(
|
||||
ScalePoint(_points[0]).X - radius,
|
||||
ScalePoint(_points[0]).Y - radius,
|
||||
radius * 2,
|
||||
radius * 2);
|
||||
}
|
||||
for (int i = 0; i < _points.Count; i++)
|
||||
{
|
||||
DrawVertex(vrtx_path, i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeTypeEnum.LineStrip:
|
||||
{
|
||||
line_path.StartFigure();
|
||||
line_path.AddLine(ScalePoint(_points[0]), ScalePoint(_points[0]));
|
||||
|
||||
for (int i = 0; i < _points.Count; i++)
|
||||
{
|
||||
PointF pt = _points[i];
|
||||
line_path.AddLine(ScalePoint(pt), ScalePoint(pt));
|
||||
DrawVertex(vrtx_path, i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeTypeEnum.Line:
|
||||
{
|
||||
// 添加框线到路径
|
||||
var tmpPoints = _points.Select(p => ScalePoint(p)).ToList();
|
||||
line_path.AddLines(tmpPoints.ToArray());
|
||||
|
||||
if (IsDrawLineVirtualRect && tmpPoints.Count == 2)
|
||||
{
|
||||
var center = new PointF((tmpPoints[0].X + tmpPoints[1].X) / 2,
|
||||
(tmpPoints[0].Y + tmpPoints[1].Y) / 2);
|
||||
|
||||
// 计算两点之间的角度
|
||||
float dx = tmpPoints[1].X - tmpPoints[0].X;
|
||||
float dy = tmpPoints[1].Y - tmpPoints[0].Y;
|
||||
float distance = PointHelper.Distance(tmpPoints[0], tmpPoints[1]);
|
||||
double angle = Math.Atan2(dy, dx) * (180.0 / Math.PI); // 转换为度数
|
||||
|
||||
float l = center.X - distance / 2;
|
||||
float t = center.Y - LineVirtualRectWidth / 2;
|
||||
float r = center.X + distance / 2;
|
||||
float b = center.Y + LineVirtualRectWidth / 2;
|
||||
|
||||
PointF ptLT = new PointF(l, t);
|
||||
PointF ptRT = new PointF(r, t);
|
||||
PointF ptRB = new PointF(r, b);
|
||||
PointF ptLB = new PointF(l, b);
|
||||
#if false
|
||||
RectangleF rect = new RectangleF(ptLT, new SizeF(distance, LineVirtualRectWidth));
|
||||
|
||||
GraphicsPath rectPath = new GraphicsPath();
|
||||
rectPath.AddRectangle(rect);
|
||||
|
||||
//// 设置矩阵以进行旋转和位移
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.RotateAt((float)angle, center); // 旋转
|
||||
|
||||
// 应用变换
|
||||
rectPath.Transform(matrix);
|
||||
// 画框线
|
||||
painter.DrawPath(pen, rectPath);
|
||||
#else
|
||||
RectangleF rect = new RectangleF(ptLT, new SizeF(distance, LineVirtualRectWidth));
|
||||
|
||||
LineVirtualRectPoints = new PointF[4] {
|
||||
ptLT,ptRT,ptRB,ptLB
|
||||
};
|
||||
|
||||
//// 设置矩阵以进行旋转和位移
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.RotateAt((float)angle, center); // 旋转
|
||||
matrix.TransformPoints(LineVirtualRectPoints);
|
||||
|
||||
GraphicsPath rectPath = new GraphicsPath();
|
||||
rectPath.AddPolygon(LineVirtualRectPoints);
|
||||
|
||||
Pen rectpen = new Pen(Color.FromArgb(60, 0, 255, 0), 1);
|
||||
|
||||
// 画框线
|
||||
painter.DrawPath(rectpen, rectPath);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// 添加节点到路径
|
||||
for (int i = 0; i < _points.Count; i++)
|
||||
{
|
||||
DrawVertex(vrtx_path, i);
|
||||
}
|
||||
|
||||
if (IsClosed())
|
||||
{
|
||||
line_path.AddLine(ScalePoint(_points[0]), ScalePoint(_points[0]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ShapeTypeEnum.Polygon:
|
||||
case ShapeTypeEnum.Point:
|
||||
default:
|
||||
{
|
||||
// 添加多边形框线到路径
|
||||
line_path.AddLines(_points.Select(p => ScalePoint(p)).ToArray());
|
||||
|
||||
// 添加节点到路径
|
||||
for (int i = 0; i < _points.Count; i++)
|
||||
{
|
||||
DrawVertex(vrtx_path, i);
|
||||
}
|
||||
|
||||
if (IsClosed())
|
||||
{
|
||||
line_path.AddLine(ScalePoint(_points[0]), ScalePoint(_points[0]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region 将点绘制到画布上
|
||||
|
||||
// 画框线
|
||||
painter.DrawPath(pen, line_path);
|
||||
|
||||
// 填充节点
|
||||
if (vrtx_path.PointCount > 0)
|
||||
{
|
||||
painter.DrawPath(pen, vrtx_path);
|
||||
painter.FillPath(new SolidBrush(vertex_fill_color), vrtx_path);
|
||||
}
|
||||
|
||||
|
||||
if (fill) // 是否填充多边形
|
||||
{
|
||||
Color fillColor = Selected ? select_fill_color : fill_color;
|
||||
painter.FillPath(new SolidBrush(fillColor), line_path);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
|
||||
private Region[] _regionVertex = new Region[] { };
|
||||
|
||||
private void DrawVertex1(GraphicsPath path, int i)
|
||||
{
|
||||
PointF pt = _points[i];
|
||||
_regionVertex[i] = new Region(new RectangleF(
|
||||
pt.X - _epsilon, pt.Y - _epsilon,
|
||||
_epsilon * 2, _epsilon * 2));
|
||||
|
||||
// 将节点变换
|
||||
PointF[] transformedPoint = new PointF[] { pt };
|
||||
_matrix.TransformPoints(transformedPoint); // 变换节点位置
|
||||
|
||||
pt = transformedPoint[0]; // 获取变换后的节点位置
|
||||
|
||||
// 绘制节点
|
||||
float d = point_size; // Point size
|
||||
PointTypeEnum shape = point_type; // Point shape
|
||||
PointF point = ScalePoint(pt);
|
||||
|
||||
if (i == _highlightIndex)
|
||||
{
|
||||
var setting = _highlightSettings[_highlightMode];
|
||||
var size = setting.PointSize;
|
||||
shape = setting.PointType;
|
||||
d *= size; // Example for highlighting
|
||||
}
|
||||
|
||||
if (_highlightIndex >= 0)
|
||||
{
|
||||
_vertex_fill_color = hvertex_fill_color;
|
||||
}
|
||||
else
|
||||
{
|
||||
_vertex_fill_color = vertex_fill_color;
|
||||
}
|
||||
|
||||
switch (shape)
|
||||
{
|
||||
case PointTypeEnum.SQUARE:
|
||||
path.AddRectangle(new RectangleF(point.X - d / 2, point.Y - d / 2, d, d));
|
||||
break;
|
||||
case PointTypeEnum.ROUND:
|
||||
path.AddEllipse(point.X - d / 2, point.Y - d / 2, d, d);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Unsupported vertex shape");
|
||||
}
|
||||
}
|
||||
private void DrawVertex(GraphicsPath path, int i)
|
||||
{
|
||||
PointF pt = _points[i];
|
||||
|
||||
float d = point_size; // Point size
|
||||
PointTypeEnum shape = point_type; // Point shape
|
||||
PointF point = ScalePoint(pt);
|
||||
|
||||
if (i == _highlightIndex)
|
||||
{
|
||||
var setting = _highlightSettings[_highlightMode];
|
||||
var size = setting.PointSize;
|
||||
shape = setting.PointType;
|
||||
d *= size; // Example for highlighting
|
||||
}
|
||||
|
||||
if (_highlightIndex >= 0)
|
||||
{
|
||||
_vertex_fill_color = hvertex_fill_color;
|
||||
}
|
||||
else
|
||||
{
|
||||
_vertex_fill_color = vertex_fill_color;
|
||||
}
|
||||
|
||||
switch (shape)
|
||||
{
|
||||
case PointTypeEnum.SQUARE:
|
||||
path.AddRectangle(new RectangleF(point.X - d / 2, point.Y - d / 2, d, d));
|
||||
break;
|
||||
case PointTypeEnum.ROUND:
|
||||
path.AddEllipse(point.X - d / 2, point.Y - d / 2, d, d);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Unsupported vertex shape");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查找离鼠标最近且距离小于阈值的节点
|
||||
/// </summary>
|
||||
/// <param name="point">鼠标位置</param>
|
||||
/// <param name="epsilon">阈值</param>
|
||||
/// <returns>返回节点的索引</returns>
|
||||
public int NearestVertex(PointF point, float epsilon = DFT_VTX_EPSILON)
|
||||
{
|
||||
switch (ShapeType)
|
||||
{
|
||||
case ShapeTypeEnum.Rectangle:
|
||||
{
|
||||
|
||||
for (int i = 0; i < _regionVertex.Length; i++)
|
||||
{
|
||||
if (_regionVertex[i] == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (_regionVertex[i].IsVisible(point))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
_epsilon = epsilon;
|
||||
float min_distance = float.MaxValue;
|
||||
int min_i = -1;
|
||||
|
||||
PointF scaledPoint = new PointF(point.X * scale, point.Y * scale);
|
||||
|
||||
for (int i = 0; i < _points.Count; i++)
|
||||
{
|
||||
// 缩放顶点
|
||||
PointF scaledVertex = new PointF(_points[i].X * scale, _points[i].Y * scale);
|
||||
float dist = PointHelper.Distance(scaledVertex, scaledPoint);
|
||||
|
||||
// 检查距离是否在 epsilon 范围内
|
||||
if (dist <= epsilon && dist < min_distance)
|
||||
{
|
||||
min_distance = dist;
|
||||
min_i = i;
|
||||
}
|
||||
}
|
||||
|
||||
return min_i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public int NearestEdge(PointF point, float epsilon)
|
||||
{
|
||||
float min_distance = float.MaxValue;
|
||||
int post_i = -1;
|
||||
|
||||
PointF scaledPoint = new PointF(point.X * scale, point.Y * scale);
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < _points.Count; i++)
|
||||
{
|
||||
// 计算边的两个端点
|
||||
PointF start = new PointF(this[i - 1].X * scale, this[i - 1].Y * scale);
|
||||
PointF end = new PointF(this[i].X * scale, this[i].Y * scale);
|
||||
|
||||
// 计算到线段的距离
|
||||
float dist = PointHelper.DistanceToLine(scaledPoint, start, end);
|
||||
|
||||
// 检查距离是否在 epsilon 范围内
|
||||
if (dist <= epsilon && dist < min_distance)
|
||||
{
|
||||
min_distance = dist;
|
||||
post_i = i;
|
||||
}
|
||||
}
|
||||
|
||||
return post_i;
|
||||
}
|
||||
|
||||
|
||||
public bool ContainsPoint(PointF point)
|
||||
{
|
||||
return MakePath().IsVisible(point);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private GraphicsPath MakePath()
|
||||
{
|
||||
GraphicsPath path = new GraphicsPath();
|
||||
|
||||
if (ShapeType == ShapeTypeEnum.Rectangle)
|
||||
{
|
||||
if (_points.Count == 2)
|
||||
{
|
||||
// 创建矩形路径
|
||||
RectangleF rect = new RectangleF(
|
||||
Math.Min(_points[0].X, _points[1].X),
|
||||
Math.Min(_points[0].Y, _points[1].Y),
|
||||
Math.Abs(_points[1].X - _points[0].X),
|
||||
Math.Abs(_points[1].Y - _points[0].Y));
|
||||
|
||||
path.AddRectangle(rect);
|
||||
}
|
||||
}
|
||||
else if (ShapeType == ShapeTypeEnum.Circle)
|
||||
{
|
||||
if (_points.Count == 2)
|
||||
{
|
||||
// 计算半径
|
||||
float radius = PointHelper.Distance(_points[0], _points[1]);
|
||||
path.AddEllipse(_points[0].X - radius, _points[0].Y - radius, radius * 2, radius * 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理多边形
|
||||
path.StartFigure();
|
||||
path.AddLine(_points[0], _points[1]);
|
||||
|
||||
for (int i = 2; i < _points.Count; i++)
|
||||
{
|
||||
path.AddLine(_points[i - 1], _points[i]);
|
||||
}
|
||||
path.CloseFigure(); // 结束图形
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
public RectangleF BoundingRect()
|
||||
{
|
||||
return MakePath().GetBounds();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void MoveBy(PointF offset)
|
||||
{
|
||||
for (int i = 0; i < _points.Count; i++)
|
||||
{
|
||||
_points[i] = new PointF(_points[i].X + offset.X, _points[i].Y + offset.Y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 移动特定顶点
|
||||
/// </summary>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public void MoveVertexBy(int index, PointF offset)
|
||||
{
|
||||
if (index >= 0 && index < _points.Count)
|
||||
{
|
||||
_rectSelectedVertex = index;
|
||||
_rectSelectedMoveVertex = new PointF(_points[index].X, _points[index].Y);
|
||||
_points[index] = new PointF(_points[index].X + offset.X, _points[index].Y + offset.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void HighlightVertex(int i, HighlightModeEnum action)
|
||||
{
|
||||
this._highlightIndex = i;
|
||||
this._highlightMode = action;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void HighlightClear()
|
||||
{
|
||||
_highlightIndex = -1;
|
||||
}
|
||||
|
||||
|
||||
public FlyShape Copy()
|
||||
{
|
||||
var jsonStr = JsonConvert.SerializeObject(this);
|
||||
FlyShape copyShp = JsonConvert.DeserializeObject<FlyShape>(jsonStr);
|
||||
return copyShp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int Length => _points.Count();
|
||||
|
||||
|
||||
|
||||
public PointF this[int index]
|
||||
{
|
||||
|
||||
get
|
||||
{
|
||||
if (index == -1)
|
||||
{
|
||||
return _points[_points.Count - 1];
|
||||
}
|
||||
return _points[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
if (index == -1)
|
||||
{
|
||||
_points[_points.Count - 1] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_points[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void NomalizeRotateAngle()
|
||||
{
|
||||
if (_currentRotateAngle >= 360)
|
||||
{
|
||||
_currentRotateAngle %= 360;
|
||||
}
|
||||
else if (_currentRotateAngle < 0)
|
||||
{
|
||||
_currentRotateAngle = 360 - (-_currentRotateAngle % 360);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user