cloudflight
2024-06-15 28e1c9f3b620567acced4730cc36368090a6abe5
Hydraulic/Hydro.MapUI/Map/MapViewer.cs
@@ -1,7 +1,7 @@
//using CloudWaterNetwork.Magnifier;
using DevExpress.Diagram.Core.Layout;
using DevExpress.XtraPrinting;
using DevExpress.XtraEditors;
using Hydro.CommonBase;
using Hydro.Core.Model;
using Hydro.Inp;
//using ConfigApp;
//using DevExpress.Diagram.Core.Layout;
@@ -9,6 +9,7 @@
//using DevExpress.Utils.Extensions;
//using dict_py_Inner;
using Hydro.MapView;
using Hydro.MapView.Base;
using Hydro.MapView.Common;
using Newtonsoft.Json;
//using ReflectionManager_NameSpace;
@@ -29,6 +30,7 @@
using System.Runtime.Remoting.Metadata;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
@@ -107,7 +109,6 @@
        //}
        public MapViewer(bool showToolBar = false)
        {
@@ -130,11 +131,15 @@
            MapCenter = PointF.Empty;
            zoom = 1.0f;
            DoubleBuffered = true;
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            BackColor = Color.Transparent;
        }
        public void SetEditMode(bool isEditMode)
        {
            _IsEditMode= isEditMode;
        }
        private void MapViewer_Load(object sender, EventArgs e)
        {
            this.panel1.Visible = _showToolBar;
@@ -164,7 +169,65 @@
            cb_Link_Colour.SelectedIndex = 0;
            map.Init(TC,new DrawDelegate[] { Draw, Draw, DrawBackGroud, DrawH },new MouseDelegate[] { mapMouseDown, mapMouseMove, mapMouseUp, mapMouseWheel });
            TContainer TCCube = new TContainer();
            TCCube.template = new Template();
            TCCube.template.network = new MapViewNetWork();
            TCCube.template.network.Areas = new List<AreaViewModel>();
            Cube cb=new Cube();
            foreach (var item in cb.FacesVertices)
            {
                AreaViewModel area = new AreaViewModel();
                area.ID = item.Key.ToString();
                area.InnerNodes = new List<NodeViewModel>();
                //area.Name= item.Key.ToString();
                //6个面设置不一样的颜色
                switch (item.Key)
                {
                    case 1:
                        area.color = Color.Red;
                        area.Name = "右";
                        break;
                    case 2:
                        area.color = Color.SkyBlue;
                        area.Name = "左";
                        break;
                    case 3:
                        area.color = Color.Green;
                        area.Name = "后";
                        break;
                    case 4:
                        area.color = Color.DarkBlue;
                        area.Name = "前";
                        break;
                    case 5:
                        area.color = Color.Purple;
                        area.Name = "上";
                        break;
                    case 6:
                        area.color = Color.Orange;
                        area.Name = "下";
                        break;
                    default:
                        area.color = Color.White;
                        break;
                }
                foreach (var p in item.Value)
                {
                    NodeViewModel node = new NodeViewModel();
                    node.X = p.X;
                    node.Y = p.Y;
                    node.Elev = p.Z;
                    area.InnerNodes.Add(node);
                }
                TCCube.template.network.Areas.Add(area);
            }
            CubeView.Init(TCCube, new DrawDelegate[] { Draw, Draw, DrawBackGroud, DrawH }, new MouseDelegate[] { mapMouseDown, mapMouseMove, mapMouseUp, mapMouseWheel });
        }
        #endregion
@@ -174,7 +237,7 @@
        public bool LoadData(bool isDelCache = false)
        {
            if (_Template == null) return false;
            if (isDelCache || _Template.network == null)
            {
@@ -243,7 +306,7 @@
            zoom = 1.0f;
            Rotation = 0;
            RotationF = 90;
            Invalidate();
            SetMapInvalidate();
        }
        public void SetData(Template template, dict<string, dynamic> param = null, Dictionary<TemplateType, bool> viewMode = null)
        {
@@ -251,7 +314,7 @@
            bool reLoad = _Template == template;
            this._Template = template;
            this._ViewModel = viewMode;
            //if ( _Template?.Floors!=null)
            //{
@@ -266,7 +329,7 @@
            //            { 
            //                this.mapOption= f.MapView.Copy();
            //            }
            //            this.Invalidate();
            //            this.SetInvalidated();
            //        };
            //        ToolStripMenuItem_Floor.DropDownItems.Add(btn);
@@ -291,11 +354,15 @@
                    //Rotation = _Template.view.rotation;
                    //RotationF = _Template.view.rotationF;
                    this.mapOption = _Template.view.Copy();
                    SetInvalidated();
                    SetMapInvalidate();
                }
            }
            刷新楼层ToolStripMenuItem_Click(1, new EventArgs());
            //Invalidate();
            label_center.Text = $"center:({MapCenter.X.ToString("0.00")} ,{MapCenter.Y.ToString("0.00")})";
            label_zoom.Text = $"Zoom:{zoom.ToString("0.000")}";
            toolStripStatusLabel_rotation.Text = $"Rotation:({Rotation.ToString("0")},{RotationF.ToString("0")})";
            //SetInvalidated();
        }
        private void InitCenter()
@@ -316,7 +383,7 @@
            float x_span = x1 - x0, y_span = y1 - y0;
            zoom = Math.Min(Width / x_span, Height / y_span);
            zoom = Math.Min(this.map.Width / x_span, this.map.Height / y_span);
            zoom = Math.Max(zoom, MinZoom);
            zoom = Math.Min(zoom, MaxZoom);
@@ -332,10 +399,13 @@
            MapCenter = p;
        }
        public void SetInvalidated()
        public void SetMapInvalidate()
        {
            Invalidate();
            _needPaintAll = true;
            PMin_Show = ScreenToMap(new PointF(0, this.map.Height));
            PMax_Show = ScreenToMap(new PointF(this.map.Width, 0));
            _timerDraw = true;
        }
@@ -344,14 +414,14 @@
        {
            _StartPoint = node1;
            _EndPoint = node2;
            Invalidate();
            SetMapInvalidate();
        }
        public void Set3DView(bool is3Dview, double 俯视角度)
        {
            this.RotationF = 俯视角度;
            this.is3Dview = is3Dview;
            Invalidate();
            SetMapInvalidate();
        }
@@ -359,310 +429,11 @@
        public void SetRotation(double d)
        {
            this.Rotation = d;
            Invalidate();
            SetMapInvalidate();
        }
        #endregion
        #region 基础坐标转换方法
        /// <summary>
        /// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
        /// </summary>
        /// <param name="screenPos"></param>
        /// <returns></returns>
        private PointF ScreenToVMap(PointF screenPos, float z = 0)
        {
            var centerX = Width / 2;
            var centerY = Height / 2;
            var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X;
            var worldY = (screenPos.Y - centerY) / Zoom.Y + 0;
            //if (is3Dview) worldY = -(screenPos.Y - centerY + 2 * z) / (0.5f* zoom) + center.Y;
            return new PointF(worldX, worldY);
        }
        /// <summary>
        /// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
        /// </summary>
        /// <param name="screenPos"></param>
        /// <returns></returns>
        private PointF ScreenToMap(PointF screenPos, float z = 0)
        {
            var centerX = Width / 2;
            var centerY = Height / 2;
            var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X;
            var worldY = (screenPos.Y - centerY - Z(z).Y) / Zoom.Y + MapCenter.Y;
            //if (is3Dview) worldY = -(screenPos.Y - centerY + 2 * z) / (0.5f* zoom) + center.Y;
            return new PointF(worldX, worldY);
        }
        private PointF MapToScreen(PointF mapPos, float z = 0)
        {
            var centerX = Width / 2;
            var centerY = Height / 2;
            var screenX = (mapPos.X - MapCenter.X) * Zoom.X + centerX + Z(z).X;
            var screenY = (mapPos.Y - MapCenter.Y) * Zoom.Y + centerY + Z(z).Y;
            //if (is3Dview) screenY = -(mapPos.Y - center.Y) * (0.5f * zoom) + centerY - 2 * z;
            return new PointF(screenX, screenY);
        }
        // 根据旋转角度计算旋转后的坐标
        // 根据旋转角度计算旋转后的坐标
        private PointF Get平面旋转Point(PointF p)
        {
            PointF center = MapCenter;
            double radian = Rotation * Math.PI / 180;  // 角度转弧度
            float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X);
            float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y);
            return new PointF(x, y);
        }
        private PointF Get平面还原Point(PointF p)
        {
            PointF center = MapCenter;
            double radian = -Rotation * Math.PI / 180;  // 角度转弧度
            float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X);
            float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y);
            return new PointF(x, y);
        }
        private PointF Get俯视角旋转Point(PointF p, float z)
        {
            PointF center = MapCenter;
            double radian_fushi = 俯视弧度;
            float sin = (float)Math.Sin(radian_fushi);
            float cos = (float)Math.Cos(radian_fushi);
            float x = (float)p.X;
            float y = (float)(sin * (p.Y - center.Y) + center.Y) + cos * z;
            return new PointF(x, y);
        }
        private PointF Get俯视角还原Point(PointF p, float z)
        {
            PointF center = MapCenter;
            double radian_fushi = 俯视弧度;
            float sin = (float)Math.Sin(radian_fushi);
            float cos = (float)Math.Cos(radian_fushi);
            float x = (float)p.X;
            float y = (p.Y - center.Y - cos * z) / sin + center.Y;
            return new PointF(x, y);
        }
        private PointF GetRotateVector(PointF p, PointF p0)
        {
            double radian = Rotation * Math.PI / 180;  // 角度转弧度
            float x = (float)(Math.Cos(radian) * (p.X - p0.X) - Math.Sin(radian) * (p.Y - p0.Y));
            float y = (float)(Math.Sin(radian) * (p.X - p0.X) + Math.Cos(radian) * (p.Y - p0.Y));
            return new PointF(x, y);
        }
        /// <summary>
        /// 获取地图投影坐标
        /// </summary>
        /// <param name="point"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        private PointF WorldPointToMapPoint(PointF point, float z, PointF3D offset = null)
        {
            if (offset == null) offset = new PointF3D(0, 0, 0);
            point = new PointF(point.X + offset.X, point.Y + offset.Y);
            var pointR = Get平面旋转Point(point);
            var pointT = Get俯视角旋转Point(pointR, z + offset.Z);
            //var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y));
            return pointT;
        }
        private PointF WorldPointToMapPoint(PointF3D point, PointF3D offset = null)
        {
            return WorldPointToMapPoint(new PointF(point.X, point.Y), point.Z, offset);
        }
        private PointF WorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null)
        {
            PointF p;
            if (junction == null) return new PointF(0, 0);
            p = WorldPointToMapPoint(junction.Position, junction.Elev, offset);
            return p;
        }
        private List<PointF> WorldPointToMapPoint(LinkViewModel pipe, PointF3D offset = null)
        {
            List<PointF> list = new List<PointF>();
            PointF p;
            p = WorldPointToMapPoint(pipe.StartNode, offset);
            list.Add(p);
            p = WorldPointToMapPoint(pipe.EndNode, offset);
            list.Add(p);
            return list;
        }
        /// <summary>
        /// 获取正交投影坐标,返回的是世界坐标
        /// </summary>
        /// <param name="position3D">世界坐标</param>
        /// <param name="mousePosition">地图坐标</param>
        /// <param name="vector3">投影向量</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private PointF3D GetZZWorldPoint(PointF3D position3D, PointF mousePosition, Vector3 vector3)
        {
            //做一条通过position3D的平行于vector3的直线,
            if (vector3==new Vector3(0,0,1))
            {
                return GetLGWorldPoint(position3D, mousePosition);
            }
            else
            {
                return new PointF3D(0, 0, 0);
            }
        }
        /// <summary>
        /// 获取正交投影坐标,返回的是世界坐标
        /// </summary>
        /// <param name="position3D">世界坐标</param>
        /// <param name="mousePosition">地图坐标</param>
        /// <param name="vector3">投影向量</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private PointF3D GetLGWorldPoint(PointF3D position3D, PointF p2)
        {
            double radian_fushi = 俯视弧度;
            float sin = (float)Math.Sin(radian_fushi);
            float cos = (float)Math.Cos(radian_fushi);
            var p1 = WorldPointToMapPoint(position3D);
            var dy=p2.Y - p1.Y;
            float dz= dy/cos;
            return new PointF3D(position3D.X, position3D.Y, position3D.Z+ dz);
        }
        private PointF MapPointToWorldPoint(PointF3D point)
        {
            return MapPointToWorldPoint(new PointF(point.X, point.Y), point.Z);
        }
        /// <summary>
        /// 获取地图投影坐标
        /// </summary>
        /// <param name="point"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        private PointF MapPointToWorldPoint(PointF point, float z = 0)
        {
            var pointT = Get俯视角还原Point(point, z);
            pointT = Get平面还原Point(pointT);
            //var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y));
            return pointT;
        }
        private PointF GetMapPoint_还原(NodeViewModel junction)
        {
            PointF p;
            p = MapPointToWorldPoint(junction.Position, junction.Elev);
            return p;
        }
        #endregion
        #region 判断可见性
        private float Get_dist(PointF A, PointF B)
        {
            float dx = A.X - B.X;
            float dy = A.Y - B.Y;
            float dist = (float)Math.Sqrt(dx * dx + dy * dy);
            return dist;
        }
        //判断A距离线段B和C的距离,如果超出了线段的范围,则返回到最近的端点的距离;距离线段中心点越远,返回的距离越大;
        private float Get_dist(PointF A, PointF B, PointF C, float MaxOff)
        {
            //PointF A, PointF B,PointF C,求点A到B、C构成线段的中心点的距离
            float dist_off = GetDistanceFromPointAToMidpointOfLineSegmentBC(A, B, C);
            //使用dist_off 跟 线段A、B的长度比较,如果大于1/2,则返回MaxOff,否则按照比例返回
            float dist_len = Get_dist(B, C);
            if (dist_len < 5) dist_len = 5;
            float dist_add = (dist_off / dist_len > 0.5 ? MaxOff : dist_off / dist_len * 2 * MaxOff);
            float dx = C.X - B.X;
            float dy = C.Y - B.Y;
            float dist = (float)Math.Sqrt(dx * dx + dy * dy);
            if (dist == 0) return Get_dist(A, B) + dist_add;
            float t = ((A.X - B.X) * dx + (A.Y - B.Y) * dy) / (dist * dist);
            if (t < 0) return Get_dist(A, B) + dist_add;
            if (t > 1) return Get_dist(A, C) + dist_add;
            float x = B.X + t * dx;
            float y = B.Y + t * dy;
            return Get_dist(A, new PointF(x, y)) + dist_add;
        }
        private float GetDistanceFromPointAToMidpointOfLineSegmentBC(PointF A, PointF B, PointF C)
        {
            // Calculate the midpoint of the line segment BC
            PointF midpoint = new PointF((B.X + C.X) / 2, (B.Y + C.Y) / 2);
            // Calculate the distance from point A to the midpoint
            float dx = midpoint.X - A.X;
            float dy = midpoint.Y - A.Y;
            float distance = (float)Math.Sqrt(dx * dx + dy * dy);
            return distance;
        }
        PointF PMin_Show, PMax_Show;
        /// <summary>
        /// 判断是否在屏幕坐标内
        /// </summary>
        /// <param name="screenPos"></param>
        /// <returns></returns>
        public bool isVisible(PointF MapPos)
        {
            if (MapPos.X < PMin_Show.X || MapPos.X > PMax_Show.X || MapPos.Y < PMin_Show.Y || MapPos.Y > PMax_Show.Y)
                return false;
            else
                return true;
        }
        /// <summary>
        /// 判断是否在屏幕坐标内
        /// </summary>
        /// <param name="screenPos"></param>
        /// <returns></returns>
        public bool isVisible(List<PointF> list_MapPos)
        {
            bool visible = false;
            foreach (var MapPos in list_MapPos)
            {
                if (MapPos.X < PMin_Show.X || MapPos.X > PMax_Show.X || MapPos.Y < PMin_Show.Y || MapPos.Y > PMax_Show.Y)
                {
                }
                else
                {
                    visible = true;
                    return true;
                }
            }
            return visible;
        }
        #endregion
