lixiaojun
2024-08-16 8f677b1741b78e4de4c95373fc02587a05d7b5ca
WinFrmUI/Yw.WinFrmUI.Hydro.L2d.Core/02-panel/NetworkPanel.cs
@@ -1,4 +1,5 @@
namespace Yw.WinFrmUI.HydroL2d

namespace Yw.WinFrmUI.HydroL2d
{
    /// <summary>
    /// 管网面板
@@ -19,25 +20,29 @@
            //设置允许的最小尺寸
            this.MinimumSize = new Size(10, 10);
        }
        private Network _network = null;//管网
        private Bitmap _cache = null;//绘制缓存
        private float _zoomMin = 1;//最小缩放层级
        private float _zoomMax = 3200;//最大缩放层级
        private float _zoom = 1;//当前缩放层级
        private float _dxo = 0;//x偏移量
        private float _dyo = 0;//y偏移量
        protected Network _network = null;//管网
        protected RectangleF _networkBounds;//管网边界
        private Bitmap _cache = null;//缓存<依据工作区域创建的空图片>
        private object _cacheLocker = new();//缓存锁
        private Bitmap _disp = null;//显示<在cache基础上进行绘制,最终的显示图片>
        private object _dispLocker = new();//显示锁
        private float _zoomMin = 0.01f;//最小缩放层级
        private float _zoomMax = 10000f;//最大缩放层级
        private float _zoom = 1f;//当前缩放层级
        private float _dxo = 0f;//x偏移量
        private float _dyo = 0f;//y偏移量
        private RectangleF _clientRectf;//工作区域矩形
        #region 初始化
        /// <summary>
        /// 是否初始化
        /// </summary>
        public bool Initialized => _network != null;
        /// <summary>
        /// 初始化
