using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.Drawing;
|
using System.Drawing.Drawing2D;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using System.Windows.Forms;
|
|
namespace DPumpHydr.WinFrmUI.WenSkin.Controls;
|
|
public class NestBox : Control
|
{
|
private PoiList pois;
|
|
public NestBox()
|
{
|
base.SetStyle(
|
ControlStyles.UserPaint |
|
ControlStyles.DoubleBuffer |
|
ControlStyles.OptimizedDoubleBuffer |
|
ControlStyles.AllPaintingInWmPaint |
|
ControlStyles.ResizeRedraw |
|
ControlStyles.SupportsTransparentBackColor, true);
|
base.UpdateStyles();
|
this.BackColor = Color.Transparent;
|
}
|
|
|
[Category("文"), Description("限制移动只允许内部区域"), DefaultValue(false)]
|
public bool IsLimitRec { get; set; } = true;
|
|
|
public float L { get; set; } = 2400;
|
public float W { get; set; } = 1200;
|
public float H { get; set; } = 18;
|
|
private float Sc => this.Width / this.L;
|
|
|
|
public Poi SelectedPoi { get; set; }
|
|
|
protected override void OnSizeChanged(EventArgs e)
|
{
|
base.OnSizeChanged(e);
|
this.Width = (int)(this.Height * (L / W));
|
}
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
{
|
base.OnPaint(e);
|
|
|
Graphics g = e.Graphics.SetGDIHigh();
|
|
|
//画底层框
|
using Pen p = new Pen(Color.Gray, 3);
|
//画底层框
|
using Pen px = new Pen(Color.Gray, 1)
|
{
|
DashStyle = DashStyle.Dot,
|
};
|
g.DrawRectangle(p, 0, 0, this.Width - 1, this.Height - 1);
|
|
for (int i = 0; i < this.W; i += 100)
|
{
|
g.DrawLine(px, 0, i * Sc, this.Width, i * Sc);
|
}
|
for (int i = 0; i < this.L; i += 100)
|
{
|
g.DrawLine(px, i * Sc, 0, i * Sc, this.Height);
|
}
|
|
DrawPoi(g);
|
}
|
|
|
private void DrawPoi(Graphics g)
|
{
|
if (this.Pois.Count <= 0)
|
{
|
return;
|
}
|
|
|
foreach (var poi in Pois)
|
{
|
g.FillPath(Brushes.Black, poi.GetGraphicsPath(this.Sc));
|
if (poi == SelectedPoi)
|
{
|
using var p = new Pen(Color.Red, 3)
|
{
|
Alignment = PenAlignment.Inset,
|
DashStyle = DashStyle.Dot,
|
};
|
g.DrawPath(p, poi.GetGraphicsPath(this.Sc));
|
|
g.FillRectangle(Brushes.Aqua, new RectangleF((poi.BasicPoint.X) * this.Sc, (poi.BasicPoint.Y) * this.Sc, 8, 8));
|
}
|
}
|
}
|
|
|
|
#region 鼠标操作
|
|
private bool isMouseDown = false;
|
private PointF mouseDownPoint = new PointF(0, 0);
|
|
//鼠标进入控件
|
protected override void OnMouseMove(MouseEventArgs e)
|
{
|
base.OnMouseMove(e);
|
|
var p = new PointF(e.X / Sc, e.Y / Sc);
|
|
if (this.Pois.IsVisible(p))
|
{
|
Cursor = Cursors.SizeAll;
|
}
|
else
|
{
|
Cursor = Cursors.Default;
|
}
|
|
|
|
var x = e.X - mouseDownPoint.X;
|
var y = e.Y - mouseDownPoint.Y;
|
|
if (this.SelectedPoi != null && isMouseDown)
|
{
|
var mx = (int)(x / Sc);
|
var my = (int)(y / Sc);
|
|
if (this.SelectedPoi.IsOffsetBasicPointIsVisible(mx, my, new RectangleF(0, 0, L, W)))
|
{
|
this.SelectedPoi.OffsetBasicPoint(mx, my);
|
|
var po = this.SelectedPoi.BasicPoint;
|
|
//判断基点是否考进指定点
|
|
//获取最小值
|
var mmx = this.NoSelectedPointFs.OrderBy(p => Math.Abs(p.X - po.X)).First();
|
var mmy = this.NoSelectedPointFs.OrderBy(p => Math.Abs(p.Y - po.Y)).First();
|
|
|
|
//判断当前坐标是否接近整数
|
var px = Math.Abs((po.X + mx) % 100);
|
var py = Math.Abs((po.Y + my) % 100);
|
|
var nx = Math.Abs(mmx.X - po.X) <= 10 ? mmx.X : px <= 5 ? po.X - px : px >= 95 ? po.X - px + 100 : po.X;
|
var ny = Math.Abs(mmy.Y - po.Y) <= 10 ? mmy.Y : py <= 5 ? po.Y - py : py >= 95 ? po.Y - py + 100 : po.Y;
|
|
//Console.WriteLine(mmx);
|
//Console.WriteLine(mmy);
|
//Console.WriteLine(po);
|
//Console.WriteLine();
|
this.SelectedPoi.BasicPoint = new PointF(nx, ny);
|
}
|
|
this.Invalidate();
|
mouseDownPoint = e.Location;
|
}
|
}
|
|
protected override void OnMouseDown(MouseEventArgs e)
|
{
|
base.OnMouseDown(e);
|
var p = new PointF(e.X / Sc, e.Y / Sc);
|
|
this.isMouseDown = true;
|
this.mouseDownPoint = e.Location;
|
|
this.SelectedPoi = this.Pois.GetMousePoi(p);
|
if(this.SelectedPoi!=null)
|
{
|
NoSelectedPointFs = GetNoSelectedPoiPs();
|
}
|
this.Invalidate(true);
|
}
|
|
protected override void OnMouseUp(MouseEventArgs e)
|
{
|
base.OnMouseUp(e);
|
this.isMouseDown = false;
|
}
|
|
|
|
|
#endregion
|
|
|
|
private List<PointF> NoSelectedPointFs { get; set; } = new List<PointF>();
|
|
private List<PointF> GetNoSelectedPoiPs()
|
{
|
var ps = new List<PointF>();
|
foreach (var p in this.Pois.FindAll(x => x != this.SelectedPoi).ToList())
|
{
|
ps.AddRange(p.GetPointFs());
|
}
|
return ps;
|
}
|
|
|
|
//检查是否重叠
|
public void Rrr()
|
{
|
var ls = new List<Poi>();
|
|
for (int i = 0; i < this.Pois.Count; i++)
|
{
|
var gp = this.Pois[i].GetGraphicsPath();
|
|
for (int j = i + 1; j < this.Pois.Count; j++)
|
{
|
var ps = this.Pois[j].GetPointFs();
|
foreach (var p in ps)
|
{
|
if (gp.IsVisible(p))
|
{
|
ls.Add(this.pois[j]);
|
ls.Add(this.pois[i]);
|
break;
|
}
|
}
|
}
|
}
|
var xs = ls.Distinct();
|
}
|
|
|
public PoiList Pois => this.pois ??= new PoiList(this);
|
|
|
public class PoiList : List<Poi>
|
{
|
private NestBox owner;
|
|
public PoiList(NestBox owner)
|
{
|
this.owner = owner;
|
}
|
|
public bool IsVisible(PointF p)
|
{
|
foreach (var poi in Enumerable.Reverse(this))
|
{
|
if (poi.GetGraphicsPath().IsVisible(p))
|
return true;
|
}
|
return false;
|
}
|
|
public Poi GetMousePoi(PointF p)
|
{
|
foreach (var poi in Enumerable.Reverse(this))
|
{
|
if (poi.GetGraphicsPath().IsVisible(p))
|
return poi;
|
}
|
return null;
|
}
|
|
public new void Add(Poi poi)
|
{
|
base.Add(poi);
|
owner.Invalidate();
|
}
|
}
|
|
public class Poi
|
{
|
|
private List<PointF> points;
|
public List<PointF> Points => points ??= new List<PointF>();
|
|
public PointF BasicPoint { get; set; } = new PointF(0, 0);
|
|
|
public int Rotate { get; set; } = 0;
|
|
public PointF[] GetPointFs(float sc = 1)
|
{
|
return Points.Select(x => new PointF((x.X + this.BasicPoint.X) * sc, (x.Y + this.BasicPoint.Y) * sc)).ToArray();
|
}
|
|
|
|
public GraphicsPath GetGraphicsPath(float sc = 1)
|
{
|
var gp = new GraphicsPath();
|
gp.AddLines(GetPointFs(sc));
|
gp.CloseAllFigures();
|
|
var rec = gp.GetBounds();
|
var matrix = new Matrix();
|
matrix.RotateAt(this.Rotate, new PointF(rec.X + rec.Width / 2, rec.Y + rec.Height / 2));
|
gp.Transform(matrix);
|
return gp;
|
}
|
|
public void SetBasicPoint(PointF p)
|
{
|
this.BasicPoint = p;
|
}
|
|
public void OffsetBasicPoint(float x, float y)
|
{
|
this.BasicPoint = new PointF(this.BasicPoint.X + x, this.BasicPoint.Y + y);
|
}
|
|
|
public bool IsOffsetBasicPointIsVisible(float x, float y, RectangleF inrec)
|
{
|
var pos = Points.Select(it => new PointF(it.X + this.BasicPoint.X + x, it.Y + this.BasicPoint.Y + y)).ToArray();
|
var gp = new GraphicsPath();
|
gp.AddLines(pos);
|
gp.CloseAllFigures();
|
|
var rec = gp.GetBounds();
|
var matrix = new Matrix();
|
matrix.RotateAt(this.Rotate, new PointF(rec.X + rec.Width / 2, rec.Y + rec.Height / 2));
|
gp.Transform(matrix);
|
|
return inrec.Contains(gp.GetBounds());
|
}
|
}
|
}
|