@@ -679,144 +450,7 @@
                __needpaintall = value;
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (float.IsInfinity(zoom)) return;
            label_center.Text = $"center:({MapCenter.X.ToString("0.00")} ,{MapCenter.Y.ToString("0.00")})";
            label_zoom.Text = $"Zoom:{zoom.ToString("0.000")}";
            toolStripStatusLabel_rotation.Text = $"Rotation:({Rotation.ToString("0")},{RotationF.ToString("0")})";
            //if (!_needPaintAll)
            //    return;
            int heightOfBar = showToolBar ? 24 : 0;
            if (!showToolBar) heightOfBar = 0;
            if (e.ClipRectangle != new Rectangle(this.Left, heightOfBar, this.Width, this.Height - heightOfBar - statusStrip1.Height)) return;
            _needPaintAll = false;
            if (buffer == null || buffer.Width != Width || buffer.Height != Height)
            {
                buffer?.Dispose();
                buffer = new Bitmap(Width, Height);
            }
            // 使用缓存绘制,避免在每次重绘时重新计算所有要绘制的元素
            //if (bufferG == null) bufferG = Graphics.FromImage(buffer);
            using (var bufferG = Graphics.FromImage(buffer))
            //using (var bufferG = e.Graphics)
            {
                // 先将控件的背景填充为白色
                bufferG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                bufferG.Clear(Color.Transparent);
                bufferG.TranslateTransform(Width / 2, Height / 2);
                bufferG.ScaleTransform(Zoom.X, Zoom.Y);
                bufferG.TranslateTransform(-MapCenter.X, -MapCenter.Y);
                //if (_NodeColour==null)
                //{
                //    cb_Node_Colour_SelectedIndexChanged(1, new EventArgs());
                //}
                //if (_LinkColour==null)
                //{
                //    cb_Link_Colour_SelectedIndexChanged(1, new EventArgs());
                //}
                //BookMark    :绘制地图事件
                Draw(bufferG, _Template);
                if (_newTemplate?.network != null) Draw(bufferG, _newTemplate);
                var r = 2f / zoom;
                if (_isDragging && DragStartPos != new PointF(0, 0) && mousePosition != new PointF(0, 0))
                {
                    label_center.Text = $"S:{DragStartPos.X}:{DragStartPos.Y} E:{mousePosition.X}:{mousePosition.Y}";
                    var _lastMousePosition = DragStartPos;
                    // 绘制矩形
                    var start = new PointF((float)Math.Min(mousePosition.X, _lastMousePosition.X), (float)Math.Min(mousePosition.Y, _lastMousePosition.Y));
                    var size = new SizeF((float)Math.Abs(_lastMousePosition.X - mousePosition.X), (float)Math.Abs(_lastMousePosition.Y - mousePosition.Y));
                    if (size.Width == 0) size.Width = 0.01f;
                    if (size.Height == 0) size.Height = 0.01f;
                    var rectangle0 = new RectangleF(start, size);
                    using (var pen = new Pen(Color.Black, 0.5f * r))
                    {
                        bufferG.DrawRectangles(pen, new RectangleF[] { rectangle0 });
                    }
                }
                if (_isPainting)
                {
                    if (_mouseState == MouseState.新增立管)
                    {
                        var wPos=GetZZWorldPoint(_select_junction1.Position3D, _MousePosition,new Vector3(0,0,1));
                        using (var pen = new Pen(Color.Black, 1 * r))
                        {
                            pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                            bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), WorldPointToMapPoint(wPos));
                        }
                    }
                    else
                    {
                        using (var pen = new Pen(Color.Black, 1 * r))
                        {
                            pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                            bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), _MousePosition);
                        }
                    }
                }
                if (_isDrawingPolygon && polygonPoints.Count > 0)
                {
                    List<PointF> pf = polygonPoints.ToList();
                    pf.Add(new PointF(mousePosition.X, mousePosition.Y));
                    using (var pen = new Pen(Color.Black, 1 * r))
                    {
                        // 绘制多边形虚线边框
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                        bufferG.DrawLines(pen, pf.ToArray());
                    }
                }
                if (_isSettingBackGroundPictur)
                {
                    var _lastMousePosition = DragStartPos;
                    // 绘制矩形
                    var start = new PointF((float)Math.Min(mousePosition.X, _lastMousePosition.X), (float)Math.Min(mousePosition.Y, _lastMousePosition.Y));
                    var size = new SizeF((float)Math.Abs(_lastMousePosition.X - mousePosition.X), (float)Math.Abs(_lastMousePosition.Y - mousePosition.Y));
                    var rectangle0 = new RectangleF(start, size);
                    using (var pen = new Pen(Color.Black, 1 * r))
                    {
                        bufferG.DrawRectangles(pen, new RectangleF[] { rectangle0 });
                    }
                }
                if (_isMovingObject)
                {
                    var newP = _MousePosition;
                    //var p = MapPointToWorldPoint(, _OperaNode.Elev);
                    var oldP3D = (PointF3D)_undoOldValue;
                    var oldP = WorldPointToMapPoint(new PointF(oldP3D.X, oldP3D.Y), oldP3D.Z);
                    List<PointF> pf = new List<PointF> { oldP, newP };
                    using (var pen = new Pen(Color.Black, 1 * r))
                    {
                        // 绘制多边形虚线边框
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                        bufferG.DrawLines(pen, pf.ToArray());
                    }
                }
            }
            // 将生成的画布绘制到控件上
            e.Graphics.DrawImage(buffer, 0, 0);
        }
        PointF[] getCurclePoints(int num)
        {
@@ -833,744 +467,43 @@
            return points;
        }
        void Draw(Graphics bufferG, Template template)
        {
            if (template == null) return;
            var _Nodes = template.network.Nodes.ViewNodes;
            var _Links = template.network.Links.ViewLinks;
            var Cpoints = getCurclePoints(64).ToList();
            var r = 1.73f / zoom;
            var rt = r;
            float minElve = float.MinValue;
            float maxElve = float.MaxValue;
            //if (this.mapOption!=null && this.mapOption.ShowFloor!=int.MinValue )
            //{
            //    var fl = template.Floors.Find(f => f.FloorIndex == this.mapOption.ShowFloor);
            //    var fl_1 = template.Floors.Find(f => f.FloorIndex == this.mapOption.ShowFloor+1);
            //    if (fl!=null)
            //    {st
            //        minElve = fl.Elev;
            //        maxElve = fl_1!=null ? fl_1.Elev : float.MaxValue;
            //    }
            //}
            r = r * Link_multiply;
            List<PointF> diametersZoom = new List<PointF>() { new PointF(0, 0.08f), new PointF(150, 0.03f), new PointF(300, 0.001f), new PointF(800, 0.0001f) };
            Pen penN = new Pen(Color.FromArgb(0, 0, 255), 1 * r);
            Pen penChoosed = new Pen(Color.Purple, 5 * r);
            Pen pen_valveChoosed = new Pen(Color.Red, 5 * r);
            Pen penClosed = new Pen(Color.OrangeRed, 2 * r);
            Pen penHovered =new Pen(Color.DeepSkyBlue, 5 * r);
            //背景图绘制
            if (this.mapOption.isShowPic && template != null && File.Exists(template.BackGroundImg_FullPath))
            {
                //var gs = bufferG.Save();
                // 应用矩阵变换以抵消之前的翻转效果
                //bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
                // 恢复之前保存的绘图状态
                var Cps = new List<PointF>
                {
                    template.BackGroundPoint1,
                    new PointF(template.BackGroundPoint2.X,template.BackGroundPoint1.Y),
                    new PointF(template.BackGroundPoint1.X,template.BackGroundPoint2.Y),
                    //template.BackGroundPoint2,
                };
                List<PointF> p = new List<PointF>();
                Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet)));
                //bufferG.DrawImage(System.Drawing.Image.FromFile(@"C:\Users\cloud\Pictures\GenshinImpactCloudGame\QQ截图20230919105637.png"), p[0]);
                try
                {
                    var img = System.Drawing.Image.FromFile(template.BackGroundImg_FullPath);
                    if (img != null)
                    {
                        bufferG.FillPolygon(penN.Brush, p.ToArray());
                        bufferG.DrawImage(img, p.ToArray());
                    }
                }
                catch
                {
                }
                //bufferG.Restore(gs);
            }
            // 绘制线
            HashSet<long> dict_flow_direction = new HashSet<long>();
            using (Pen pen0 = new Pen(Color.FromArgb(0, 0, 255), 2 * r))
            {
                foreach (var link in _Links)
                {
                    if (!link.Visible) continue;
                    if (link.Elev < minElve || link.Elev >= maxElve) continue;
                    //if (_isMovingObject && (link.StartNode == _OperaNode || link.EndNode == _OperaNode)) continue;
                    var p1 = WorldPointToMapPoint(link.StartNode, template.OffSet);
                    var p2 = WorldPointToMapPoint(link.EndNode, template.OffSet);
                    if (!isVisible(p1) && !isVisible(p2)) continue;
                    if (_LinkColour != null)
                    {
                        pen0.Color = penClosed.Color = getLinkColor(_LinkColour, link);
                    }
                    Pen pen = pen0;
#if DEBUG
#else
                    if (_Template != null && _Template.mapOption._ShowStatus && link.Status == Hydro.Core.ObjectEnum.StatusType.CLOSED) pen = penClosed;
#endif
                    if (link.Hovered) pen = penHovered;
                    float zoomAtMin = 0;
                    for (int i = 0; i < diametersZoom.Count; i++)
                    {
                        PointF point = diametersZoom[i];
                        if (link.Diameter >= point.X) continue;
                        zoomAtMin = diametersZoom[i - 1].Y;
                        break;
                    }
                    if (zoomAtMin >= zoom) continue;
                    if (link is ValveViewModel)
                    {
                        if (link.Selected || _ShowValve)
                        {
                            var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
                            bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
                            var valveShapeHeight = link.Selected ? 10 : 5;
                            PointF[] points = new PointF[] {
                                getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
                                getRotatePoint(c.X - valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2),
                                getRotatePoint(c.X + valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
                                getRotatePoint(c.X + valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2),
                                getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
                            };
                            bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
                        }
                    }
                    else if (link is PumpViewModel)
                    {
                        if (link.Selected || _ShowValve)
                        {
                            var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
                            //bufferG.DrawLine(link.Selected ? pen_valveChoosed : pen, p1, p2);
                            bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
                            // 绘制圆形部分(水泵的泵体)
                            float radius = 5 * r;
                            float diameter = radius * 2;
                            #region 圆形拆分
                            //var p = new PointF[]
                            //{
                            //    getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2),
                            //    getRotatePoint(c.X + radius - radius, c.Y - radius, c, p1, p2),
                            //    getRotatePoint(c.X + radius - radius, c.Y + radius, c, p1, p2),
                            //    getRotatePoint(c.X - radius - radius, c.Y + radius, c, p1, p2),
                            //    getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2),
                            //};
                            List<PointF> p = new List<PointF>();
                            Cpoints.ForEach(cp => p.Add(getRotatePoint(c.X + cp.X * radius - radius, c.Y + cp.Y * radius, c, p1, p2)));
                            #endregion
                            //RectangleF circleRect = new RectangleF(p[0].X, p[0].Y,p[1].X-p[0].X>0? diameter:-diameter,p[1].Y-p[0].Y>0? diameter:-diameter);
                            //bufferG.FillEllipse(link.Selected ? pen_valveChoosed.Brush : pen.Brush, circleRect);
                            bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray());
                            //// 绘制矩形部分(水泵的出口)
                            //float rectangleWidth = 6*r;
                            //float rectangleHeight = 2*r;
                            //PointF rectTopLeft = new PointF(c.X - rectangleWidth / 2, c.Y + radius);
                            //SizeF rectSize = new SizeF(rectangleWidth, rectangleHeight);
                            //RectangleF rectangleRect = new RectangleF(rectTopLeft, rectSize);
                            //bufferG.DrawRectangles(link.Selected ? pen_valveChoosed : pen,new RectangleF[] { rectangleRect });
                            // 绘制连接线
                            var valveShapeHeight = link.Selected ? radius * 2 : radius;
                            PointF[] points = new PointF[] {
                                getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
                                getRotatePoint(c.X - valveShapeHeight , c.Y ,c,p1,p2),
                                getRotatePoint(c.X + valveShapeHeight , c.Y ,c,p1,p2),
                                getRotatePoint(c.X + valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
                                getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
                            };
                            bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
                        }
                    }
                    else if (link is RepeaterViewModel re)
                    {
                        if (re.Status == RepeaterViewModel.RepeatStatus.收起 || _IsEditMode)
                        {
                            bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
                            var listNode = Get等分Nodes(p1, p2, Math.Max(re.RepeatTimes, 1));
                            for (int i = 0; i < listNode.Count; i++)
                            {
                                //foreach (var c in listNode)
                                //{
                                var c = listNode[i];
                                RectangleF[] rects = new RectangleF[] {
                                    new RectangleF(c.X-10*r,c.Y-8*r,20*r,16*r),
                                };
                                bufferG.FillRectangles(new SolidBrush(Color.White), rects);
                                //bufferG.FillRectangles(link.Selected ? penChoosed.Brush : pen.Brush, new RectangleF[]
                                //{
                                //    new RectangleF(c.X-5*r,c.Y-5*r,3*r,3*r),
                                //    new RectangleF(c.X-5*r,c.Y+2*r,3*r,3*r),
                                //    new RectangleF(c.X+2*r,c.Y+2*r,3*r,3*r),
                                //    new RectangleF(c.X+2*r,c.Y-5*r,3*r,3*r),
                                //});
                                // 保存当前绘图状态
                                var gs = bufferG.Save();
                                // 应用矩阵变换以抵消之前的翻转效果
                                bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
                                int index = re.GetIndex(i);
                                string indexString = index == 0 ? "" : index.ToString();
                                Font font = new Font(FontFamily.GenericSansSerif, 10);
                                string text = $"{indexString}{re.NetworkShowName}";
                                SizeF textSize = bufferG.MeasureString(text, font);
                                var center = new PointF(c.X * Zoom.X, c.Y * Zoom.Y);
                                float textLeft = center.X - textSize.Width / 2;
                                float textTop = center.Y - textSize.Height / 2;
                                PointF p = new PointF(textLeft, textTop);
                                bufferG.DrawString(text, font, link.Selected ? penChoosed.Brush : pen.Brush, p);
                                // 恢复之前保存的绘图状态
                                bufferG.Restore(gs);
                                if (textSize.Width / Zoom.X > rects[0].Width)
                                {
                                    rects[0] = new RectangleF(c.X - textSize.Width / 2 / Zoom.X - 1 * r, c.Y - 8 * r, textSize.Width / Zoom.X + 2 * r, 16 * r);
                                }
                                try
                                {
                                    bufferG.DrawRectangles(penN, rects);
                                }
                                catch { }
                            }
                            //var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
                        }
                        //else
                        //{
                        //    DrawRepeater(bufferG,re);
                        //}
                    }
                    else
                    {
                        if (link.StartNode == null || link.EndNode == null) continue;
                        bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
                        if (_Template.mapOption._ShowFlowDirection)
                        {
                            var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
                            var ps = MapToScreen(c);
                            //将ps转换为ulong,精度为20,并加入到dict_flow_direction中
                            var ps_20 = GetUlongByPoint(ps, 5);
                            if (!dict_flow_direction.Contains(ps_20))
                            {
                                dict_flow_direction.Add(ps_20);
                                bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
                                // 绘制圆形部分(水泵的泵体)
                                float radius = 5 * r;
                                float diameter = radius * 2;
                                #region 圆形拆分
                                float activeD = 1;
                                if (link.EN_FLOW < 0) activeD = -1;
                                List<PointF> p = new List<PointF>();
                                Cpoints.ForEach(cp => p.Add(getRotatePoint(c.X - activeD * cp.X * radius + activeD * radius, c.Y + cp.Y * radius, c, p1, p2)));
                                #endregion
                                bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray());
                                var valveShapeHeight = link.Selected ? radius * 2 : radius;
                                PointF[] points = new PointF[] {
                                    getRotatePoint(c.X -activeD* valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
                                    getRotatePoint(c.X  , c.Y ,c,p1,p2),
                                    getRotatePoint(c.X - activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2),
                                    getRotatePoint(c.X + activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2),
                                    getRotatePoint(c.X + activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
                                    getRotatePoint(c.X - activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
                                };
                                bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
                            }
                        }
                    }
                }
            }
            r = rt;
            HashSet<long> dict_point = new HashSet<long>();
            //绘制点
            penChoosed = new Pen(Color.Green, 1f * r);
            Brush brushChoosed = penChoosed.Brush;
            SolidBrush whiteBrush = new SolidBrush(Color.White);
            using (Pen pen0 = new Pen(Color.FromArgb(255, 0, 0), 1 * r))
            {
                foreach (NodeViewModel node in _Nodes)
                {
                    if (!node.Visible) continue;
                    if (node.Elev < minElve || node.Elev >= maxElve) continue;
                    Pen pen = pen0;
                    Brush brush = pen.Brush;
                    float pr = (float)(r * 0.5);
                    pr = pr * junction_multiply;
                    PointF p = WorldPointToMapPoint(node, template.OffSet);
                    if (!isVisible(p)) continue;
                    var ps_20 = GetUlongByPoint(p, 0.1f);
                    if (dict_point.Contains(ps_20))
                        continue;
                    dict_point.Add(ps_20);
                    //var x = junction.Position.X * zoom + PanningOffset.X - radius / 2.0f;
                    //var y = junction.Position.Y * zoom + PanningOffset.Y - radius / 2.0f;
                    if (_NodeColour != null)
                    {
                        pen.Color = penChoosed.Color = getNodeColor(_NodeColour, node);
                        brush = pen.Brush;
                        brushChoosed = penChoosed.Brush;
                    }
                    if (node.Hovered)
                    {
                        pen= penHovered;
                        brush = pen.Brush;
                    }
                    var rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr);
                    float zoomAtMin = 0;
                    for (int i = 0; i < diametersZoom.Count; i++)
                    {
                        PointF point = diametersZoom[i];
                        if (node.MaxDiameter >= point.X) continue;
                        zoomAtMin = diametersZoom[i - 1].Y;
                        break;
                    }
                    if (zoomAtMin >= zoom) continue;
                    //if(node.ID == _StartPoint)
                    //{
                    //    var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                    //    bufferG.FillEllipse(whiteBrush, whiteRect);
                    //    whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr);
                    //    bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
                    //    whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                    //    bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
                    //}
                    //else
                    if ( node == _OperaNode)
                    {
                        var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                        bufferG.FillEllipse(whiteBrush, whiteRect);
                        whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr);
                        bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
                        whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                        bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
                    }
                    else if (node.ID == _EndPoint)
                    {
                        var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                        bufferG.FillEllipse(whiteBrush, whiteRect);
                        whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                        bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
                        //whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr);
                        //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, whiteRect);
                        var p1 = new PointF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr);
                        var p2 = new PointF(p1.X + 6 * pr, p1.Y + 6 * pr);
                        bufferG.DrawLine(node.Selected ? penChoosed : pen, p1, p2);
                        p1 = new PointF(rectangle.X + 2 * pr, rectangle.Y + 8 * pr);
                        p2 = new PointF(p1.X + 6 * pr, p1.Y - 6 * pr);
                        bufferG.DrawLine(node.Selected ? penChoosed : pen, p1, p2);
                        //bufferG.FillEllipse(junction.Choosed ? brushChoosed : brush, rectangle);
                        //var whiteRect = new RectangleF(rectangle.X + 1 * pr, rectangle.Y + 1 * pr, rectangle.Width - 2 * pr, rectangle.Height - 2 * pr);
                        //bufferG.FillEllipse(whiteBrush, whiteRect);
                        //whiteRect = new RectangleF(rectangle.X - 2 * pr, rectangle.Y - 2 * pr, rectangle.Width + 4 * pr, rectangle.Height + 4 * pr);
                        //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, whiteRect);
                    }
                    else if (node is TankViewModel)
                    {
                        pr *= 2;
                        rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr);
                        RectangleF r0 = new RectangleF(rectangle.X, rectangle.Y + 5 * pr, 10 * pr, 5 * pr);
                        RectangleF r1 = new RectangleF(rectangle.X + 2 * pr, rectangle.Y, 6 * pr, 5 * pr);
                        bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r0);
                        bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r1);
                    }
                    else if (node is ReservoirViewModel)
                    {
                        pr *= 2;
                        rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr);
                        RectangleF r0 = new RectangleF(rectangle.X, rectangle.Y + 2 * pr, rectangle.Width, 6 * pr);
                        RectangleF r1 = new RectangleF(rectangle.X, rectangle.Y + 8 * pr, 1 * pr, 2 * pr);
                        RectangleF r2 = new RectangleF(rectangle.X + 9 * pr, rectangle.Y + 8 * pr, 1 * pr, 2 * pr);
                        bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r0);
                        bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r1);
                        bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r2);
                    }
                    else if (node is MeterViewModel)
                    {
                        //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, rectangle);
                        bufferG.FillEllipse(node.Selected ? brushChoosed : brush, rectangle);
                        var whiteRect = new RectangleF(rectangle.X + 1 * pr, rectangle.Y + 1 * pr, rectangle.Width - 2 * pr, rectangle.Height - 2 * pr);
                        bufferG.FillEllipse(whiteBrush, whiteRect);
                        var p1 = new PointF(rectangle.X + 5 * pr, rectangle.Y);
                        var p2 = new PointF(rectangle.X + 5 * pr, rectangle.Y + 10 * pr);
                        bufferG.DrawLine(node.Selected ? penChoosed : pen, p1, p2);
                    }
                    else
                    {
                        rectangle = new RectangleF((float)p.X - 3 * pr, (float)p.Y - 3 * pr, 6 * pr, 6 * pr);
                        if (node.Selected || _ShowJunction)
                            bufferG.FillEllipse(node.Selected ? brushChoosed : brush, rectangle);
                    }
                }
            }
            using (Pen pen = new Pen(Color.FromArgb(255, 0, 0), 1 * r))
            {
                Brush brush = pen.Brush;
                //获取_Nodes中自由水压最小的节点
                var node = _Nodes.Where(n => n is JunctionViewModel || n is MeterViewModel && n.EN_PRESSURE != float.NaN).OrderBy(n => n.EN_PRESSURE).FirstOrDefault();
                //判断node.EN_PRESSURE不是float.NaN
                if (node != null && !float.IsNaN( node.EN_PRESSURE))
                {
                    //if (node.Elev < minElve || node.Elev >= maxElve) continue;
                    float pr = (float)(r * 0.5);
                    pr = pr * junction_multiply;
                    PointF p = WorldPointToMapPoint(node, template.OffSet);
                    var ps_20 = GetUlongByPoint(p, 0.1f);
                    dict_point.Add(ps_20);
                    //var x = junction.Position.X * zoom + PanningOffset.X - radius / 2.0f;
                    //var y = junction.Position.Y * zoom + PanningOffset.Y - radius / 2.0f;
                    if (_NodeColour != null)
                    {
                        pen.Color = getNodeColor(_NodeColour, node);
                        brush = pen.Brush;
                        brushChoosed = penChoosed.Brush;
                    }
                    var rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr);
                    float zoomAtMin = 0;
                    for (int i = 0; i < diametersZoom.Count; i++)
                    {
                        PointF point = diametersZoom[i];
                        if (node.MaxDiameter >= point.X) continue;
                        zoomAtMin = diametersZoom[i - 1].Y;
                        break;
                    }
                    //var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                    //bufferG.FillEllipse(whiteBrush, whiteRect);
                    //whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr);
                    //bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
                    //whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                    //bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
                    var p1 = new PointF((float)p.X - 4 * pr, (float)p.Y - 2 * pr);
                    var p2 = new PointF((float)p.X + 4 * pr, (float)p.Y - 2 * pr);
                    var p3 = new PointF((float)p.X, (float)p.Y - 4 * pr);
                    bufferG.DrawPolygon(node.Selected ? penChoosed : pen, new PointF[] { p1, p2, p3 });
                    var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                    bufferG.FillEllipse(whiteBrush, whiteRect);
                    whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
                    bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect);
                }
            }
            //r = r * Link_multiply;
            //using (Pen pen = new Pen(Color.FromArgb(0, 0, 255), 2 * r))
            //{
            //    foreach (var link in _Links)
            //    {
            //        if (!link.Visible) continue;
            //        if (!isVisible(WorldPointToMapPoint(link))) continue;
            //        float zoomAtMin = 0;
            //        for (int i = 0; i < diametersZoom.Count; i++)
            //        {
            //            PointF point = diametersZoom[i];
            //            if (link.Diameter >= point.X) continue;
            //            zoomAtMin = diametersZoom[i - 1].Y;
            //            break;
            //        }
            //        if (zoomAtMin >= zoom) continue;
            //        if (link is Valve)
            //        {
            //            if (link.Selected)
            //            {
            //                var p1 = WorldPointToMapPoint(link.StartNode);
            //                var p2 = WorldPointToMapPoint(link.EndNode);
            //                var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
            //                bufferG.DrawLines(link.Selected ? valveChoosed : pen, new PointF[] { p1, p2 });
            //                bufferG.DrawLines(link.Selected ? valveChoosed : pen, new PointF[] {
            //                    getRotatePoint(c.X - 3 * r, c.Y + 3 * r,c,p1,p2),
            //                    getRotatePoint(c.X - 3 * r, c.Y - 2 * r,c,p1,p2),
            //                    getRotatePoint(c.X + 3 * r, c.Y + 2 * r,c,p1,p2),
            //                    getRotatePoint(c.X + 3 * r, c.Y - 2 * r,c,p1,p2),
            //                    getRotatePoint(c.X - 3 * r, c.Y + 2 * r,c,p1,p2),
            //                });
            //            }
            //        }
            //    }
            //}
        }
        Color getNodeColor(Colour colour, NodeViewModel node)
        {
            double value = 0;
            Color color = Color.Gray;
            switch (colour.Type)
            {
                case ColourType.节点自由压力:
                    value = node.EN_PRESSURE;
                    break;
                case ColourType.节点绝对压力:
                    value = node.EN_HEAD;
                    break;
                case ColourType.节点需水量:
                    value = node.EN_DEMAND;
                    break;
            }
            for (int i = 0; i < colour.Items.Count; i++)
            {
                if (colour.Items[i].DRange.IsInside(value))
                {
                    color = colour.Items[i].value;
                    break;
                }
            }
            return color;
        }
        Color getLinkColor(Colour colour, LinkViewModel link)
        {
            double value = 0;
            Color color = Color.Gray;
            switch (colour.Type)
            {
                case ColourType.管线流量:
                    value = link.EN_FLOW;
                    break;
                case ColourType.管线流速:
                    value = link.EN_VELOCITY;
                    break;
            }
            for (int i = 0; i < colour.Items.Count; i++)
            {
                if (colour.Items[i].DRange.IsInside(value))
                {
                    color = colour.Items[i].value;
                    break;
                }
            }
            return color;
        }
        private static long GetUlongByPoint(PointF ps, float delta = 20, int MaxY = 2000)
        {
            return (long)((int)(ps.X / delta) + ((int)Math.Round(ps.Y / delta)) * MaxY / delta);
        }
        public List<PointF> Get等分Nodes(PointF p1, PointF p2, int n)
        {
            // 计算线段长度
            float len = (float)Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
            if (len == 0) len = 0.00001f;
            // 计算单位向量
            PointF u = new PointF((p2.X - p1.X) / len, (p2.Y - p1.Y) / len);
            // 计算间距
            float d = len / (n + 1);
            // 计算n等分点
            List<PointF> nodes = new List<PointF>();
            for (int i = 1; i < n + 1; i++)
            {
                PointF node = new PointF(p1.X + i * d * u.X, p1.Y + i * d * u.Y);
                if (node.X == float.NaN || node.Y == float.NaN) node = p1;
                nodes.Add(node);
            }
            //nodes.RemoveAt(0);
            //nodes.RemoveAt(nodes.Count - 1);
            //// 绘制线段
            //graphics.DrawLine(Pens.Black, p1, p2);
            //// 绘制3等分点和n等分点
            //foreach (PointF node in node3)
            //{
            //    graphics.FillEllipse(Brushes.Red, node.X - 2, node.Y - 2, 4, 4);
            //}
            //foreach (PointF node in nodes)
            //{
            //    graphics.FillEllipse(Brushes.Blue, node.X - 2, node.Y - 2, 4, 4);
            //}
            return nodes;
        }
        private PointF getRotatePoint(float px, float py, PointF center, PointF x, PointF y)
        {
            PointF p = new PointF(px, py);
            return getRotatePoint(p, center, x, y);
        }
        private PointF[] getRotatePoints(PointF[] ps, PointF center, PointF x, PointF y)
        {
            return ps.ToList().Select(p => getRotatePoint(p, center, x, y)).ToArray();
        }
        private PointF getRotatePoint(PointF p, PointF center, PointF x, PointF y)
        {
            float angle = (float)Math.Atan2(y.Y - x.Y, y.X - x.X);
            float distance = (float)Math.Sqrt(Math.Pow(p.X - center.X, 2) + Math.Pow(p.Y - center.Y, 2));
            float rotationAngle = (float)(Math.Atan2(p.Y - center.Y, p.X - center.X) + angle);
            float rotatedX = center.X + distance * (float)Math.Cos(rotationAngle);
            float rotatedY = center.Y + distance * (float)Math.Sin(rotationAngle);
            return new PointF(rotatedX, rotatedY);
        }
        public new void Invalidate()
        {
            _needPaintAll = true;
            PMin_Show = ScreenToMap(new PointF(0, Height));
            PMax_Show = ScreenToMap(new PointF(Width, 0));
            _timerDraw = true;
        }
        bool _timerDraw = false;
        private void timer_draw_Tick(object sender, EventArgs e)
        {
            if (_timerDraw)
                base.Invalidate();
            _timerDraw = false;
            _mouseHoverCheckFlag = true;
            if (_timerDraw && map.Status==DrawingStatus.Ready)
            {
                this.map.Invalidate();
                this.CubeView.Invalidate();
                _timerDraw = false;
            }
        }
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            // 当控件尺寸改变时,触发重绘
            this.Invalidate();
            this.SetMapInvalidate();
        }