@@ -45,42 +50,385 @@
        public virtual void Initial(Network network)
        {
            _network = network;
            _networkBounds = _network.GetBounds();
            _clientRectf = GetClientRectangleF();
            CreateCache();
            ZoomAll();
        }
        protected override void OnPaint(PaintEventArgs e)
        #endregion
        #region 缓存与显示
        /// <summary>
        /// 创建缓存
        /// </summary>
        protected virtual void CreateCache()
        {
            base.OnPaint(e);
            if (!Initialized)
            {
                return;
            }
            try
            var img = new Bitmap((int)_clientRectf.Width, (int)_clientRectf.Height);
            img.MakeTransparent(Color.White);
            lock (_cacheLocker)
            {
                e.Graphics.PageUnit = GraphicsUnit.Pixel;
                e.Graphics.InterpolationMode = InterpolationMode.High;
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                e.Graphics.PageScale = _zoom;
                e.Graphics.TranslateTransform(_dxo, _dyo);
                e.Graphics.ScaleTransform(1, -1);
                if (_cache != null)
                {
                    _cache.Dispose();
                }
                _cache = img;
            }
            catch
            {
                return;
            }
            _network.Draw(e.Graphics);
        }
        /// <summary>
        /// 界面尺寸发生改变
        /// 绘制缓存
        /// </summary>
        /// <param name="eventargs"></param>
        protected override void OnResize(EventArgs eventargs)
        protected virtual void DrawCache()
        {
            base.OnResize(eventargs);
            ZoomAll();
            if (!Initialized)
            {
                return;
            }
            if (_cache == null)
            {
                return;
            }
            var disp = _cache.CloneC();
            if (disp == null)
            {
                return;
            }
            var dispRect = GetDispRectangleF();
            using (var g = Graphics.FromImage(disp))
            {
                g.PageUnit = GraphicsUnit.Pixel;
                g.InterpolationMode = InterpolationMode.High;
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.PixelOffsetMode = PixelOffsetMode.HighQuality;
                g.PageScale = _zoom;
                g.TranslateTransform(_dxo, _dyo);
                g.ScaleTransform(1, -1);
                //_network.Draw(g, dispRect);
                _network.Draw(g);
            }
            lock (_dispLocker)
            {
                if (_disp != null)
                {
                    _disp.Dispose();
                }
                _disp = disp;
            }
        }
        /// <summary>
        /// 应用缓存
        /// </summary>
        protected virtual void ApplyCache(Graphics g)
        {
            if (!Initialized)
            {
                return;
            }
            lock (_dispLocker)
            {
                if (_disp != null)
                {
                    g.DrawImage(_disp, _clientRectf);
                }
            }
        }
        #endregion
        #region 缩放
        /// <summary>
        /// 缩放等级
        /// </summary>
        public float Zoom
        {
            get => _zoom;
            private set
            {
                if (_networkBounds.IsEmpty)
                {
                    _zoom = 1f;
                    return;
                }
                float sizeMax = Math.Max(_networkBounds.Height, _networkBounds.Width);
                float sizeNew = sizeMax * value;
                if (sizeNew > _zoomMax)
                {
                    _zoom = _zoomMax / sizeMax;
                }
                else if (sizeNew < _zoomMin)
                {
                    _zoom = _zoomMin / sizeMax;
                }
                else
                {
                    _zoom = value;
                }
            }
        }
        /// <summary>
        /// 自适应
        /// </summary>
        public void ZoomAll()
        {
            if (!Initialized)
            {
                return;
            }
            var networkBounds = _network.GetBounds();
            if (networkBounds.IsEmpty)
            {
                return;
            }
            this.Zoom = networkBounds.Width / networkBounds.Height < this.Width / this.Height ?
                this.Height / networkBounds.Height :
                this.Width / networkBounds.Width;
            _dxo = -networkBounds.X;
            _dyo = networkBounds.Bottom;
            this.Zoom *= 0.9f;
            _dxo += this.Width * 0.5f / this.Zoom - networkBounds.Width * 0.5f;
            _dyo += this.Height * 0.5f / this.Zoom - networkBounds.Height * 0.5f;
        }
        private void ZoomToPoint(MouseEventArgs e)
        {
            float scale = e.Delta > 0 ? this.Zoom * 1.5f : this.Zoom / 1.5f;
            var pt = ClientToDispPoint(e.Location);
            this.Zoom = scale;
            _dxo = -pt.X + e.X / this.Zoom;
            _dyo = pt.Y + e.Y / this.Zoom;
        }
        #endregion
        #region 坐标转换
        protected PointF ClientToDispPoint(PointF cp)
        {
            return new PointF(-_dxo + cp.X / _zoom, _dyo - cp.Y / _zoom);
        }
        #endregion
        #region 边框绘制
        /// <summary>
        /// 边框颜色
        /// </summary>
        [Browsable(true)]
        [Description("自定义边框颜色")]
        public Color CustomBorderColor
        {
            get { return _customBorderColor; }
            set { _customBorderColor = value; }
        }
        private Color _customBorderColor = Color.Gray;
        /// <summary>
        /// 边框宽度
        /// </summary>
        [Browsable(true)]
        [Description("自定义边框宽度")]
        public int CustomBorderWidth
        {
            get { return _customBorderWidth; }
            set { _customBorderWidth = value; }
        }
        private int _customBorderWidth = 1;
        /// <summary>
        /// 边框是否显示
        /// </summary>
        [Browsable(true)]
        [Description("自定义边框可见性")]
        [DefaultValue(false)]
        public bool CustomBorderVisible
        {
            get { return _customBorderVisible; }
            set
            {
                _customBorderVisible = value;
            }
        }
        private bool _customBorderVisible = false;
        /// <summary>
        /// 绘制自定义边框
        /// </summary>
        protected virtual void DrawCustomBorder(Graphics g)
        {
            if (this.CustomBorderVisible)
            {
                ControlPaint.DrawBorder(g,
                                                    this.ClientRectangle,
                                                    this.CustomBorderColor, this.CustomBorderWidth, ButtonBorderStyle.Solid,
                                                    this.CustomBorderColor, this.CustomBorderWidth, ButtonBorderStyle.Solid,
                                                    this.CustomBorderColor, this.CustomBorderWidth, ButtonBorderStyle.Solid,
                                                    this.CustomBorderColor, this.CustomBorderWidth, ButtonBorderStyle.Solid);
            }
        }
        #endregion
        #region 获取矩形
        /// <summary>
        /// 获取工作区域
        /// </summary>
        /// <returns></returns>
        protected virtual RectangleF GetClientRectangleF()
        {
            return new RectangleF(0, 0, this.Width, this.Height);
        }
        /// <summary>
        /// 获取显示区域
        /// </summary>
        protected virtual RectangleF GetDispRectangleF()
        {
            if (_clientRectf.IsEmpty)
            {
                return default;
            }
            if (!Initialized)
            {
                return default;
            }
            var pt = ClientToDispPoint(_clientRectf.Location);
            var width = _clientRectf.Width / _zoom;
            var height = _clientRectf.Height / _zoom;
            return new RectangleF(pt, new SizeF(width, height));
        }
        #endregion
        #region 鼠标左键按下拖动
        /// <summary>
        /// 当鼠标左键按下时允许拖动
        /// </summary>
        [Browsable(true)]
        [Description("当鼠标左键按下时允许拖动")]
        [DefaultValue(true)]
        public bool AllowMoveWhenMouseLeftDown
        {
            get => _allowMoveWhenMouseLeftDown;
            set => _allowMoveWhenMouseLeftDown = value;
        }
        private bool _allowMoveWhenMouseLeftDown = true;
        protected bool _hasMouseLeftDown = false;//鼠标左键是否按下
        protected Point _mouseLeftDownMovePoint;//鼠标左键按下移动点
        /// <summary>
        /// 判断鼠标左键是否按下
        /// </summary>
        protected virtual bool HasMouseLeftDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (Initialized)
                {
                    if (this.AllowMoveWhenMouseLeftDown)
                    {
                        _hasMouseLeftDown = true;
                        _mouseLeftDownMovePoint = e.Location;
                        return true;
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// 鼠标左键按下移动
        /// </summary>
        /// <param name="e"></param>
        protected virtual bool MouseLeftDownMove(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (this.AllowMoveWhenMouseLeftDown)
                {
                    if (_hasMouseLeftDown)
                    {
                        if (Initialized)
                        {
                            var pt = new PointF(e.X - _mouseLeftDownMovePoint.X, e.Y - _mouseLeftDownMovePoint.Y);
                            _dxo += pt.X / _zoom;
                            _dyo += pt.Y / _zoom;
                            _mouseLeftDownMovePoint = e.Location;
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// 判断鼠标左键是否弹起
        /// </summary>
        protected virtual bool HasMouseLeftUp(MouseEventArgs e)
        {
            _hasMouseLeftDown = false;
            return true;
        }
        #endregion
        #region 鼠标双击恢复自适应
        /// <summary>
        /// 当鼠标双击时允许自适应
        /// </summary>
        [Browsable(true)]
        [Description("当鼠标双击时允许自适应")]
        [DefaultValue(true)]
        public bool AllowZoomAllWhenMouseDoubleClick
        {
            get => _allowZoomAllWhenMouseDoubleClick;
            set => _allowZoomAllWhenMouseDoubleClick = value;
        }
        private bool _allowZoomAllWhenMouseDoubleClick = true;
        /// <summary>
        /// 鼠标双击时自适应
        /// </summary>
        protected virtual bool ZoomAllWhenMouseDoubleClick(MouseEventArgs e)
        {
            if (e.Clicks > 1)
            {
                if (AllowZoomAllWhenMouseDoubleClick)
                {
                    ZoomAll();
                    return true;
                }
            }
            return true;
        }
        #endregion
        #region 释放资源
        /// <summary>
        /// 释放资源
@@ -94,51 +442,109 @@
        }
        #endregion
        #region 选择
        /// <summary>
        /// 自适应
        /// 选择(通过点选择)
        /// </summary>
        public void ZoomAll()
        protected virtual List<Parter> Select(MouseEventArgs e)
        {
            if (!Initialized)
            {
                return;
            }
            float w = Width;
            float h = Height;
            var networkBounds = _network.GetBounds();
            if (networkBounds.IsEmpty)
            {
                return;
            }
            _zoom = networkBounds.Width / networkBounds.Height < w / h ?
                h / networkBounds.Height :
                w / networkBounds.Width;
            _dxo = -networkBounds.X;
            _dyo = networkBounds.Bottom;
            _zoom *= 0.95f;
            _dxo += w * 0.5f / _zoom - networkBounds.Width * 0.5f;
            _dyo += h * 0.5f / _zoom - networkBounds.Height * 0.5f;
            Invalidate();
            var pt = ClientToDispPoint(e.Location);
            var list = _network.Select(pt);
            return list;
        }
        /// <summary>
        /// 悬停
        /// </summary>
        protected virtual List<Parter> Hover(MouseEventArgs e)
        {
            var pt = ClientToDispPoint(e.Location);
            var list = _network.Hover(pt);
            return list;
        }
        #endregion
        /// <summary>
        /// 重绘
        /// </summary>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            DrawCustomBorder(e.Graphics);
            DrawCache();
            ApplyCache(e.Graphics);
        }
        /// <summary>
        /// 界面尺寸发生改变
        /// </summary>
        /// <param name="eventargs"></param>
        protected override void OnResize(EventArgs eventargs)
        {
            base.OnResize(eventargs);
            _clientRectf = GetClientRectangleF();
            ZoomAll();
            CreateCache();
            this.Invalidate();
        }
        /// <summary>
        /// 鼠标按下
        /// </summary>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            HasMouseLeftDown(e);
        }
        /// <summary>
        /// 鼠标移动
        /// </summary>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            Hover(e);
            MouseLeftDownMove(e);
            this.Invalidate();
        }
        /// <summary>
        /// 鼠标弹起
        /// </summary>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            HasMouseLeftUp(e);
            Select(e);
            this.Invalidate();
        }
        //鼠标滚轮滚动
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            ZoomToPoint(e);
            this.Refresh();
        }
        /// <summary>
        /// 鼠标双击
        /// </summary>
        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            base.OnMouseDoubleClick(e);
            if (ZoomAllWhenMouseDoubleClick(e))
            {
                this.Invalidate();
            }
        }
    }
}