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 NoSelectedPointFs { get; set; } = new List(); private List GetNoSelectedPoiPs() { var ps = new List(); 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(); 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 { 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 points; public List Points => points ??= new List(); 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()); } } }