#endregion
        #endregion
        #region 鼠标事件
        public PointF mouseXY = new PointF(0, 0);
        PointF DragStartPos;
        PointF _ClickStartPos;
        PointF RotaStartPos;
        PointF BackGroudPicLeftPos;
        bool _isPanning;
        /// <summary>
        /// 拖拽选择
        /// </summary>
        bool _isDragging;
        bool _isRotating;
        bool _isPainting;
        public List<IBaseViewModel> selectedObjs = new List<IBaseViewModel>();
        private List<NodeViewModel> selectedNodes => selectedObjs.FindAll(o => o is NodeViewModel).Select(o => (NodeViewModel)o).ToList();
        private List<LinkViewModel> selectedLinks => selectedObjs.FindAll(o => o is LinkViewModel).Select(o => (LinkViewModel)o).ToList();
        private NodeViewModel _OperaNode = null;
        PointF mousePosition;
        // control+鼠标中间按下缩放
        bool _isInsertingObject = false;
        bool _isMovingObject = false;
        bool _isPastingObject = false;
        Cursor _lastCursor;
        object _undoOldValue = null;
        private List<PointF> polygonPoints = new List<PointF>();
        public bool Lock2DView = false;
        private bool _isDrawingPolygon;
        protected override void OnMouseDown(MouseEventArgs e)
        void mapMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            _ClickStartPos = new PointF(e.X, e.Y);
            DragStartPos = ScreenToMap(new PointF(e.X, e.Y));
            DragStartPos= ScreenToMap(new PointF(e.X, e.Y));
            mousePosition = _MousePosition = ScreenToMap(new PointF(e.X, e.Y));
            if (e.Button == MouseButtons.Left && _isInsertingObject)
            {
@@ -1613,7 +546,7 @@
                    polygonPoints.Add(point);
                    mousePosition = _MousePosition = ScreenToMap(new PointF(e.X, e.Y));
                    Invalidate();
                    SetMapInvalidate();
                    return;
                }
                if (_isDrawingPolygon)
@@ -1622,7 +555,7 @@
                }
                //移动
                if (selectedObjs.Count >= 1) //&& selectedObjs[0].isNode())
                if (_IsEditMode && selectedObjs.Count >= 1) //&& selectedObjs[0].isNode())
                {
                    List<NodeViewModel> nodes = selectedNodes;
                    foreach (NodeViewModel node in nodes)
@@ -1706,7 +639,7 @@
        bool controlDown = false;
        PointF _MousePosition = new PointF(0, 0);
        protected override void OnMouseMove(MouseEventArgs e)
        void mapMouseMove(MouseEventArgs e)
        {
            //base.OnMouseMove(e);
            bool needInvalidate = false;
@@ -1751,14 +684,14 @@
                //    Math.Abs((int)DragStartPos.Y - (int)MP.Y));
                //DrawSelectionRect(selectionRect);
                needInvalidate = true;
            }
            else if (_isRotating)
            {
                mousePosition = _MousePosition;
                bool is下半屏幕 = RotaStartPos.Y >= this.Height / 2;
                if (ModifierKeys != Keys.Alt) Rotation = Rotation0 + ((float)e.X - (float)RotaStartPos.X) * 180 * 2.5 / (float)this.Width * (is下半屏幕 ? 1 : 1);
                if (ModifierKeys != Keys.Shift) RotationF = 俯视角度_start + ((float)e.Y - (float)RotaStartPos.Y) * 180 * 2.5 / (float)this.Height;
                bool is下半屏幕 = RotaStartPos.Y >= this.map.Height / 2;
                if (ModifierKeys != Keys.Alt) Rotation = Rotation0 + ((float)e.X - (float)RotaStartPos.X) * 180 * 2.5 / (float)this.map.Width * (is下半屏幕 ? 1 : 1);
                if (ModifierKeys != Keys.Shift) RotationF = 俯视角度_start + ((float)e.Y - (float)RotaStartPos.Y) * 180 * 2.5 / (float)this.map.Height;
                if (RotationF > 90) RotationF = 90;
                if (RotationF < 0) RotationF = 0;
                needInvalidate = true;
@@ -1779,7 +712,9 @@
            }
            //else
            /*判断是否触碰到对象*/
            if (_mouseHoverCheckFlag)
            {
                _mouseHoverCheckFlag = false;
                // 遍历所有对象,找出范围内的对象
                PointF clickedPoint = new PointF(e.X, e.Y);  //ScreenToMap(new PointF(e.X, e.Y));
                var obj = GetObj_by_ScreenPoint(clickedPoint);
@@ -1806,7 +741,7 @@
            
            if (needInvalidate) this.Invalidate();
            if (needInvalidate) this.SetMapInvalidate();
            label_mouse.Text = $"X:{e.X.ToString("0")} Y:{e.Y.ToString("0")} [Map]X:{_MousePosition.X.ToString("0.00")} Y:{_MousePosition.Y.ToString("0.00")}";
            _lastMouseX = e.X;
            _lastMouseY = e.Y;
@@ -1833,7 +768,7 @@
        DateTime _lastMouseUp = DateTime.Now;
        int doubleClick_Delay = 500;//毫秒
        bool recordView = false;
        protected override void OnMouseUp(MouseEventArgs e)
        void mapMouseUp(MouseEventArgs e)
        {
            //BookMark    :鼠标抬起事件
            base.OnMouseUp(e);
@@ -1858,13 +793,13 @@
                var new_center = MapPointToWorldPoint(new PointF(start.X + size.Width / 2, start.Y + size.Height / 2));
                this.MapCenter = new_center;
                this.zoom = Math.Max(1.0f * Width / size.Width, 1.0f * Height / size.Height);
                this.zoom = Math.Max(1.0f * this.map.Width / size.Width, 1.0f * this.map.Height / size.Height);
                if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption);
                label_center.Text = $"center:({MapCenter.X.ToString("0.000")} ,{MapCenter.Y.ToString("0.000")})";
                label_zoom.Text = $"Zoom:{zoom.ToString("0.000")}";
                Invalidate();
                SetMapInvalidate();
                return;
            }
            if /*放大镜*/(ModifierKeys == Keys.Shift && (e.Button == MouseButtons.Middle || e.Button == MouseButtons.XButton2))
@@ -1924,12 +859,13 @@
                _isSettingBackGroundPictur = false;
                mapOption.isShowPic = true;
                this.Cursor = _lastCursor;
                Invalidate();
                SetMapInvalidate();
                return;
            }
            if  /*插入结构*/(e.Button == MouseButtons.Left && _isInsertingObject)
            {
                var net = _newTemplate.network;
                var net = _newTemplate.network;//clone
                var net0 = _newTemplate.network.DeepCopyByBin<MapViewNetWork>();
                List<NodeViewModel> nodes = _Nodes.Select(node => (NodeViewModel)node).ToList();
                float minDist = 100f;
                NodeViewModel minNode = null;
@@ -1954,7 +890,7 @@
                    var p1 = (PointF3D)_undoOldValue;
                    var p2 = minNode.Position3D;
                    var dd = _newTemplate.OffSet;
                    //var dd = _newTemplate.OffSet;
                    dx = p2.X - p1.X;
                    dy = p2.Y - p1.Y;
                    dz = p2.Z - p1.Z;
@@ -1967,7 +903,7 @@
                    _NewNet.Clear();
                    _OperaNode = null;
                    _isInsertingObject = false;
                    this.Invalidate();
                    this.SetMapInvalidate();
                    return;
                    var p1 = (PointF3D)_undoOldValue;
@@ -1985,7 +921,7 @@
                var list = _Network.Add(net);
                var j = _Network.AddPipe(minNode, _OperaNode);
                j.Length = 0.0001f;
                //j.Length = 0.0001f;
                list.Add(j);
                _OperaNode = null;
                _NewNet.Clear();
@@ -1999,13 +935,19 @@
                selectedObjs.AddRange(list);
                MapObjectExtensions.AddCommand(_Network, "Add", null, list);
                _isInsertingObject = false;
                //_OperaNode = null;
                //_Network.Nodes.AddRange(net.Nodes);
                //_Network.Links.AddRange(net.Links);
                Invalidate();
                _newTemplate.network = net0;
                _isInsertingObject = true;
                _undoOldValue = new PointF3D(0, 0, 0);
                _OperaNode = _newTemplate.network.Nodes.Find(node => node.ID == _newTemplate.Node1) as NodeViewModel;
                SetMapInvalidate();
                return;
            }
            if  /*多边形选择*/(_isDrawingPolygon && e.Button == MouseButtons.Left && ModifierKeys == Keys.None)
@@ -2033,7 +975,7 @@
                    });
                }
                Invalidate();
                SetMapInvalidate();
                // 结束绘制多边形
                return;
            }
@@ -2071,6 +1013,10 @@
                    List<PointF3D> newPositons = selectedNodes.Select(n => n.Position3D).ToList();
                    List<PointF3D> oldPositons = newPositons.Select(n => new PointF3D(n.X - dx, n.Y - dy, n.Z - dz)).ToList();
                    MapObjectExtensions.AddCommand(selectedNodes, "Position3D", oldPositons, newPositons);
                    var l = new List<IBaseViewModel>();
                    l.Add(_Network.AddPipe(_OperaNode, minNode));
                    if (l.Count > 0) MapObjectExtensions.AddCommand(_Network, "Add", null, l);
                    _OperaNode = null;
                    _NewNet.Clear();
                }
@@ -2090,7 +1036,7 @@
                    _OperaNode = null;
                    _NewNet.Clear();
                }
                this.Invalidate();
                this.SetMapInvalidate();
                return;
            }
            if  /*取消移动对象*/(_isMovingObject && !isMouseMoved && e.Button == MouseButtons.Left)
@@ -2145,7 +1091,7 @@
                    case MouseState.新建重复器:
                        if (_select_junction1 == null)
                        {
                            if (_mouseState == MouseState.新增立管)
                            if (_mouseState==MouseState.新增立管)
                            {
                                var m = ScreenToVMap(new PointF(e.X, e.Y));
                                z = m.Y;
@@ -2157,7 +1103,7 @@
                                getPointAndHeight(e, out p, out z);
                                Set_junction1(e);
                            }
                        }
                        else
                        {
@@ -2169,14 +1115,26 @@
                                //var m = ScreenToVMap(new PointF(e.X, e.Y));
                                //z = m.Y;
                                p = new PointF(wPos.X, wPos.Y);
                                var l = AddLink(e, true, p, wPos.Z);
                                var l = AddLink(new PointF( e.X,e.Y), isdoubleClick, p, wPos.Z);
                                if (l.Count > 0) MapObjectExtensions.AddCommand(_Network, "Add", null, l);
                            }
                            else
                            {
                                getPointAndHeight(e, _select_junction1, out p, out z);
                                var l = AddLink(e, isdoubleClick, p, z);
                                if (l.Count > 0) MapObjectExtensions.AddCommand(_Network, "Add", null, l);
                                if (mapOption.IsOrtho)
                                {
                                    var wPos = GetZZWorldPoint(_select_junction1.Position3D, _MousePosition, new Vector3(1, 1, 0));
                                    //getPointAndHeight(e, _select_junction1, out p, out z);
                                    p = new PointF(wPos.X, wPos.Y);
                                    var l = AddLink(new PointF(e.X, e.Y), isdoubleClick, p, wPos.Z);
                                    if (l.Count > 0) MapObjectExtensions.AddCommand(_Network, "Add", null, l);
                                }
                                else
                                {
                                    getPointAndHeight(e, _select_junction1, out p, out z);
                                    var l = AddLink(new PointF(e.X, e.Y), isdoubleClick, p,z);
                                    if (l.Count > 0) MapObjectExtensions.AddCommand(_Network, "Add", null, l);
                                }
                            }
                            
@@ -2185,7 +1143,7 @@
                }
                _Network.BuildRelation();
                Invalidate();
                SetMapInvalidate();
            }
            if /*锁定点选*/(GlobalObject.LockSelect && !isMouseMoved && _mouseState == MouseState.无 && e.Button == MouseButtons.Left)
            {
@@ -2201,7 +1159,7 @@
                    GlobalObject.PropertyForm.SetObjs(new List<IBaseViewModel>() { obj });
                    if (isJunction) _OperaNode = (NodeViewModel)obj;
                    mousePosition = new PointF(0, 0);
                    Invalidate();
                    SetMapInvalidate();
                }
                else
@@ -2209,7 +1167,7 @@
                    GlobalObject.PropertyForm.SetObjs(new List<IBaseViewModel>() { });
                    _OperaNode = null;
                    mousePosition = new PointF(0, 0);
                    Invalidate();
                    SetMapInvalidate();
                }
                return;
            }
@@ -2253,7 +1211,7 @@
                if (findNode.Count > 0) _OperaNode = findNode[0] as NodeViewModel;
                if (GlobalObject.PropertyForm != null)
                    GlobalObject.PropertyForm.SetObjs(selectedObjs);
                Invalidate();
                SetMapInvalidate();
                mousePosition = new PointF(0, 0);
                return;
            }
@@ -2313,7 +1271,7 @@
                }
                if (GlobalObject.PropertyForm != null)
                    GlobalObject.PropertyForm.SetObjs(selectedObjs);
                Invalidate();
                SetMapInvalidate();
                mousePosition = new PointF(0, 0);
                return;
            }
@@ -2357,7 +1315,7 @@
                }
                if (GlobalObject.PropertyForm != null)
                    GlobalObject.PropertyForm.SetObjs(selectedObjs);
                Invalidate();
                SetMapInvalidate();
                mousePosition = new PointF(0, 0);
                return;
            }
@@ -2382,7 +1340,7 @@
                    _OperaNode = null;
                    Invalidate();
                    SetMapInvalidate();
                    mousePosition = new PointF(0, 0);
@@ -2398,7 +1356,7 @@
                    _OperaNode = null;
                    Invalidate();
                    SetMapInvalidate();
                }
                return;
@@ -2422,7 +1380,7 @@
                        if (GlobalObject.PropertyForm != null)
                            GlobalObject.PropertyForm.SetObjs(selectedObjs);
                        Invalidate();
                        SetMapInvalidate();
                        mousePosition = new PointF(0, 0);
                    }
                    else
@@ -2431,7 +1389,7 @@
                        selectedObjs.Add(obj);
                        if (GlobalObject.PropertyForm != null)
                            GlobalObject.PropertyForm.SetObjs(selectedObjs);
                        Invalidate();
                        SetMapInvalidate();
                        mousePosition = new PointF(0, 0);
                    }
                }
@@ -2447,8 +1405,11 @@
                    if (!isMouseMoved)
                    {
                        右键_Menu.Show(this, e.Location);
                        转换为ToolStripMenuItem.Enabled = selectedNodes.Count > 0; //(selectedObjs.Count == 1);
                        转换为ToolStripMenuItem.Enabled =  selectedNodes.Count > 0; //(selectedObjs.Count == 1);
                        删除ToolStripMenuItem.Enabled = selectedObjs.Count > 0;
                        删除ToolStripMenuItem1.Enabled = selectedObjs.Count > 0;
                    }
                    if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption);
@@ -2581,7 +1542,7 @@
        /// 鼠标滚轮事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseWheel(MouseEventArgs e)
        void mapMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            mapOption0 = mapOption.Copy();
@@ -2590,14 +1551,14 @@
            zoom = Math.Max(MinZoom, Math.Min(MaxZoom, zoom));
            if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption);
            Invalidate();
            SetMapInvalidate();
        }
        private int _lastMouseX;
        private int _lastMouseY;
        #endregion
#endregion 一、全局
        #endregion 一、全局
        #region 二、工具栏
@@ -2632,7 +1593,7 @@
            }
            if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption);
            Invalidate();
            SetMapInvalidate();
        }
        private void tool设置俯视角度_Click(object sender, EventArgs e)
@@ -2643,7 +1604,7 @@
            jiaodu = Convert.ToDouble(tool.Text);
            RotationF = jiaodu;
            if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption);
            Invalidate();
            SetMapInvalidate();
        }
@@ -2655,7 +1616,7 @@
            Rotation = 0;
            InitCenter();
            if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption);
            Invalidate();
            SetMapInvalidate();
        }
        private void 正视图ToolStripMenuItem_Click(object sender, EventArgs e)
        {
@@ -2663,7 +1624,7 @@
            RotationF = 0;
            if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption);
            Invalidate();
            SetMapInvalidate();
        }
        private void 俯视图ToolStripMenuItem_Click(object sender, EventArgs e)
        {
@@ -2671,7 +1632,7 @@
            RotationF = 90;
            MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption);
            Invalidate();
            SetMapInvalidate();
        }
        private void 默认视角ToolStripMenuItem_Click(object sender, EventArgs e)
        {
@@ -2684,7 +1645,7 @@
            Rotation = -45;
            MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption);
            Invalidate();
            SetMapInvalidate();
        }
        private void 设为隐藏ToolStripMenuItem_Click(object sender, EventArgs e)
        {
@@ -2698,7 +1659,7 @@
            });
            this.Invalidate();
            this.SetMapInvalidate();
        }
        private void 设置长度ToolStripMenuItem_Click(object sender, EventArgs e)
        {
@@ -2725,7 +1686,7 @@
                        MovePointbyLength(l.StartNode, l.EndNode, (float)length);
                    }
                    Invalidate();
                    SetMapInvalidate();
                }
@@ -2735,7 +1696,7 @@
            this.Invalidate();
            this.SetMapInvalidate();
        }
        void MovePointbyLength(NodeViewModel node1, NodeViewModel node2, float Length)
        {
@@ -2784,7 +1745,7 @@
                    v.Visible = true;
                }
            });
            this.Invalidate();
            this.SetMapInvalidate();
        }
        #endregion
@@ -2801,6 +1762,8 @@
            {
                _Template = new Template();
                _Template.network = new MapViewNetWork();
                //_Template.network.use_old = false;
                // 获取选中文件的文件路径
                string filePath = openFileDialog.FileName;
@@ -2890,7 +1853,7 @@
        #region 绘图工具
        MouseState _mouseState = MouseState.无;
        public void toolStripButton_新建节点_Click(object sender, EventArgs e)
        {
            _mouseState = MouseState.新增节点;
@@ -2901,6 +1864,55 @@
        {
            _mouseState = MouseState.无;
            Cursor = Cursors.Default;
            if (_isPainting)
            {
                _select_junction1 = null;
                _isPainting = false;
                SetMapInvalidate();
            }
            else if (_isDragging)
            {
                _isDragging = false;
                SetMapInvalidate();
            }
            else if (_isPanning)
            {
                _isPanning = false;
                SetMapInvalidate();
            }
            else if (_isRotating)
            {
                Rotation = Rotation0;
                _isRotating = false;
                SetMapInvalidate();
            }
            else if (_isMovingObject)
            {
                _NewNet.Clear();
                _isMovingObject = false;
                SetMapInvalidate();
            }
            else if (_mouseState != MouseState.无)
            {
                _mouseState = MouseState.无;
                Cursor = Cursors.Default;
            }
            else if (_isInsertingObject)
            {
                _NewNet.Clear();
                _isInsertingObject = false;
                _OperaNode = null;
                SetMapInvalidate();
            }
            else
            {
                _Nodes.ForEach(o => ((NodeViewModel)o).Selected = false);
                _Links.ForEach(o => ((LinkViewModel)o).Selected = false);
                selectedObjs.Clear();
                SetMapInvalidate();
            }
        }
        public void toolStripButton_新建管线_Click(object sender, EventArgs e)
@@ -2908,17 +1920,17 @@
            _mouseState = MouseState.新增管线;
            Cursor = Cursors.Cross;
        }
        public void toolStripButton_新建立管_Click(object sender, EventArgs e)
        public void toolStripButton_新建立管_Click(object sender,EventArgs e)
        {
            _mouseState = MouseState.新增立管;
            Cursor = Cursors.Cross;
        }
        private List<IBaseViewModel> AddLink(MouseEventArgs e, bool isdoubleClick, PointF p, float z)
        private List<IBaseViewModel> AddLink(PointF e, bool isdoubleClick, PointF p, float z)
        {
            List<IBaseViewModel> l = new List<IBaseViewModel>();
            var node = GetObj_by_ScreenPoint(new PointF(e.X, e.Y));
            var node = GetObj_by_ScreenPoint(e);
            if (node != null || isdoubleClick)
            {
                if (node != null && node is NodeViewModel j)
@@ -2931,7 +1943,7 @@
                    l.Add(_select_junction2);
                }
                if (_mouseState == MouseState.新增管线 || _mouseState == MouseState.新增立管)
                if (_mouseState == MouseState.新增管线 || _mouseState==MouseState.新增立管)
                    l.Add(_Network.AddPipe(_select_junction1, _select_junction2));
                else if (_mouseState == MouseState.新建阀门)
                    l.Add(_Network.AddValve(_select_junction1, _select_junction2));
@@ -3004,29 +2016,29 @@
                {
                    _select_junction1 = null;
                    _isPainting = false;
                    Invalidate();
                    SetMapInvalidate();
                }
                else if (_isDragging)
                {
                    _isDragging = false;
                    Invalidate();
                    SetMapInvalidate();
                }
                else if (_isPanning)
                {
                    _isPanning = false;
                    Invalidate();
                    SetMapInvalidate();
                }
                else if (_isRotating)
                {
                    Rotation = Rotation0;
                    _isRotating = false;
                    Invalidate();
                    SetMapInvalidate();
                }
                else if (_isMovingObject)
                {
                    _NewNet.Clear();
                    _isMovingObject = false;
                    Invalidate();
                    SetMapInvalidate();
                }
                else if (_mouseState != MouseState.无)
                {
@@ -3038,21 +2050,21 @@
                    _NewNet.Clear();
                    _isInsertingObject = false;
                    _OperaNode = null;
                    Invalidate();
                    SetMapInvalidate();
                }
                else
                {
                    _Nodes.ForEach(o => ((NodeViewModel)o).Selected = false);
                    _Links.ForEach(o => ((LinkViewModel)o).Selected = false);
                    selectedObjs.Clear();
                    Invalidate();
                    SetMapInvalidate();
                }
            }
            if (e.KeyCode == Keys.Delete)
            if (_IsEditMode && e.KeyCode == Keys.Delete)
            {
                DeleteChoosedObj();
            }
@@ -3061,32 +2073,32 @@
                selectedObjs.Clear();
                _Nodes.ForEach(o => { ((NodeViewModel)o).Selected = true; selectedObjs.Add((NodeViewModel)o); });
                _Links.ForEach(o => { ((LinkViewModel)o).Selected = true; selectedObjs.Add((LinkViewModel)o); });
                Invalidate();
                SetMapInvalidate();
            }
            if (e.KeyCode == Keys.C && e.Modifiers == Keys.Control)
            if (_IsEditMode && e.KeyCode == Keys.C && e.Modifiers == Keys.Control)
            {
                复制ToolStripMenuItem_Click(1, new EventArgs());
            }
            if (e.KeyCode == Keys.V && e.Modifiers == Keys.Control)
            if (_IsEditMode && e.KeyCode == Keys.V && e.Modifiers == Keys.Control)
            {
                _ClickStartPos = Cursor.Position;
                粘贴ToolStripMenuItem1_Click(1, new EventArgs());
            }
            if (e.KeyCode == Keys.D1 && e.Modifiers == Keys.Control)
            if (_IsEditMode && e.KeyCode == Keys.D1 && e.Modifiers == Keys.Control)
            {
                南北对齐ToolStripMenuItem_Click(1, new EventArgs());
            }
            if (e.KeyCode == Keys.Oemtilde && e.Modifiers == Keys.Control)
            if (_IsEditMode && e.KeyCode == Keys.Oemtilde && e.Modifiers == Keys.Control)
            {
                东西对齐ToolStripMenuItem_Click(1, new EventArgs());
            }
            if (e.KeyCode == Keys.D2 && e.Modifiers == Keys.Control)
            if (_IsEditMode && e.KeyCode == Keys.D2 && e.Modifiers == Keys.Control)
            {
                竖直对齐ToolStripMenuItem_Click(1, new EventArgs());
            }
            if (e.KeyCode == Keys.D3 && e.Modifiers == Keys.Control)
            if (_IsEditMode && e.KeyCode == Keys.D3 && e.Modifiers == Keys.Control)
            {
                自动对齐ToolStripMenuItem_Click(1, new EventArgs());
            }
@@ -3096,7 +2108,7 @@
        private void MapViewer_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (ctrlPressed && e.KeyChar == 'Z' - 64)
            if (_IsEditMode && ctrlPressed && e.KeyChar == 'Z' - 64)
            {
                // 执行相应的操作
                buttonUndo_Click(sender, e);
@@ -3105,7 +2117,7 @@
                // 防止默认操作
                e.Handled = true;
            }
            if (ctrlPressed && e.KeyChar == 'Y' - 64)
            if (_IsEditMode && ctrlPressed && e.KeyChar == 'Y' - 64)
            {
                // 执行相应的操作
                buttonRedo_Click(sender, e);
@@ -3126,14 +2138,14 @@
        }
        private void MapViewer_PreKeyPress(object sender, PreviewKeyDownEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.Z)
            if (_IsEditMode && e.Control && e.KeyCode == Keys.Z)
            {
                ctrlPressed = true;
                // 防止默认操作
                e.IsInputKey = true;
            }
            if (e.Control && e.KeyCode == Keys.Y)
            if (_IsEditMode && e.Control && e.KeyCode == Keys.Y)
            {
                ctrlPressed = true;
                // 防止默认操作
@@ -3156,7 +2168,7 @@
            else
                position = obj.Position;
            PointF currentPos = MapToScreen(WorldPointToMapPoint(position, obj.Elev));
            PointF centerScreen = new PointF(this.Width / 2, this.Height / 2);
            PointF centerScreen = new PointF(this.map.Width / 2, this.map.Height / 2);
            var vector = GetRotateVector(centerScreen, currentPos);
            MapCenter = new PointF(
            MapCenter.X - vector.X / Zoom.X,
@@ -3255,7 +2267,7 @@
            }
            Invalidate();
            SetMapInvalidate();
        }
        public void 删除ToolStripMenuItem_Click(object sender, EventArgs e)
@@ -3268,7 +2280,7 @@
            var list = _Network.Remove(selectedObjs);
            MapObjectExtensions.AddCommand(_Network, "Remove", null, list);
            selectedObjs.Clear();
            Invalidate();
            SetMapInvalidate();
        }
        #endregion
@@ -3281,7 +2293,7 @@
        {
            _IsEditMode = !_IsEditMode;
            //toolStripComboBox_浏览模式.Text = isEditMode ? "编辑模式" : "浏览模式";
            LoadData(true);
            //LoadData(true);
        }
        private void 浏览模式ToolStripMenuItem_Click(object sender, EventArgs e)
@@ -3289,7 +2301,7 @@
            var obj = sender as ToolStripItem;
            _IsEditMode = obj.Text == "编辑模式";
            //toolStripComboBox_浏览模式.Text = isEditMode ? "编辑模式" : "浏览模式";
            LoadData(true);
            //LoadData(true);
        }
        #endregion
@@ -3361,7 +2373,7 @@
            MapObjectExtensions.AddCommand(nodes, "Position", OldPositions, NewPositions);
            Invalidate();
            SetMapInvalidate();
        }
@@ -3443,7 +2455,7 @@
        private void 缩放ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var objs = GlobalObject.PropertyForm.selectionSet.selectedObjects;
            var list = objs.FindAll(o => o is NodeViewModel); //GlobalObject.PropertyForm.listBox1.SelectedItems;
            if (list.Count <= 0) return;
@@ -3491,7 +2503,7 @@
            MapObjectExtensions.AddCommand(nodes, "Position3D", OldPositions, NewPositions);
            Invalidate();
            SetMapInvalidate();
        }
        public static List<PointF3D> ScalePoints(List<PointF3D> points, PointF3D centerPoint, float scale)
@@ -3517,12 +2529,103 @@
        }
        private void btn_初分配_Click(object sender, EventArgs e)
        {
            string result = null;
            if ((result=_Template.network.CheckValidate())!=null)
            {
                MessageBox.Show(result);
                return;
            }
            List<WaterEquivalentSettings> settings = new List<WaterEquivalentSettings>();
            settings.Add(new WaterEquivalentSettings()
            {
                waterEquivalents=new WaterEquivalentTemplate()
                {
                    ID="1",
                    Name="1",
                    WaterEquivalentCollection=new WaterEquivalentCollection()
                    {
                        new WaterEquivalent()
                        {
                            ID=1008,
                            MinRatedFlow=0.48f,
                            RatedFlow=0.72f,
                            Count=1,
                        },
                        new WaterEquivalent()
                        {
                            ID=1009,
                            MinRatedFlow=0.88f,
                            RatedFlow=0.96f,
                            Count=2,
                        },
                        new WaterEquivalent()
                        {
                            ID=1010,
                            MinRatedFlow=1.08f,
                            RatedFlow=1.08f,
                            Count=3,
                        }
                    }
                },
                Meters=new List<string>()
                {
                    //按以下规律生成数组到M10,"M1","M2"
                        "M1","M2","M3","M4","M5","M6","M7","M8","M9","M10","M11","M12","M13","M14","M15","M16",
                    "M17","M18","M19","M20","M21","M22","M23","M24","M25","M26","M27","M28","M29","M30"
                },
            });
            settings.Add(new WaterEquivalentSettings()
            {
                waterEquivalents = new WaterEquivalentTemplate()
                {
                    ID = "1",
                    Name = "1",
                    WaterEquivalentCollection = new WaterEquivalentCollection()
                    {
                        new WaterEquivalent()
                        {
                            ID=2008,
                            MinRatedFlow=0.48f,
                            RatedFlow=0.48f,
                            Count=1,
                        },
                        new WaterEquivalent()
                        {
                            ID=2009,
                            MinRatedFlow=0.12f,
                            RatedFlow=0.12f,
                            Count=5,
                        },
                        new WaterEquivalent()
                        {
                            ID=2010,
                            MinRatedFlow=0.16f,
                            RatedFlow=0.18f,
                            Count=6,
                        }
                    }
                },
                Meters = new List<string>()
                {
                    //按以下规律生成数组到M10,"M1","M2"
                       "M31","M32","M33","M34","M35","M36","M37","M38","M39","M40","M41","M42","M43","M44","M45","M46","M47","M48","M49","M50","M51","M52","M53","M54","M55","M56","M57","M58","M59","M60","M61","M62","M63","M64","M65","M66","M67","M68","M69","M70","M71","M72","M73","M74","M75","M76","M77","M78","M79","M80"
                },
            });
            var head=_Network.reservoirs.FirstOrDefault().Head;
            _Network.WaterDistribution(_Template.FullPath, GlobalPath.configPath + "config_waterDistri.wdb",settings,40, head);
        }
        public void toolStripButton_计算_Click(object sender, EventArgs e)
        {
            //LoadData();
            _Network.Calc(_Template.FullPath, GlobalPath.configPath + "config_calc.wdb");
            _Network.Calc(_Template.FullPath, GlobalPath.configPath+ "config_calc.wdb");
        }
        public void 关阀搜索ToolStripMenuItem_Click(object sender, EventArgs e)
@@ -3536,7 +2639,7 @@
                selectedObjs.Clear();
                TraversePipeNetwork(objs, null, false);
                selectsValve.ForEach(o => o.Selected = false);
                this.Invalidate();
                this.SetMapInvalidate();
            }
        }
@@ -3556,7 +2659,7 @@
                selectedObjs.Clear();
                TraversePipeNetwork(objs, null);
                selectsValve.ForEach(o => o.Selected = false);
                this.Invalidate();
                this.SetMapInvalidate();
            }
        }
@@ -3794,11 +2897,11 @@
        //        objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes));
        //        this.Invalidate();
        //        this.SetInvalidated();
        //    }
        //}
        private void TraversePipeNetworkALL(LinkViewModel startLink, HashSet<NodeViewModel> visitedNodes = null, int direction = 0)
        private void TraversePipeNetworkALL(LinkViewModel startLink, HashSet<NodeViewModel> visitedNodes = null,int direction=0)
        {
            Queue<LinkViewModel> queue = new Queue<LinkViewModel>();
@@ -3856,13 +2959,13 @@
        private void 显示节点ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _ShowJunction = true;
            Invalidate();
            SetMapInvalidate();
        }
        private void 隐藏节点ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _ShowJunction = false;
            Invalidate();
            SetMapInvalidate();
        }
        private void 大ToolStripMenuItem_Click(object sender, EventArgs e)
@@ -3880,20 +2983,20 @@
            {
                junction_multiply = 0.4f;
            }
            Invalidate();
            SetMapInvalidate();
        }
        private void 显示阀门ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _ShowValve = true;
            Invalidate();
            SetMapInvalidate();
        }
        private void 隐藏阀门ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _ShowValve = false;
            Invalidate();
            SetMapInvalidate();
        }
@@ -3913,7 +3016,7 @@
            {
                Link_multiply = 0.4f;
            }
            Invalidate();
            SetMapInvalidate();
        }
@@ -4153,13 +3256,13 @@
        }
        public void buttonUndo_Click(object sender, EventArgs e)
        {
            SetInvalidated();
            SetMapInvalidate();
            GlobalObject.PropertyForm.propertyGrid.Refresh();
            MapObjectExtensions.Undo();
        }
        public void buttonRedo_Click(object sender, EventArgs e)
        {
            SetInvalidated();
            SetMapInvalidate();
            GlobalObject.PropertyForm.propertyGrid.Refresh();
            MapObjectExtensions.Redo();
        }
@@ -4180,6 +3283,59 @@
            {
                bool isReplace = false;
                _Network.BuildToInp(_filePath, null, null, false);
            }
        }
        /// <summary>
        /// 批量一键生成楼层模型
        /// </summary>
        public void BatchInsertNet(Template temp)
        {
            var nodes = _Nodes.Where(c => c.Elev > 0).Select(node => (NodeViewModel)node).ToList();
            _undoOldValue = new PointF3D(0, 0, 0);
            _OperaNode = temp.network.Nodes.Find(node => node.ID == temp.Node1) as NodeViewModel;
            //foreach (var item in nodes)
            if (nodes.Any())
            {
                for (var i = 0; i < nodes.Count(); i++)
                {
                    var net = temp.network.DeepCopy();
                    float dx, dy, dz;
                    var p1 = (PointF3D)_undoOldValue;
                    var p2 = nodes[i].Position3D;
                    var dd = temp.OffSet;
                    dx = p2.X - p1.X;
                    dy = p2.Y - p1.Y;
                    dz = p2.Z - p1.Z;
                    net.Nodes.ForEach(n => { ((NodeViewModel)n).Position3D = new PointF3D(n.X + dx, n.Y + dy, n.Elev + dz); });
                    var list = _Network.Add(net);
                    //var j = _Network.AddPipe(nodes[i], _OperaNode);
                    //j.Length = 0.0001f;
                    //list.Add(j);
                    _NewNet.Clear();
                    _Network.BuildRelation();
                    selectedObjs.ForEach(o => o.Selected = false);
                    selectedObjs.Clear();
                    //list.ForEach(m => m.Selected = true);
                    //selectedObjs.AddRange(list);
                    MapObjectExtensions.AddCommand(_Network, "Add", null, list);
                }
                _OperaNode = null;
                //_OperaNode = null;
                //_Network.Nodes.AddRange(net.Nodes);
                //_Network.Links.AddRange(net.Links);
                SetMapInvalidate();
            }
        }
@@ -4242,14 +3398,14 @@
            {
                var objs = selectedObjs.FindAll(o => o is LinkViewModel).Select(o => o as LinkViewModel).ToList();
                if (objs.Count == 0) selectedObjs.FindAll(o => o is NodeViewModel).Select(o => o as NodeViewModel).ToList().ForEach(o => objs.AddRange(o.Links.Select(l => l as LinkViewModel).ToList()));
                if (objs.Count == 0) selectedObjs.FindAll(o => o is NodeViewModel).Select(o => o as NodeViewModel).ToList().ForEach(o=>objs.AddRange(o.Links.Select(l=>l as LinkViewModel).ToList()));
                //objs去掉重复的元素
                objs = objs.Distinct().ToList();
                var visitedNodes = new HashSet<NodeViewModel>();
                objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes));
                this.Invalidate();
                this.SetMapInvalidate();
            }
        }
@@ -4259,15 +3415,15 @@
            {
                var objs = selectedObjs.FindAll(o => o is LinkViewModel).Select(o => o as LinkViewModel).ToList();
                if (objs.Count == 0) selectedObjs.FindAll(o => o is NodeViewModel).Select(o => o as NodeViewModel).ToList().ForEach(o =>
                if (objs.Count == 0) selectedObjs.FindAll(o => o is NodeViewModel).Select(o => o as NodeViewModel).ToList().ForEach(o =>
                {
                    objs.AddRange(o.Links.Select(oo => oo as LinkViewModel).ToList().FindAll(oo => oo.StartNode == o ? oo.EN_FLOW > 0 : oo.EN_FLOW < 0));
                    objs.AddRange(o.Links.Select(oo => oo as LinkViewModel).ToList().FindAll(oo=>oo.StartNode==o?oo.EN_FLOW>0:oo.EN_FLOW<0));
                });
                //objs去掉重复的元素
                objs = objs.Distinct().ToList();
                var visitedNodes = new HashSet<NodeViewModel>();
                objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes, 1));
                this.Invalidate();
                objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes,1));
                this.SetMapInvalidate();
            }
        }
@@ -4295,7 +3451,7 @@
            try
            {
                Clipboard.SetText(json);
                this.Invalidate();
                this.SetMapInvalidate();
            }
            catch
            {
@@ -4308,29 +3464,62 @@
        public void 粘贴ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            {
                var net = new MapViewNetWork();
                string json = Clipboard.GetText();
                net.ReadFromJson(json);
                PointF minPoint = new PointF(net.StartPoint.X, net.StartPoint.Y);
                if (net.StartPoint == null) return;
                string SID = net.StartPoint.ID;
                net.StartPoint=net.Nodes.Find(n => n.ID == SID);
                PointF3D minPoint = net.StartPoint.Position3D;// new PointF(net.StartPoint.X, net.StartPoint.Y);
                Point controlLocation = this.PointToScreen(new Point(0, 0));
                int offsetX = Cursor.Position.X - controlLocation.X;
                int offsetY = Cursor.Position.Y - controlLocation.Y;
                var position = new Point(offsetX, offsetY);
                net.BuildRelation();
                var basePoint = MapPointToWorldPoint(ScreenToMap(position, net.StartPoint.Elev), net.StartPoint.Elev);
                net.Nodes.ForEach(obj =>
                //var basePoint = MapPointToWorldPoint(ScreenToMap(position, net.StartPoint.Elev), net.StartPoint.Elev);
                var mPos = _MousePosition;
                if (hoveredObjs.Count>0 && hoveredObjs[0] is NodeViewModel minNode)
                {
                    obj.X = obj.X + basePoint.X - minPoint.X;
                    obj.Y = obj.Y + basePoint.Y - minPoint.Y;
                });
                selectedObjs.ForEach(o => o.Selected = false);
                selectedObjs.Clear();
                selectedObjs.AddRange(net.Nodes.Select(n => (NodeViewModel)n));
                selectedObjs.AddRange(net.Links.ViewLinks);
                var list = _Network.Add(net);
                MapObjectExtensions.AddCommand(_Network, "Add", null, list);
                Invalidate();
                    var basePoint = minNode.Position3D;
                    net.Nodes.ForEach(obj =>
                    {
                        obj.X = obj.X + basePoint.X - minPoint.X;
                        obj.Y = obj.Y + basePoint.Y - minPoint.Y;
                        obj.Elev = obj.Elev + basePoint.Z - minPoint.Z;
                    });
                    selectedObjs.ForEach(o => o.Selected = false);
                    selectedObjs.Clear();
                    selectedObjs.AddRange(net.Nodes.Select(n => (NodeViewModel)n));
                    selectedObjs.AddRange(net.Links.ViewLinks);
                    var list = _Network.Add(net,null,false,minNode);
                    net.BuildRelation();
                    //list.Add(_Network.AddPipe(Snode, minNode));
                    MapObjectExtensions.AddCommand(_Network, "Add", null, list);
                    SetMapInvalidate();
                }
                else
                {
                    var basePoint = MapPointToWorldPoint(_MousePosition, net.StartPoint.Elev);
                    net.Nodes.ForEach(obj =>
                    {
                        obj.X = obj.X + basePoint.X - minPoint.X;
                        obj.Y = obj.Y + basePoint.Y - minPoint.Y;
                    });
                    selectedObjs.ForEach(o => o.Selected = false);
                    selectedObjs.Clear();
                    selectedObjs.AddRange(net.Nodes.Select(n => (NodeViewModel)n));
                    selectedObjs.AddRange(net.Links.ViewLinks);
                    var list = _Network.Add(net);
                    net.BuildRelation();
                    MapObjectExtensions.AddCommand(_Network, "Add", null, list);
                    SetMapInvalidate();
                }
            }
        }
        private void 增量保存ToolStripMenuItem_Click(object sender, EventArgs e)
@@ -4358,13 +3547,13 @@
        private void 设为关闭ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            selectedObjs.ForEach(obj => { if (obj is LinkViewModel link) link.Status =Hydro.Core.ObjectEnum. StatusType.CLOSED; });
            Invalidate();
            SetMapInvalidate();
        }
        private void 显示全部楼层ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //this.mapOption.ShowFloor = int.MinValue;
            _Network.MapObjects.ForEach(o => o.Visible = true);
            this.Invalidate();
            this.SetMapInvalidate();
        }
        private void 保存楼层视角ToolStripMenuItem_Click(object sender, EventArgs e)
        {
@@ -4381,7 +3570,7 @@
            List<float> list1 = new List<float>();
            selectedNodes.ForEach(n => { list.Add(n.X); n.X = selectedNodes[0].X; list1.Add(n.X); });
            MapObjectExtensions.AddCommand(selectedNodes, "X", list, list1);
            this.Invalidate();
            this.SetMapInvalidate();
        }
        public void 东西对齐ToolStripMenuItem_Click(object sender, EventArgs e)
        {
@@ -4390,7 +3579,7 @@
            List<float> list1 = new List<float>();
            selectedNodes.ForEach(n => { list.Add(n.Y); n.Y = selectedNodes[0].Y; list1.Add(n.Y); });
            MapObjectExtensions.AddCommand(selectedNodes, "Y", list, list1);
            this.Invalidate();
            this.SetMapInvalidate();
        }
        public void 竖直对齐ToolStripMenuItem_Click(object sender, EventArgs e)
        {
@@ -4399,7 +3588,7 @@
            List<PointF> list1 = new List<PointF>();
            selectedNodes.ForEach(n => { list.Add(n.Position); n.Position = selectedNodes[0].Position; list1.Add(n.Position); });
            MapObjectExtensions.AddCommand(selectedNodes, "Position", list, list1);
            this.Invalidate();
            this.SetMapInvalidate();
        }
        public void 自动对齐ToolStripMenuItem_Click(object sender, EventArgs e)
        {
@@ -4412,7 +3601,7 @@
            }
            MapObjectExtensions.AddCommand(selectedNodes, "Position3D", OldPosition3Ds, NewPosition3Ds);
            this.Invalidate();
            this.SetMapInvalidate();
        }
        List<PointF3D> ProjectPointsToLine(List<PointF3D> points)
        {
@@ -4479,7 +3668,7 @@
            {
                var backgroundImagePath = openFileDialog.FileName;
                Global.ClearFileReadOnly(_Template.BackGroundImg_FullPath);
                File.Copy(backgroundImagePath, _Template.BackGroundImg_FullPath, true);
                FileCopy.Copy(backgroundImagePath, _Template.BackGroundImg_FullPath, true);
                设置底图ToolStripMenuItem_Click(1, new EventArgs());
            }
        }
@@ -4506,7 +3695,7 @@
        public void 显示隐藏底图ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            mapOption.isShowPic = !mapOption.isShowPic;
            Invalidate();
            SetMapInvalidate();
        }
        private dict<string, dynamic> param = null;
@@ -4514,7 +3703,7 @@
        public void 清除底图ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            mapOption.isShowPic = false;
            Invalidate();
            SetMapInvalidate();
            try
            {
                File.Delete(_Template.BackGroundImg_FullPath);
@@ -4573,7 +3762,7 @@
                }
            });
            this.Invalidate();
            this.SetMapInvalidate();
        }
        private void 全选ToolStripMenuItem_Click(object sender, EventArgs e)
@@ -4588,7 +3777,7 @@
                }
            });
            this.Invalidate();
            this.SetMapInvalidate();
        }
        private void 反选ToolStripMenuItem_Click(object sender, EventArgs e)
@@ -4612,23 +3801,23 @@
                }
            });
            this.Invalidate();
            this.SetMapInvalidate();
        }
        private void 显示状态ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Template.mapOption._ShowStatus = true;
            this.Invalidate();
            this.SetMapInvalidate();
        }
        private void 隐藏状态ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Template.mapOption._ShowStatus = false;
            this.Invalidate();
            this.SetMapInvalidate();
        }
        private void 显示流向ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Template.mapOption._ShowFlowDirection = true;
            this.Invalidate();
            this.SetMapInvalidate();
@@ -4636,7 +3825,7 @@
        private void 隐藏流向ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Template.mapOption._ShowFlowDirection = false;
            this.Invalidate();
            this.SetMapInvalidate();
        }
@@ -4671,11 +3860,11 @@
                string tagstring = i.ToString() + "楼";
                if (tags.Contains(tagstring))
                {
                    var item = ToolStripMenuItem_Floor.DropDownItems.Add(i.ToString() + "楼");
                    var item=ToolStripMenuItem_Floor.DropDownItems.Add(i.ToString() + "楼");
                    item.Click += (oo, ee) =>
                    {
                        mapobjects.ForEach(o =>
                        {
                            if (o.Tags.Contains(tagstring))
@@ -4687,18 +3876,18 @@
                                o.Visible = false;
                            }
                        });
                        this.Invalidate();
                        this.SetMapInvalidate();
                    };
                }
            }
            this.Invalidate();
            this.SetMapInvalidate();
        }
        private void 显示所有隐藏内容ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Network.MapObjects.ForEach(o => o.Visible = true);
            this.Invalidate();
            this.SetMapInvalidate();
        }
        public void toolStripButton_CalcMiniLoss_Click(object sender, EventArgs e)
        {
@@ -4708,100 +3897,50 @@
        }
        private void toolStripButton_ClearMinor_Click(object sender, EventArgs e)
        {
            _Network.ClearMinorLoss();
        }
        private void 显示流向ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            _isShowDirection = !_isShowDirection;
        }
        bool _isShowDirection = false;
        bool _isShowDirection=false;
        private void 颜色分级管理ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form_Colour form_Colour = new Form_Colour(_Template.Colours);
            Form_Colour form_Colour = new Form_Colour(_Template.Colours,_Template);
            form_Colour.Show(this);
        }
        Colour _NodeColour = null;
        Colour _LinkColour = null;
      private bool __needpaintall=false;
        private List<IBaseViewModel> hoveredObjs=new List<IBaseViewModel>();
        private bool __isOrtho = true;
        private bool _isOrtho
        {
            get
            {
                return __isOrtho;
            }
            set
            {
                __isOrtho = value;
                if (__isOrtho)
                {
                    label_ZZ.Text = "正交模式:开";
                }
                else
                {
                    label_ZZ.Text = "正交模式:关";
                }
            }
        }
        private void cb_Node_Colour_Click(object sender, EventArgs e)
        {
        }
        private void cb_Link_Colour_Click(object sender, EventArgs e)
        {
        }
        private void cb_Link_Colour_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_Template == null) return;
            mapOption.LinkColourIndex = cb_Link_Colour.SelectedIndex;
            var type = cb_Link_Colour.SelectedItem == null ? ColourType.管线流量 : (ColourType)cb_Link_Colour.SelectedItem;
            var Colours = _Template.Colours.FindAll(c => c.Type == type);
            if (Colours.Count == 0)
            {
                _LinkColour = null;
            }
            else
            {
                var cls = Colours.FindAll(cl => cl.isChoosed);
                if (cls.Count >= 1)
                {
                    _LinkColour = cls[0];
                }
                else
                {
                    _LinkColour = Colours[0];
                }
            }
            this.Invalidate();
            var doubles = _Template.network.getMinMax(type);
            var colour = new Colour(type, null, type.ToString());
            List<ColourItem> colours = Colour.GetColourItems((float)doubles[0], (float)doubles[1], 5, Color.Gray, Color.Red);
            colour.Items = colours;
            LinkColour = colour;
            this.SetMapInvalidate();
        }
        private void cb_Node_Colour_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_Template == null) return;
            mapOption.NodeColourIndex = cb_Node_Colour.SelectedIndex;
            var type = cb_Node_Colour.SelectedItem == null ? ColourType.节点自由压力 : (ColourType)cb_Node_Colour.SelectedItem;
            var Colours = _Template.Colours.FindAll(c => c.Type == type);
            if (Colours.Count == 0)
            {
                _NodeColour = null;
            }
            else
            {
                var cls = Colours.FindAll(cl => cl.isChoosed);
                if (cls.Count >= 1)
                {
                    _NodeColour = cls[0];
                }
                else
                {
                    _NodeColour = Colours[0];
                }
            }
            this.Invalidate();
            var doubles = _Template.network.getMinMax(type);
            var colour = new Colour(type, null, type.ToString());
            List<ColourItem> colours = Colour.GetColourItems((float)doubles[0], (float)doubles[1], 5, Color.Gray, Color.Red);
            colour.Items = colours;
            NodeColour = colour;
            this.SetMapInvalidate();
        }
        private void label_ZZ_Click(object sender, EventArgs e)
@@ -4822,36 +3961,7 @@
       
        public class Prompt : Form
        {
            private static TextBox textBox;
            private static Button okButton;
            public static string ShowDialog(string text, string caption, string defaultTxt = "")
            {
                Form prompt = new Form()
                {
                    Width = 200,
                    Height = 150,
                    FormBorderStyle = FormBorderStyle.FixedDialog,
                    Text = caption,
                    StartPosition = FormStartPosition.CenterScreen
                };
                Label textLabel = new Label() { Left = 20, Top = 20, Text = text };
                textBox = new TextBox() { Left = 20, Top = 50, Width = 150 };
                textBox.Text = defaultTxt;
                okButton = new Button() { Text = "确定", Left = 75, Width = 75, Top = 80 };
                okButton.Click += (sender, e) => { prompt.Close(); };
                prompt.Controls.Add(textBox);
                prompt.Controls.Add(textLabel);
                prompt.Controls.Add(okButton);
                prompt.ShowDialog();
                return textBox.Text;
            }
        }
        #endregion
    }
}