ningshuxia
2025-03-24 7b8ae93d47186c442ff890a1a83d108f115924c7
WinFrmUI/PBS.WinFrmUI.Hydro/99-map-view/Class1.cs
@@ -2,10 +2,8 @@
using MathNet.Numerics.LinearAlgebra.Double;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.ComponentModel;
using System.Data;
using System.Drawing.Design;
using System.IO;
using System.Numerics;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
@@ -16,10 +14,7 @@
using Cursor = System.Windows.Forms.Cursor;
namespace Hydro;
public class TemplateStoreViewModel
{
    public List<Template> templates { get; set; } = new List<Template>();
}
partial class DMap
{
@@ -71,6 +66,8 @@
    drawingOthers,
    Ready,
}
[Serializable]
public class MapOption
{
    public float Link_multiply { get; set; } = 0.6667f;
@@ -82,1553 +79,1468 @@
}
partial class MapViewer
{
    void DrawBackGroud(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();
//[Serializable]
//partial class MapViewer
//{
//    void DrawBackGroud(Graphics bufferG, Template template)
//    {
//        if (template == null) return;
//        var _Nodes = template.network.Nodes.ViewNodes;
//        var _Links = template.network.Links.ViewLinks;
        var r = 1.73f / zoom;
        var rt = r;
//        var Cpoints = getCurclePoints(64)?.ToList();
//        var r = 1.73f / zoom;
//        var rt = r;
        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) };
//        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 penN = new Pen(Color.FromArgb(0, 0, 255), 1 * r);
        //背景图绘制
        if (this.mapOption.isShowPic && template != null && File.Exists(template.BackGroundImg_FullPath))
//        //背景图绘制
//        if (this.mapOption.isShowPic && template != null && File.Exists(template.BackGroundImg_FullPath))
        {
            //var gs = bufferG.Save();
            // 应用矩阵变换以抵消之前的翻转效果
            //bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
            List<PointF> p = new List<PointF>();
//        {
//            //var gs = bufferG.Save();
//            // 应用矩阵变换以抵消之前的翻转效果
//            //bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
//            List<PointF> p = new List<PointF>();
            if (!this.mapOption.isAutoBackgroundImage)
            {
                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,
};
                Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet)));
            }
            else
            {
                // 恢复之前保存的绘图状态
                //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,
                //};
                var p1 = new PointF(template.BackGroundImgX, template.BackGroundImgY);
                var p2 = new PointF(template.BackGroundImgX + template.BackGroundImgWidth, template.BackGroundImgY + template.BackGroundImgHeight);
                var f = template.BackGroundImgRotaAngle / 180 * Math.PI;
                var djx = Math.Sqrt((Math.Pow(template.BackGroundImgWidth, 2) + Math.Pow(template.BackGroundImgHeight, 2)));
                var p3 = new PointF(p1.X + (float)(Math.Cos(f) * template.BackGroundImgWidth), p1.Y + (float)(Math.Sin(f) * template.BackGroundImgWidth));
                var p4 = new PointF(p1.X - (float)(Math.Sin(f) * template.BackGroundImgHeight), p1.Y + (float)(Math.Cos(f) * template.BackGroundImgHeight));
                p3.Y = p4.Y;
                //p4.Y = -p4.Y;
                var Cps = new List<PointF>
{
//            if (!this.mapOption.isAutoBackgroundImage)
//            {
//                var Cps = new List<PointF>
//{
//template.BackGroundPoint1,
//new PointF(template.BackGroundImgX,template.BackGroundImgY),
p4,
p3,p1
//template.BackGroundPoint2,
//new PointF(template.BackGroundPoint2.X,template.BackGroundPoint1.Y),
//new PointF(template.BackGroundPoint1.X,template.BackGroundPoint2.Y),
};
                template.BackGroundPoint1 = p4;
                template.BackGroundPoint2 = new PointF(p3.X, p1.Y);
//};
//                Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet)));
//            }
//            else
//            {
                //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
            {
//                var p1 = new PointF(template.BackGroundImgX, template.BackGroundImgY);
//                var p2 = new PointF(template.BackGroundImgX + template.BackGroundImgWidth, template.BackGroundImgY + template.BackGroundImgHeight);
            }
//                var f = template.BackGroundImgRotaAngle / 180 * Math.PI;
//                var djx = Math.Sqrt((Math.Pow(template.BackGroundImgWidth, 2) + Math.Pow(template.BackGroundImgHeight, 2)));
//                var p3 = new PointF(p1.X + (float)(Math.Cos(f) * template.BackGroundImgWidth), p1.Y + (float)(Math.Sin(f) * template.BackGroundImgWidth));
//                var p4 = new PointF(p1.X - (float)(Math.Sin(f) * template.BackGroundImgHeight), p1.Y + (float)(Math.Cos(f) * template.BackGroundImgHeight));
//                p3.Y = p4.Y;
//                var Cps = new List<PointF>
//{
            //bufferG.Restore(gs);
        }
    }
//p4,
//p3,p1
    void Draw(Graphics bufferG, Template template)
    {
        if (template == null) return;
        var _Nodes = template.network.Nodes.ViewNodes;
        var _Links = template.network.Links.ViewLinks;
        var _Areas = template.network.Areas;
        var Cpoints = getCurclePoints(64).ToList();
        var r = 1.73f / zoom;
        var rt = r;
//};
//                template.BackGroundPoint1 = p4;
//                template.BackGroundPoint2 = new PointF(p3.X, p1.Y);
        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)
        //{
        //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) };
//                Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet)));
//            }
        Pen penN = new Pen(Color.FromArgb(0, 0, 255), 1 * r);
//            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
//            {
        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);
//        }
//    }
//    void Draw(Graphics bufferG, Template template)
//    {
//        if (template == null) return;
//        var _Nodes = template.network.Nodes.ViewNodes;
//        var _Links = template.network.Links.ViewLinks;
//        var _Areas = template.network.Areas;
//        var Cpoints = getCurclePoints(64)?.ToList();
        //绘制面
        using (Pen pen0 = new Pen(Color.FromArgb(0, 0, 255), 2 * r))
        {
            foreach (var area in _Areas)
            {
//        var r = 1.73f / zoom;
//        var rt = r;
                if (!area.Visible) continue;
                if (!IsFaceVisibleToCamera(area, GetCameraPosition())) continue;
                if (area.Elev < minElve || area.Elev >= maxElve) continue;
//        float minElve = float.MinValue;
//        float maxElve = float.MaxValue;
                var p = new List<PointF>();
                foreach (var node in area.InnerNodes)
                {
                    p.Add(CubeWorldPointToMapPoint(node, template.OffSet));
                }
                if (p.Count < 3) continue;
                pen0.Color = penClosed.Color = area.color;
                Pen pen = pen0;
                if (area.Hovered) pen = penHovered;
                bufferG.FillPolygon(pen.Brush, p.ToArray());
                bufferG.DrawPolygon(pen, p.ToArray());
                //显示area的名称
                var c = new PointF(p.Average(p0 => p0.X), p.Average(p0 => p0.Y));
                var brush = new SolidBrush(Color.White);
//        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);
                var gs = bufferG.Save();
                // 应用矩阵变换以抵消之前的翻转效果
                bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
                Font font = new Font(FontFamily.GenericSansSerif, 10 * 10 * zoom);
//        //绘制面
//        using (Pen pen0 = new Pen(Color.FromArgb(0, 0, 255), 2 * r))
//        {
//            foreach (var area in _Areas)
//            {
                SizeF textSize = bufferG.MeasureString(area.Name, 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 pd = new PointF(textLeft, textTop);
//                if (!area.Visible) continue;
//                if (!IsFaceVisibleToCamera(area, GetCameraPosition())) continue;
//                if (area.Elev < minElve || area.Elev >= maxElve) continue;
                bufferG.DrawString(area.Name, font, brush, pd);
                // 恢复之前保存的绘图状态
                bufferG.Restore(gs);
            }
        }
//                var p = new List<PointF>();
//                foreach (var node in area.InnerNodes)
//                {
//                    p.Add(CubeWorldPointToMapPoint(node, template.OffSet));
//                }
//                if (p.Count < 3) continue;
//                pen0.Color = penClosed.Color = area.color;
//                Pen pen = pen0;
//                if (area.Hovered) pen = penHovered;
//                bufferG.FillPolygon(pen.Brush, p.ToArray());
//                bufferG.DrawPolygon(pen, p.ToArray());
//                //显示area的名称
//                var c = new PointF(p.Average(p0 => p0.X), p.Average(p0 => p0.Y));
//                var brush = new SolidBrush(Color.White);
        // 绘制线
        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 = GraphHelper.getLinkColor(LinkColour, link);
                }
//                var gs = bufferG.Save();
//                // 应用矩阵变换以抵消之前的翻转效果
//                bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
                Pen pen = pen0;
#if DEBUG
#else
if (_Template != null && _Template.mapOption._ShowStatus && link.Status == Hydro.Core.StatusType.CLOSED) pen = penClosed;
#endif
//                Font font = new Font(FontFamily.GenericSansSerif, 10 * 10 * zoom);
                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)
                    {
//                SizeF textSize = bufferG.MeasureString(area.Name, 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 pd = new PointF(textLeft, textTop);
                        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[] {
GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2),
GraphHelper.getRotatePoint(c.X + valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
GraphHelper.getRotatePoint(c.X + valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2),
GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
//                bufferG.DrawString(area.Name, font, brush, pd);
//                // 恢复之前保存的绘图状态
//                bufferG.Restore(gs);
//            }
//        }
};
                        bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
//        // 绘制线
                    }
//        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 = GraphHelper.getLinkColor(LinkColour, link);
//                }
                }
                else if (link is PumpViewModel)
                {
                    if (link.Selected || _ShowValve)
                    {
//                Pen pen = pen0;
//#if DEBUG
//#else
//if (_Template != null && _Template.mapOption._ShowStatus && link.Status == Hydro.Core.StatusType.CLOSED) pen = penClosed;
//#endif
                        var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2);
                        //bufferG.DrawLine(link.Selected ? pen_valveChoosed : pen, p1, p2);
//                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)
//                    {
                        bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
                        // 绘制圆形部分(水泵的泵体)
                        float radius = 5 * r;
                        float diameter = radius * 2;
                        #region 圆形拆分
                        //var p = new PointF[]
                        //{
                        //GraphHelper.getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2),
                        //GraphHelper.getRotatePoint(c.X + radius - radius, c.Y - radius, c, p1, p2),
                        //GraphHelper.getRotatePoint(c.X + radius - radius, c.Y + radius, c, p1, p2),
                        //GraphHelper.getRotatePoint(c.X - radius - radius, c.Y + radius, c, p1, p2),
                        //GraphHelper.getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2),
                        //};
                        List<PointF> p = new List<PointF>();
                        Cpoints.ForEach(cp => p.Add(GraphHelper.getRotatePoint(c.X + cp.X * radius - radius, c.Y + cp.Y * radius, c, p1, p2)));
//                        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[] {
//GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
//GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2),
//GraphHelper.getRotatePoint(c.X + valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2),
//GraphHelper.getRotatePoint(c.X + valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2),
//GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,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, points);
//                    }
                        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 });
//                }
//                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 valveShapeHeight = link.Selected ? radius * 2 : radius;
                        PointF[] points = new PointF[] {
GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y ,c,p1,p2),
GraphHelper.getRotatePoint(c.X + valveShapeHeight , c.Y ,c,p1,p2),
GraphHelper.getRotatePoint(c.X + valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
//                        List<PointF> p = new List<PointF>();
//                        Cpoints.ForEach(cp => p.Add(GraphHelper.getRotatePoint(c.X + cp.X * radius - radius, c.Y + cp.Y * radius, c, p1, p2)));
};
//                        #endregion
                        bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
                    }
//                        //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);
                }
                else if (link is RepeaterViewModel re)
                {
                    if (re.Status == RepeaterViewModel.RepeatStatus.收起 || _IsEditMode)
                    {
//                        bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray());
                        bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
//                        // 绘制连接线
                        var listNode = GraphHelper.Get等分Nodes(p1, p2, Math.Max(re.RepeatTimes, 1));
//                        var valveShapeHeight = link.Selected ? radius * 2 : radius;
//                        PointF[] points = new PointF[] {
//GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
//GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y ,c,p1,p2),
//GraphHelper.getRotatePoint(c.X + valveShapeHeight , c.Y ,c,p1,p2),
//GraphHelper.getRotatePoint(c.X + valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
//GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
                        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.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
//                    }
                            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);
//                }
//                else if (link is RepeaterViewModel re)
//                {
//                    if (re.Status == RepeaterViewModel.RepeatStatus.收起 || _IsEditMode)
//                    {
                            }
                            catch { }
//                        bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
                        }
                        //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;
                    try
                    {
                        bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
                    }
                    catch (Exception)
                    {
//                        var listNode = GraphHelper.Get等分Nodes(p1, p2, Math.Max(re.RepeatTimes, 1));
                    }
                    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 = GraphHelper.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(GraphHelper.getRotatePoint(c.X - activeD * cp.X * radius + activeD * radius, c.Y + cp.Y * radius, c, p1, p2)));
//                        for (int i = 0; i < listNode.Count; i++)
//                        {
                            #endregion
//                            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.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray());
//                            // 保存当前绘图状态
//                            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);
                            var valveShapeHeight = link.Selected ? radius * 2 : radius;
                            PointF[] points = new PointF[] {
GraphHelper.getRotatePoint(c.X -activeD* valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
GraphHelper.getRotatePoint(c.X, c.Y ,c,p1,p2),
GraphHelper.getRotatePoint(c.X - activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2),
GraphHelper.getRotatePoint(c.X + activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2),
GraphHelper.getRotatePoint(c.X + activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
GraphHelper.getRotatePoint(c.X - activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
};
//                            bufferG.DrawString(text, font, link.Selected ? penChoosed.Brush : pen.Brush, p);
//                            // 恢复之前保存的绘图状态
//                            bufferG.Restore(gs);
                            bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
                        }
//                            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 { }
//                        }
//                    }
                    }
                }
//                }
//                else
//                {
            }
        }
//                    if (link.StartNode == null || link.EndNode == null) continue;
//                    try
//                    {
//                        bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 });
//                    }
//                    catch (Exception)
//                    {
//                    }
//                    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 = GraphHelper.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(GraphHelper.getRotatePoint(c.X - activeD * cp.X * radius + activeD * radius, c.Y + cp.Y * radius, c, p1, p2)));
        r = rt;
//                            #endregion
        HashSet<long> dict_point = new HashSet<long>();
        //绘制点
        penChoosed = new Pen(Color.Green, 1f * r);
        Brush brushChoosed = penChoosed.Brush;
        SolidBrush whiteBrush = new SolidBrush(Color.White);
//                            bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray());
        using (Pen pen0 = new Pen(Color.FromArgb(255, 0, 0), 1 * r))
        {
//                            var valveShapeHeight = link.Selected ? radius * 2 : radius;
//                            PointF[] points = new PointF[] {
//GraphHelper.getRotatePoint(c.X -activeD* valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
//GraphHelper.getRotatePoint(c.X, c.Y ,c,p1,p2),
//GraphHelper.getRotatePoint(c.X - activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2),
//GraphHelper.getRotatePoint(c.X + activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2),
//GraphHelper.getRotatePoint(c.X + activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
//GraphHelper.getRotatePoint(c.X - activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2),
//};
            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 = GraphHelper.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 = GraphHelper.getNodeColor(NodeColour, node);
                    brush = pen.Brush;
                    brushChoosed = penChoosed.Brush;
//                            bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points);
//                        }
                }
                if (node.Hovered)
                {
                    pen = penHovered;
                    brush = pen.Brush;
                    pr = pr * 2;
                }
                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)
                {
                    //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, rectangle);
                    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);
//        r = rt;
                    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);
//        HashSet<long> dict_point = new HashSet<long>();
//        //绘制点
//        penChoosed = new Pen(Color.Green, 1f * r);
//        Brush brushChoosed = penChoosed.Brush;
//        SolidBrush whiteBrush = new SolidBrush(Color.White);
                    //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, rectangle);
//        using (Pen pen0 = new Pen(Color.FromArgb(255, 0, 0), 1 * r))
//        {
                }
                else if (node.ID == _EndPoint)
                {
//            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 = GraphHelper.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 = GraphHelper.getNodeColor(NodeColour, node);
//                    brush = pen.Brush;
//                    brushChoosed = penChoosed.Brush;
                    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);
//                }
//                if (node.Hovered)
//                {
//                    pen = penHovered;
//                    brush = pen.Brush;
//                    pr = pr * 2;
//                }
                    //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 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;
                    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);
//                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);
                    //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(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);
                }
                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);
//                    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);
                    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)
                {
//                }
//                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);
                    //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);
//                    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(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);
                    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);
                }
//                }
//                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);
        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
//                    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);
//                }
            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);
//        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
                var ps_20 = GraphHelper.GetUlongByPoint(p, 0.1f);
//            if (node != null && !float.IsNaN(node.EN_PRESSURE))
//            {
                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 = GraphHelper.getNodeColor(NodeColour, node);
                    brush = pen.Brush;
                    brushChoosed = penChoosed.Brush;
//                //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 = GraphHelper.GetUlongByPoint(p, 0.1f);
                }
//                dict_point.Add(ps_20);
//                if (NodeColour != null)
//                {
//                    pen.Color = GraphHelper.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);
//                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;
//                }
                //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);
//                //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(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);
                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 });
            }
        }
    }
    //绘制辅助线
    void DrawH(Graphics bufferG, Template template)
    {
        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 == MapViewEnum.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
            {
//                var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr);
//                bufferG.FillEllipse(whiteBrush, whiteRect);
                using (var pen = new Pen(Color.Black, 1 * r))
                {
                    pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                    if (mapOption.IsOrtho)
                    {
                        var wPos = GetZZWorldPoint(_select_junction1.Position3D, _MousePosition, new Vector3(1, 1, 0));
                        //getPointAndHeight(e, _select_junction1, out p, out z);
                        var mapPos = WorldPointToMapPoint(wPos);
                        bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), mapPos);
                    }
                    else
                    {
                        bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), _MousePosition);
                    }
//                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);
                }
            }
        }
        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)
        {
//            }
//        }
//    }
//    //绘制辅助线
//    void DrawH(Graphics bufferG, Template template)
//    {
//        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 == MapViewEnum.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
//            {
            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 });
            }
        }
//                using (var pen = new Pen(Color.Black, 1 * r))
//                {
//                    pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
//                    if (mapOption.IsOrtho)
//                    {
//                        var wPos = GetZZWorldPoint(_select_junction1.Position3D, _MousePosition, new Vector3(1, 1, 0));
//                        var mapPos = WorldPointToMapPoint(wPos);
//                        if ((!float.IsNaN(mapPos.X)) && (!float.IsNaN(mapPos.Y)))
//                        {
//                            bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), mapPos);
//                        }
        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());
            }
        }
    }
//                    }
//                    else
//                    {
//                        bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), _MousePosition);
//                    }
    #region 基础坐标转换方法
//                }
//            }
//        }
//        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)
//        {
    /// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
//            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 });
//            }
//        }
    /// <param name="screenPos"></param>
//        if (_isMovingObject)
//        {
//            var newP = _MousePosition;
//            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());
//            }
//        }
//    }
    private PointF ScreenToVMap(PointF screenPos, float z = 0)
    {
        var centerX = this.map.Width / 2;
        var centerY = this.map.Height / 2;
        var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X;
        var worldY = (screenPos.Y - centerY) / Zoom.Y + 0;
        return new PointF(worldX, worldY);
    }
//    #region 基础坐标转换方法
//    /// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
//    /// <param name="screenPos"></param>
    /// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
//    private PointF ScreenToVMap(PointF screenPos, float z = 0)
//    {
//        var centerX = this.map.Width / 2;
//        var centerY = this.map.Height / 2;
//        var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X;
//        var worldY = (screenPos.Y - centerY) / Zoom.Y + 0;
//        return new PointF(worldX, worldY);
//    }
    /// <param name="screenPos"></param>
    private PointF ScreenToMap(PointF screenPos, float z = 0)
    {
        var centerX = this.map.Width / 2;
        var centerY = this.map.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;
        return new PointF(worldX, worldY);
    }
//    /// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
//    /// <param name="screenPos"></param>
    /// 世界投影坐标转换为屏幕坐标
//    private PointF ScreenToMap(PointF screenPos, float z = 0)
//    {
    private PointF MapToScreen(PointF mapPos, float z = 0)
    {
//        var centerX = this.map.Width / 2;
//        var centerY = this.map.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;
//        return new PointF(worldX, worldY);
//    }
        var centerX = this.map.Width / 2;
        var centerY = this.map.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 MapC)
    {
//    private PointF MapToScreen(PointF mapPos, float z = 0)
//    {
        PointF center = MapC;
        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 MapC)
    {
        PointF center = MapC;
        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);
    }
//        var centerX = this.map.Width / 2;
//        var centerY = this.map.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;
//        return new PointF(screenX, screenY);
//    }
    private PointF Get俯视角旋转Point(PointF p, float z, PointF MapC)
    {
        PointF center = MapC;
        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 MapC)
    {
        PointF center = MapC;
        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);
    }
//    // 根据旋转角度计算旋转后的坐标
//    private PointF Get平面旋转Point(PointF p, PointF MapC)
//    {
//        PointF center = MapC;
//        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 MapC)
//    {
//        PointF center = MapC;
//        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 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);
//    private PointF Get俯视角旋转Point(PointF p, float z, PointF MapC)
//    {
//        PointF center = MapC;
//        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 MapC)
//    {
//        PointF center = MapC;
//        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)
//    {
        var pointR = Get平面旋转Point(point, MapCenter);
//        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);
//    }
        var pointT = Get俯视角旋转Point(pointR, z + offset.Z, MapCenter);
        //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(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);
    }
    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 PointF CubeWorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null)
    {
        if (junction == null) return new PointF(0, 0);
        var point = junction.Position;
        var z = junction.Elev;
        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, new PointF(0, 0));
        var pointT = Get俯视角旋转Point(pointR, z + offset.Z, new PointF(0, 0));
        return pointT;
    }
    private List<PointF> WorldPointToMapPoint(LinkViewModel pipe, PointF3D offset = null)
    {
        List<PointF> list = new List<PointF>();
//        var pointR = Get平面旋转Point(point, MapCenter);
        PointF p;
        p = WorldPointToMapPoint(pipe.StartNode, offset);
        list.Add(p);
        p = WorldPointToMapPoint(pipe.EndNode, offset);
        list.Add(p);
        return list;
//        var pointT = Get俯视角旋转Point(pointR, z + offset.Z, MapCenter);
//        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 PointF CubeWorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null)
//    {
//        if (junction == null) return new PointF(0, 0);
//        var point = junction.Position;
//        var z = junction.Elev;
//        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, new PointF(0, 0));
//        var pointT = Get俯视角旋转Point(pointR, z + offset.Z, new PointF(0, 0));
//        return pointT;
//    }
//    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;
    /// <param name="position3D">世界坐标</param>
    /// <param name="mousePosition">地图坐标</param>
    /// <param name="vector3">投影向量</param>
//    }
    /// <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
        {
            var p2 = MapPointToWorldPoint(mousePosition, position3D.Z);
            var vector = new Vector2(p2.X - position3D.X, p2.Y - position3D.Y);
            //判断二维向量vector在第几象限,距离哪个轴最近
            var x = vector.X;
            var y = vector.Y;
            var x1 = Math.Abs(x);
            var y1 = Math.Abs(y);
            if (x1 > y1)
            {
                if (x > 0)
                {
                    //第一象限
                    return new PointF3D(position3D.X + Math.Abs(x), position3D.Y, position3D.Z);
                }
                else
                {
                    //第三象限
                    return new PointF3D(position3D.X - Math.Abs(x), position3D.Y, position3D.Z);
                }
            }
            else
            {
                if (y > 0)
                {
                    //第二象限
                    return new PointF3D(position3D.X, position3D.Y + Math.Abs(y), position3D.Z);
                }
                else
                {
                    //第四象限
                    return new PointF3D(position3D.X, position3D.Y - Math.Abs(y), position3D.Z);
                }
            }
        }
    }
//    /// 获取正交投影坐标,返回的是世界坐标
//    /// <param name="position3D">世界坐标</param>
//    /// <param name="mousePosition">地图坐标</param>
//    /// <param name="vector3">投影向量</param>
    /// 获取正交投影坐标,返回的是世界坐标
//    /// <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
//        {
//            var p2 = MapPointToWorldPoint(mousePosition, position3D.Z);
//            var vector = new Vector2(p2.X - position3D.X, p2.Y - position3D.Y);
//            //判断二维向量vector在第几象限,距离哪个轴最近
//            var x = vector.X;
//            var y = vector.Y;
//            var x1 = Math.Abs(x);
//            var y1 = Math.Abs(y);
//            if (x1 > y1)
//            {
//                if (x > 0)
//                {
//                    //第一象限
//                    return new PointF3D(position3D.X + Math.Abs(x), position3D.Y, position3D.Z);
//                }
//                else
//                {
//                    //第三象限
//                    return new PointF3D(position3D.X - Math.Abs(x), position3D.Y, position3D.Z);
//                }
//            }
//            else
//            {
//                if (y > 0)
//                {
//                    //第二象限
//                    return new PointF3D(position3D.X, position3D.Y + Math.Abs(y), position3D.Z);
//                }
//                else
//                {
//                    //第四象限
//                    return new PointF3D(position3D.X, position3D.Y - Math.Abs(y), position3D.Z);
//                }
//            }
//        }
//    }
    /// <param name="position3D">世界坐标</param>
    /// <param name="mousePosition">地图坐标</param>
    /// <param name="vector3">投影向量</param>
    /// <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);
//    /// 获取正交投影坐标,返回的是世界坐标
    }
//    /// <param name="position3D">世界坐标</param>
//    /// <param name="mousePosition">地图坐标</param>
//    /// <param name="vector3">投影向量</param>
    private PointF MapPointToWorldPoint(PointF3D point)
    {
        return MapPointToWorldPoint(new PointF(point.X, point.Y), point.Z);
    }
//    /// <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);
    /// 获取地图投影坐标
//    }
    /// <param name="point"></param>
    /// <param name="z"></param>
//    private PointF MapPointToWorldPoint(PointF3D point)
//    {
//        return MapPointToWorldPoint(new PointF(point.X, point.Y), point.Z);
//    }
    public PointF MapPointToWorldPoint(PointF point, float z = 0)
    {
        var pointT = Get俯视角还原Point(point, z, MapCenter);
        pointT = Get平面还原Point(pointT, MapCenter);
//    /// 获取地图投影坐标
        //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;
//    /// <param name="point"></param>
//    /// <param name="z"></param>
        p = MapPointToWorldPoint(junction.Position, junction.Elev);
        return p;
//    public PointF MapPointToWorldPoint(PointF point, float z = 0)
//    {
//        var pointT = Get俯视角还原Point(point, z, MapCenter);
//        pointT = Get平面还原Point(pointT, MapCenter);
    }
//        //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 计算三维相机
    public PointF3D GetCameraPosition(float distance = 1)
    {
        // 将角度转换为弧度
        float rotationRadians = (float)Rotation * (float)Math.PI / 180;
        float rotationFRadians = (float)RotationF * (float)Math.PI / 180;
        // 计算相机的球坐标系位置
        float x = distance * (float)Math.Sin(rotationFRadians) * (float)Math.Cos(rotationRadians);
        float y = distance * (float)Math.Sin(rotationFRadians) * (float)Math.Sin(rotationRadians);
        float z = distance * (float)Math.Cos(rotationFRadians);
        return new PointF3D(x, y, z);
    }
    public bool IsFaceVisibleToCamera(AreaViewModel area, PointF3D cameraPosition)
    {
//    #endregion
//    #region 计算三维相机
//    public PointF3D GetCameraPosition(float distance = 1)
//    {
//        // 将角度转换为弧度
//        float rotationRadians = (float)Rotation * (float)Math.PI / 180;
//        float rotationFRadians = (float)RotationF * (float)Math.PI / 180;
        //正面是2,右面是1,左面是3,背面是4
        //Rotation为0时,只显示正面,Rotation为90时,只显示右面,Rotation为180时,只显示背面,Rotation为270时,只显示左面
        int delta = 5;
        bool flag = false;
        switch (area.Name)
        {
            case "左":
                //Rotation为0~180时显示
                if (RotationF <= 90 - delta && Rotation >= 0 + delta && Rotation <= 180 - delta)
                    flag = true;
                break;
            case "前":
                //Rotation为0~180时显示
                if (RotationF <= 90 - delta && Rotation >= -90 + delta && Rotation <= 90 - delta)
                    flag = true;
                break;
            case "右":
                //Rotation为0~180时显示
                if (RotationF <= 90 - delta && Rotation >= -180 + delta && Rotation <= 0 - delta)
                    flag = true;
                break;
            case "后":
                //Rotation为0~180时显示
                if (RotationF <= 90 - delta && ((Rotation >= 90 + delta && Rotation <= 180) || (Rotation >= -180 && Rotation <= -90 - delta)))
                    flag = true;
                break;
            case "上":
                if (RotationF >= 0 + delta)
                    flag = true;
                break;
            case "下":
                if (RotationF <= 0 - delta)
                    flag = true;
                break;
        }
        return flag;
//        // 计算相机的球坐标系位置
//        float x = distance * (float)Math.Sin(rotationFRadians) * (float)Math.Cos(rotationRadians);
//        float y = distance * (float)Math.Sin(rotationFRadians) * (float)Math.Sin(rotationRadians);
//        float z = distance * (float)Math.Cos(rotationFRadians);
//        return new PointF3D(x, y, z);
//    }
//    public bool IsFaceVisibleToCamera(AreaViewModel area, PointF3D cameraPosition)
//    {
    }
//        //正面是2,右面是1,左面是3,背面是4
//        //Rotation为0时,只显示正面,Rotation为90时,只显示右面,Rotation为180时,只显示背面,Rotation为270时,只显示左面
//        int delta = 5;
//        bool flag = false;
//        switch (area.Name)
//        {
//            case "左":
//                //Rotation为0~180时显示
//                if (RotationF <= 90 - delta && Rotation >= 0 + delta && Rotation <= 180 - delta)
//                    flag = true;
//                break;
//            case "前":
//                //Rotation为0~180时显示
//                if (RotationF <= 90 - delta && Rotation >= -90 + delta && Rotation <= 90 - delta)
//                    flag = true;
//                break;
//            case "右":
//                //Rotation为0~180时显示
//                if (RotationF <= 90 - delta && Rotation >= -180 + delta && Rotation <= 0 - delta)
//                    flag = true;
//                break;
//            case "后":
//                //Rotation为0~180时显示
//                if (RotationF <= 90 - delta && ((Rotation >= 90 + delta && Rotation <= 180) || (Rotation >= -180 && Rotation <= -90 - delta)))
//                    flag = true;
//                break;
//            case "上":
//                if (RotationF >= 0 + delta)
//                    flag = true;
//                break;
//            case "下":
//                if (RotationF <= 0 - delta)
//                    flag = true;
//                break;
//        }
//        return flag;
    #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);
//    #endregion
        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;
//    #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构成线段的中心点的距离
    }
    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);
//        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);
        // 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);
//        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;
        return distance;
    }
//    }
//    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);
    PointF PMin_Show, PMax_Show;
//        // 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;
    /// <param name="screenPos"></param>
    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;
    }
//    /// 判断是否在屏幕坐标内
//    /// <param name="screenPos"></param>
    /// 判断是否在屏幕坐标内
//    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;
//    }
    /// <param name="screenPos"></param>
    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;
            }
//    /// <param name="screenPos"></param>
        }
//    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)
//            {
        return visible;
    }
    #endregion
//            }
//            else
//            {
//                visible = true;
//                return true;
//            }
}
public partial class MapViewer
{
//        }
    #region 核心属性
    TContainer TC = new TContainer();
//        return visible;
//    }
//    #endregion
//}
    /// 地图选项
    public MapDimensions mapOption
    {
        get { return TC.mapOption; }
        set { TC.mapOption = value; }
    }
//public partial class MapViewer
//{
    /// 地图选项_起始操作时
//    #region 核心属性
//    TContainer TC = new TContainer();
//    /// 地图选项
    private MapDimensions mapOption0 = new MapDimensions();
//    public MapDimensions mapOption
//    {
//        get { return TC.mapOption; }
//        set { TC.mapOption = value; }
//    }
    /// 临时管网层
//    /// 地图选项_起始操作时
//    private MapDimensions mapOption0 = new MapDimensions();
    public Template _newTemplate
    {
        get { return TC.newTemplate; }
        set { TC.newTemplate = value; }
    }
//    /// 临时管网层
//    public Template _newTemplate
//    {
//        get { return TC.newTemplate; }
//        set { TC.newTemplate = value; }
//    }
    public Template _Template
    {
        get { return TC.template; }
        set
        {
            TC.template = value;
            label_file.Text = TC.template?.filePath;
        }
    }
    #endregion
    #region 交互属性
//    public Template _Template
//    {
//        get { return TC.template; }
//        set
//        {
//            TC.template = value;
    /// 悬停对象
//            label_file.Text = TC.template?.filePath;
//        }
//    }
    private List<IBaseViewModel> hoveredObjs = new List<IBaseViewModel>();
//    #endregion
//    #region 交互属性
    /// 选中对象
//    /// 悬停对象
    public List<IBaseViewModel> selectedObjs = new List<IBaseViewModel>();
//    private List<IBaseViewModel> hoveredObjs = 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();
//    public List<IBaseViewModel> selectedObjs = new List<IBaseViewModel>();
    MouseState _mouseState = MouseState.无;
    private NodeViewModel _OperaNode = null;
    public PointF mouseXY = new PointF(0, 0);
    PointF DragStartPos;
    PointF _ClickStartPos;
    PointF RotaStartPos;
    PointF BackGroudPicLeftPos;
    bool _isPanning;
//    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();
    /// 拖拽选择
//    MouseState _mouseState = MouseState.无;
//    private NodeViewModel _OperaNode = null;
//    public PointF mouseXY = new PointF(0, 0);
    bool _isDragging;
    bool _isRotating;
    bool _isPainting;
//    PointF DragStartPos;
//    PointF _ClickStartPos;
//    PointF RotaStartPos;
//    PointF BackGroudPicLeftPos;
//    bool _isPanning;
//    /// 拖拽选择
    PointF mousePosition;
    // control+鼠标中间按下缩放
    bool _isInsertingObject = false;
    bool _isMovingObject = false;
    bool _isPastingObject = false;
    Cursor _lastCursor;
    object _undoOldValue = null;
    private List<PointF> polygonPoints = new List<PointF>();
//    bool _isDragging;
//    bool _isRotating;
//    bool _isPainting;
    private bool _isDrawingPolygon;
    #endregion
    #region 新增管网(辅助)
//    PointF mousePosition;
//    // control+鼠标中间按下缩放
//    bool _isInsertingObject = false;
//    bool _isMovingObject = false;
//    Cursor _lastCursor;
//    object _undoOldValue = null;
//    private List<PointF> polygonPoints = new List<PointF>();
    MapViewNetWork _NewNet
    {
        get
        {
            if (_newTemplate == null) _newTemplate = new Template();
            if (_newTemplate.network == null) _newTemplate.network = new MapViewNetWork();
            return _newTemplate.network;
        }
    }
    #endregion
    #region 显示选项(辅助)
//    private bool _isDrawingPolygon;
//    #endregion
//    #region 新增管网(辅助)
    private string _StartPoint = null;
    private string _EndPoint = null;
    //private bool __isEditMode = true;
//    MapViewNetWork _NewNet
//    {
//        get
//        {
//            if (_newTemplate == null) _newTemplate = new Template();
//            if (_newTemplate.network == null) _newTemplate.network = new MapViewNetWork();
//            return _newTemplate.network;
//        }
//    }
//    #endregion
//    #region 显示选项(辅助)
    public bool _IsEditMode
    {
        get { return this.mapOption?.isEditMode ?? true; }
        set
        {
            toolStripComboBox_浏览模式.Text = value ? "编辑模式" : "浏览模式";
//    private string _EndPoint = null;
            if (this.mapOption != null) this.mapOption.isEditMode = value;
            转换为ToolStripMenuItem.Visible = _IsEditMode;
            toolStripSeparator9.Visible = _IsEditMode;
            删除ToolStripMenuItem.Visible = _IsEditMode;
            删除ToolStripMenuItem1.Visible = _IsEditMode;
//    public bool _IsEditMode
//    {
//        get { return this.mapOption?.isEditMode ?? true; }
//        set
//        {
//            toolStripComboBox_浏览模式.Text = value ? "编辑模式" : "浏览模式";
            复制ToolStripMenuItem.Visible = _IsEditMode;
            复制ToolStripMenuItem1.Visible = _IsEditMode;
            粘贴ToolStripMenuItem.Visible = _IsEditMode;
            粘贴ToolStripMenuItem1.Visible = _IsEditMode;
            设置长度ToolStripMenuItem.Visible = _IsEditMode;
            设为关闭ToolStripMenuItem.Visible = _IsEditMode;
            设为立管点ToolStripMenuItem.Visible = _IsEditMode;
            对齐ToolStripMenuItem.Visible = _IsEditMode;
            对齐ToolStripMenuItem1.Visible = _IsEditMode;
//            if (this.mapOption != null) this.mapOption.isEditMode = value;
//            转换为ToolStripMenuItem.Visible = _IsEditMode;
//            toolStripSeparator9.Visible = _IsEditMode;
//            删除ToolStripMenuItem.Visible = _IsEditMode;
//            删除ToolStripMenuItem1.Visible = _IsEditMode;
            toolStripButton_新建节点.Enabled = _IsEditMode;
            toolStripButton_新建管线.Enabled = _IsEditMode;
            toolStripButton_新建立管.Enabled = _IsEditMode;
            toolStripButton_添加水库.Enabled = _IsEditMode;
            toolStripButton_添加水池.Enabled = _IsEditMode;
            toolStripButton_添加水表.Enabled = _IsEditMode;
            toolStripButton_添加阀门.Enabled = _IsEditMode;
            toolStripButton_重复器.Enabled = _IsEditMode;
//            复制ToolStripMenuItem.Visible = _IsEditMode;
//            复制ToolStripMenuItem1.Visible = _IsEditMode;
//            粘贴ToolStripMenuItem.Visible = _IsEditMode;
//            粘贴ToolStripMenuItem1.Visible = _IsEditMode;
//            设置长度ToolStripMenuItem.Visible = _IsEditMode;
//            设为关闭ToolStripMenuItem.Visible = _IsEditMode;
//            设为立管点ToolStripMenuItem.Visible = _IsEditMode;
//            对齐ToolStripMenuItem.Visible = _IsEditMode;
//            对齐ToolStripMenuItem1.Visible = _IsEditMode;
//            toolStripButton_新建节点.Enabled = _IsEditMode;
//            toolStripButton_新建管线.Enabled = _IsEditMode;
//            toolStripButton_新建立管.Enabled = _IsEditMode;
//            toolStripButton_添加水库.Enabled = _IsEditMode;
//            toolStripButton_添加水池.Enabled = _IsEditMode;
//            toolStripButton_添加水表.Enabled = _IsEditMode;
//            toolStripButton_添加阀门.Enabled = _IsEditMode;
//            toolStripButton_重复器.Enabled = _IsEditMode;
        }
    }
//        }
//    }
    public float Link_multiply
    {
        get
        {
            if (_Template == null || _Template.mapOption == null) return 1.0f;
            return _Template.mapOption.Link_multiply;
        }
        set
        {
            if (_Template == null || _Template.mapOption == null) return; _Template.mapOption.Link_multiply = value;
        }
    }
    public float junction_multiply
    {
        get
        {
            if (_Template == null || _Template.mapOption == null) return 1.0f;
            return _Template.mapOption.junction_multiply;
        }
        set
        {
            if (_Template == null || _Template.mapOption == null) return; _Template.mapOption.junction_multiply = value;
        }
    }
    [DisplayName("显示阀门")]
//    public float Link_multiply
//    {
//        get
//        {
//            if (_Template == null || _Template.mapOption == null) return 1.0f;
//            return _Template.mapOption.Link_multiply;
//        }
//        set
//        {
//            if (_Template == null || _Template.mapOption == null) return; _Template.mapOption.Link_multiply = value;
//        }
//    }
    public bool _ShowValve
    {
        get
        {
            if (_Template == null || _Template.mapOption == null) return true;
            return _Template.mapOption._ShowValve;
        }
        set
        {
            if (_Template == null || _Template.mapOption == null) return; _Template.mapOption._ShowValve = value;
        }
    }
    [DisplayName("显示节点")]
    public bool _ShowJunction
    {
        get
        {
            if (_Template == null || _Template.mapOption == null) return true;
            return _Template.mapOption._ShowJunction;
        }
        set
        {
//    public float junction_multiply
//    {
//        get
//        {
//            if (_Template == null || _Template.mapOption == null) return 1.0f;
//            return _Template.mapOption.junction_multiply;
//        }
//        set
//        {
//            if (_Template == null || _Template.mapOption == null) return; _Template.mapOption.junction_multiply = value;
//        }
//    }
//    [DisplayName("显示阀门")]
            if (_Template == null || _Template.mapOption == null) return; _Template.mapOption._ShowJunction = value;
        }
    }
    string _filePath
    {
        get
        {
            if (string.IsNullOrEmpty(_Template?.filePath))
                return null;
            string path = _Template.filePath.TrimStart('\\');
            return
            Path.Combine(Directory.GetCurrentDirectory(), path);
        }
        //set
        //{
//    public bool _ShowValve
//    {
//        get
//        {
//            if (_Template == null || _Template.mapOption == null) return true;
//            return _Template.mapOption._ShowValve;
//        }
//        set
//        {
//            if (_Template == null || _Template.mapOption == null) return; _Template.mapOption._ShowValve = value;
//        }
//    }
//    [DisplayName("显示节点")]
//    public bool _ShowJunction
//    {
//        get
//        {
//            if (_Template == null || _Template.mapOption == null) return true;
//            return _Template.mapOption._ShowJunction;
//        }
//        set
//        {
        //_Template.路径 = value;
        //}
    }
    private MapViewNetWork _Network
    {
        get
        {
            return _Template?.network;
        }
    }
    #endregion
    #region 管网属性(辅助)
//            if (_Template == null || _Template.mapOption == null) return; _Template.mapOption._ShowJunction = value;
//        }
//    }
//    string _filePath
//    {
//        get
//        {
//            if (string.IsNullOrEmpty(_Template?.filePath))
//                return null;
//            string path = _Template.filePath.TrimStart('\\');
//            return
//            Path.Combine(Directory.GetCurrentDirectory(), path);
//        }
//    }
//    private MapViewNetWork _Network
//    {
//        get
//        {
//            return _Template?.network;
//        }
//    }
//    #endregion
//    #region 管网属性(辅助)
    public List<NodeCalcModel> _Nodes
    {
        get { return _Network?.Nodes ?? new List<NodeCalcModel>(); }
//    public List<NodeCalcModel> _Nodes
//    {
//        get { return _Network?.Nodes ?? new List<NodeCalcModel>(); }
    }
//    }
    public List<LinkCalcModel> _Links
    {
        get { return _Network?.Links ?? new List<LinkCalcModel>(); }
//    public List<LinkCalcModel> _Links
//    {
//        get { return _Network?.Links ?? new List<LinkCalcModel>(); }
    }
//    }
    private List<Area> _areas = new List<Area>();
//    private List<Area> _areas = new List<Area>();
    public List<Area> _Areas
    {
        get { return _areas; }
//    public List<Area> _Areas
//    {
//        get { return _areas; }
    }
    #endregion
    #region 视角设置(辅助)
//    }
//    #endregion
//    #region 视角设置(辅助)
    private const float MinZoom = 0.1f;
    private const float MaxZoom = 1000.0f;
//    private const float MinZoom = 0.1f;
//    private const float MaxZoom = 1000.0f;
    [DisplayName("缩放系数")]
    public float zoom
    {
        get
        {
            return mapOption.zoom;
        }
        set
        {
            label_zoom.Text = $"Zoom:{zoom.ToString("0.000")}";
            mapOption.zoom = value;
        }
    }
    [DisplayName("旋转角度")]
    public double Rotation
    {
        get
        {
            return mapOption.rotation;
        }
        set
        {
            toolStripStatusLabel_rotation.Text = $"Rotation:({Rotation.ToString("0")},{RotationF.ToString("0")})";
            //将旋转角度转换为-180~180
            value = value % 360;
            if (value > 180)
                value -= 360;
            else if (value < -180)
                value += 360;
            mapOption.rotation = value;
        }
    }
//    [DisplayName("缩放系数")]
//    public float zoom
//    {
//        get
//        {
//            return mapOption.zoom;
//        }
//        set
//        {
//            label_zoom.Text = $"Zoom:{zoom.ToString("0.000")}";
//            mapOption.zoom = value;
//        }
//    }
//    [DisplayName("旋转角度")]
//    public double Rotation
//    {
//        get
//        {
//            return mapOption.rotation;
//        }
//        set
//        {
//            toolStripStatusLabel_rotation.Text = $"Rotation:({Rotation.ToString("0")},{RotationF.ToString("0")})";
//            //将旋转角度转换为-180~180
//            value = value % 360;
//            if (value > 180)
//                value -= 360;
//            else if (value < -180)
//                value += 360;
//            mapOption.rotation = value;
//        }
//    }
    private double Rotation0 = 0;
//    private double Rotation0 = 0;
    public PointF MapCenter
    {
        get
        {
            return mapOption.Center;
        }
        set
        {
            label_center.Text = $"center:({MapCenter.X.ToString("0.00")} ,{MapCenter.Y.ToString("0.00")})";
            mapOption.Center = value;
        }
    }
    private PointF MapCenter0;
    private bool is3Dview = false;
    double 俯视角度_start = 90;
//    public PointF MapCenter
//    {
//        get
//        {
//            return mapOption.Center;
//        }
//        set
//        {
//            label_center.Text = $"center:({MapCenter.X.ToString("0.00")} ,{MapCenter.Y.ToString("0.00")})";
//            mapOption.Center = value;
//        }
//    }
//    private PointF MapCenter0;
//    private bool is3Dview = false;
//    double 俯视角度_start = 90;
    public bool Lock2DView
    {
        get
        {
            return mapOption.Lock2DView;
        }
        set
        {
            mapOption.Lock2DView = value;
        }
    }
//    public bool Lock2DView
//    {
//        get
//        {
//            return mapOption.Lock2DView;
//        }
//        set
//        {
//            mapOption.Lock2DView = value;
//        }
//    }
    /// 俯视线与底面的夹角,投影用sin
//    /// 俯视线与底面的夹角,投影用sin
    [DisplayName("俯视角度")]
    public double RotationF
    {
        get
        {
            return mapOption.rotationF;
        }
        set
        {
            mapOption.rotationF = value;
        }
    }
//    [DisplayName("俯视角度")]
//    public double RotationF
//    {
//        get
//        {
//            return mapOption.rotationF;
//        }
//        set
//        {
//            mapOption.rotationF = value;
//        }
//    }
    public double 俯视弧度
    {
        get
        {
            return RotationF / 180 * Math.PI;
        }
    }
//    public double 俯视弧度
//    {
//        get
//        {
//            return RotationF / 180 * Math.PI;
//        }
//    }
    public PointF Zoom
    {
        get
        {
            return new PointF(zoom, -zoom);
        }
    }
//    public PointF Zoom
//    {
//        get
//        {
//            return new PointF(zoom, -zoom);
//        }
//    }
    private PointF Z(float z)
    {
        return new PointF(0, 0);
    }
    #endregion
    #region 颜色分级(辅助)
    public Colour NodeColour
    {
        set
        {
            var type = value.Type;
            value.isChoosed = true;
            _Template?.Colours?.RemoveAll(cl => cl.Type == type);
            _Template.Colours.Add(value);
            mapOption.ColourNode = type;
        }
        private get
        {
            return _Template?.Colours?.FirstOrDefault(cl => cl.isChoosed && cl.Type == mapOption.ColourNode);
        }
    }
    public Colour LinkColour
    {
        set
        {
            var type = value.Type;
            value.isChoosed = true;
            _Template?.Colours?.RemoveAll(cl => cl.Type == type);
            _Template.Colours.Add(value);
            mapOption.ColourLink = type;
        }
        private get
        {
            return _Template?.Colours?.FirstOrDefault(cl => cl.isChoosed && cl.Type == mapOption.ColourLink);
        }
    }
//    private PointF Z(float z)
//    {
//        return new PointF(0, 0);
//    }
//    #endregion
//    #region 颜色分级(辅助)
//    public Colour NodeColour
//    {
//        set
//        {
//            var type = value.Type;
//            value.isChoosed = true;
//            _Template?.Colours?.RemoveAll(cl => cl.Type == type);
//            _Template.Colours.Add(value);
//            mapOption.ColourNode = type;
//        }
//        private get
//        {
//            return _Template?.Colours?.FirstOrDefault(cl => cl.isChoosed && cl.Type == mapOption.ColourNode);
//        }
//    }
//    public Colour LinkColour
//    {
//        set
//        {
//            var type = value.Type;
//            value.isChoosed = true;
//            _Template?.Colours?.RemoveAll(cl => cl.Type == type);
//            _Template.Colours.Add(value);
//            mapOption.ColourLink = type;
//        }
//        private get
//        {
//            return _Template?.Colours?.FirstOrDefault(cl => cl.isChoosed && cl.Type == mapOption.ColourLink);
//        }
//    }
    //private bool __isOrtho = true;
//    //private bool __isOrtho = true;
    #endregion
    #region 正交模式
    private bool _isOrtho
    {
        get
        {
            return mapOption.IsOrtho;
        }
        set
        {
            mapOption.IsOrtho = value;
            if (mapOption.IsOrtho)
            {
                label_ZZ.Text = "正交模式:开";
            }
            else
            {
                label_ZZ.Text = "正交模式:关";
            }
        }
    }
    #endregion
    #region 事件
    //按帧数判断是否重绘,减少计算量(每帧最多重绘一次)
    bool _timerDraw = false;
    //按帧数判断鼠标悬停对象,减少计算量(每帧最多判断一次)
    bool _mouseHoverCheckFlag = false;
    #endregion
}
//    #endregion
//    #region 正交模式
//    private bool _isOrtho
//    {
//        get
//        {
//            return mapOption.IsOrtho;
//        }
//        set
//        {
//            mapOption.IsOrtho = value;
//            if (mapOption.IsOrtho)
//            {
//                label_ZZ.Text = "正交模式:开";
//            }
//            else
//            {
//                label_ZZ.Text = "正交模式:关";
//            }
//        }
//    }
//    #endregion
//    #region 事件
//    //按帧数判断是否重绘,减少计算量(每帧最多重绘一次)
//    bool _timerDraw = false;
//    //按帧数判断鼠标悬停对象,减少计算量(每帧最多判断一次)
//    bool _mouseHoverCheckFlag = false;
//    #endregion
//}
/// <summary>
@@ -1783,17 +1695,19 @@
public delegate void MouseDelegate(MouseEventArgs e);
public class TContainer
{
//public class TContainer
//{
    public MapDimensions mapOption = new MapDimensions();
//    public MapDimensions mapOption = new MapDimensions();
    public Template newTemplate = null;
//    public Template newTemplate = null;
    public Template template = null;
//    public Template template = null;
}
//}
[Serializable]
public class Area : BaseModel, IBaseViewModel
{
    public List<PointF> Points { get; set; }
@@ -1930,9 +1844,7 @@
    string ID { get; set; }
    bool Selected { get; set; }
@@ -1954,31 +1866,13 @@
    [DisplayName("X坐标")]
    [Browsable(true)]
    float X { get; set; }
    //{
    //get
    //{
    //return Position.X;
    //}
    //set
    //{
    //Position = new PointF(value, Position.Y);
    //}
    //}
    [Description("Y坐标")]
    [DisplayName("Y坐标")]
    [Browsable(true)]
    float Y { get; set; }
    //{
    //get
    //{
    //return Position.Y;
    //}
    //set
    //{
    //Position = new PointF(Position.X, value);
    //}
    //}
    [Description("标高")]
@@ -1989,19 +1883,12 @@
    [Description("对象的等级")]
    [DisplayName("级别")]
    //[Editor(typeof(MyPropertyEditor), typeof(UITypeEditor))]
    int Level { get; set; } //= 0;
    int Level { get; set; }
    [Description("对象的等级")]
    [DisplayName("是否显示")]
    bool Visible { get; set; } //= true;
    //
    //[Description("标签集合")]
    //[DisplayName("标签")]
    //public string Tags { get; set; } = null;
    bool Visible { get; set; }
@@ -2012,21 +1899,20 @@
    [Description("ID类型")]
    [DisplayName("ID类型")]
    string IDType { get; }// => Type.ToString()+"\t"+ ID;
    string IDType { get; }
    MapObjectType GetTypeString();
    TagList Tags { get; set; }
    //string TagsString { get; set; }
    bool isNode();
}
[Serializable]
public class TagList : List<string>
{
{
    public override string ToString()
    {
@@ -2036,15 +1922,7 @@
            return string.Join(",", this);
    }
    //public TagList(string value):base(value.Split(','))
    //{
    //if (string.IsNullOrEmpty(value) || value == "null")
    //{
    //base.Clear();
    //return;
    //}
    //}
    public TagList()
    {
    }
@@ -2193,7 +2071,7 @@
    }
}
[Serializable]
public class LinkViewModel : LinkCalcModel, IBaseViewModel
{
    #region 构造函数
@@ -2454,7 +2332,7 @@
    #endregion
}
[Serializable]
public class NodeViewModel : NodeCalcModel, IBaseViewModel
{
    #region 构造函数
@@ -2586,7 +2464,7 @@
    {
        get
        {
            return base.Links.Select(oo => oo as LinkViewModel).ToList();
            return base.Links.Select(oo => oo as LinkViewModel)?.ToList();
        }
    }
@@ -2690,10 +2568,10 @@
}
[Serializable]
public static class Copy
{
    public static T DeepCopy<T>(this T obj)
    {
        dynamic retval;
@@ -2711,12 +2589,10 @@
    }
}
[Serializable]
public class Dataset
{
    //设置Dataset的default值
    public static List<string> listString = new List<string>() { "流量扬程曲线", "流量功率曲线", "流量效率曲线" };
    public Dataset(string name, PumpViewModel pump, int Degree = 2)
@@ -2735,10 +2611,8 @@
        }
        return txt.ToString();
    }
    //public Dataset()
    //{
    //}
    public Color Color
    {
        get
@@ -2781,9 +2655,9 @@
                switch (Name)
                {
                    case "流量扬程曲线":
                        return _data.Select(p => { p.X *= eg; p.Y *= eg * eg; return p; }).ToList();
                        return _data.Select(p => { p.X *= eg; p.Y *= eg * eg; return p; })?.ToList();
                    case "流量功率曲线":
                        return _data.Select(p => { p.X *= eg; p.Y *= eg * eg * eg; return p; }).ToList();
                        return _data.Select(p => { p.X *= eg; p.Y *= eg * eg * eg; return p; })?.ToList();
                    case "流量效率曲线":
                        var c1 = pump.Datasets["流量扬程曲线"];
                        var c2 = pump.Datasets["流量功率曲线"];
@@ -2899,7 +2773,7 @@
    double Solve(double y)
    {
        List<PointF> points = FittedCurve.ToList();
        List<PointF> points = FittedCurve?.ToList();
        PointF prevPoint = PointF.Empty;
        PointF nextPoint = PointF.Empty;
@@ -2922,7 +2796,7 @@
        if (prevPoint.IsEmpty)
        {
            return points[points.Count - 1].X; //throw new Exception("No valid interpolation range found.");
            return points[points.Count - 1].X;
        }
        else if (nextPoint.IsEmpty)
        {
@@ -3066,6 +2940,8 @@
}
[Serializable]
public class Default
{
    static string _filePath = Path.Combine(Directory.GetCurrentDirectory(), @"default.ini");
@@ -3135,14 +3011,13 @@
                // 设置新的文件属性
                File.SetAttributes(filePath, attributes);
            }
        }
    }
}
[Serializable]
public static class GlobalExtension
{
    public static Type GetObjType(this MapObjectType type)
@@ -3168,6 +3043,8 @@
}
[Serializable]
public class MapObjectRecord
{
    public IBaseViewModel mapObject { get; set; }
@@ -3177,6 +3054,7 @@
}
[Serializable]
public class MapDimensions
{
@@ -3299,6 +3177,7 @@
    }
}
[Serializable]
public static class MapObjectExtensions
{
    private static readonly Stack<UndoRedoCommand<object>> _undoStack = new Stack<UndoRedoCommand<object>>();
@@ -3463,7 +3342,7 @@
    }
}
[Serializable]
public class Colour
{
    public string Name { get; set; }
@@ -3549,6 +3428,7 @@
    }
}
public enum ColourType
{
    无 = 0,
@@ -3572,17 +3452,7 @@
}
public class EquivalentTemplateModel
{
    public string Name { get; set; }
    public long ID { get; set; }
    public List<WaterEquivalentModel> waterEquivalents { get; set; }
}
[Serializable]
public class WaterEquivalentModel
{
@@ -3644,22 +3514,26 @@
        泵站
    }
    public enum TemplateType
    {
        全部,
        小区模板,
        单元模板,
        单元分区模板,
        楼层模板,
        其他
    }
    //public enum PBS.eModelTemplateType
    //{
    //    全部,
    //    楼层模板,
    //    小区模板,
    //    单元模板,
    //    单元分区模板,
    //    其他
    //}
}
[Serializable]
public class AreaViewModel : NodeViewModel, IBaseViewModel
{
    public List<NodeViewModel> InnerNodes = new List<NodeViewModel>();
    public Color color { get; set; }
}
public class Factory
{
@@ -3676,7 +3550,7 @@
    }
}
[Serializable]
public class JunctionViewModel : NodeViewModel
{
    public override string ToString()
@@ -3687,7 +3561,7 @@
    }
}
[Serializable]
public class MeterViewModel : NodeViewModel
{
    public string DlTemplateID { get; set; }
@@ -3696,10 +3570,9 @@
        if (string.IsNullOrEmpty(PatternID)) PatternID = "";
        return $"{ID}\t{Elev}\t{Demand}\t{PatternID}\t;\t";
    }
}
[Serializable]
public class NozzleViewModel : NodeViewModel
{
@@ -3719,13 +3592,18 @@
    }
}
[Serializable]
public class PipeViewModel : LinkViewModel
{
    public override string ToString()
    {
        if (Roughness == 0) Roughness = 110;
        string statusString = Status == StatusType.CLOSED ? "CLOSED" : "";
        return $"{ID}\t{Node1}\t{Node2}\t{Length}\t{Diameter}\t{Roughness}\t{MinorLoss}\t{statusString}\t;\t";
    }
}
[Serializable]
public class PointF3D
{
    public float X { get; set; }
@@ -3765,6 +3643,7 @@
    }
}
[Serializable]
public class Cube
{
    public Dictionary<int, List<PointF3D>> FacesVertices { get; private set; }
@@ -3805,7 +3684,7 @@
    }
}
[Serializable]
public class PumpNodeViewModel : NodeViewModel
{
    public PumpNodeViewModel()
@@ -3842,7 +3721,7 @@
}
[Serializable]
public class PumpViewModel : LinkViewModel
{
    public static List<string> CurveStrings = new List<string> { "流量扬程曲线", "流量功率曲线", "流量效率曲线" };
@@ -4109,6 +3988,7 @@
    }
}
[Serializable]
public class RepeaterViewModel : LinkViewModel
{
@@ -4205,7 +4085,7 @@
    [Browsable(true)]
    public new RepeatStatus Status { get; set; }
    public bool Load(int MaxLevel, dict<string, dynamic> param, Dictionary<TemplateType, bool> viewModel, bool viewMode = true)
    public bool Load(int MaxLevel, dict<string, dynamic> param, Dictionary<PBS.eModelTemplateType, bool> viewModel, bool viewMode = true)
    {
        if (template == null)
@@ -4247,7 +4127,7 @@
        }
        if (param.Contains("层数") && param["层数"] > 0 && template.Type == TemplateType.楼层模板)
        if (param.Contains("层数") && param["层数"] > 0 && template.Type == PBS.eModelTemplateType.Floor)
        {
            RepeatTimes = (int)param["层数"];
        }
@@ -4266,7 +4146,7 @@
            net.Name = NetworkPreName + (index == 0 ? "" : index.ToString("00"));
            net.StartPoint = net.GetNode(template.Node1)[0];
            net.EndPoint = net.GetNode(template.Node2)[0];
            if (template.Type == TemplateType.楼层模板)
            if (template.Type == PBS.eModelTemplateType.Floor)
                ChangeNetbyParam(net, param);
            if (i == 0) StartNode_inner = net.StartPoint;
            EndNode_inner = net.EndPoint;
@@ -4300,7 +4180,7 @@
                n.Y = (n.Y - net.StartPoint.Y) * k + net.StartPoint.Y;
            });
        }
        if (param.Contains("户数") && template.Type == TemplateType.楼层模板)
        if (param.Contains("户数") && template.Type == PBS.eModelTemplateType.Floor)
        {
            var MaxLevel = (int)param["户数"];
            net.MapObjects.ForEach(o =>
@@ -4378,7 +4258,7 @@
    }
}
[Serializable]
public class ReservoirViewModel : NodeViewModel
{
    [Category("计算参数")]
@@ -4397,7 +4277,7 @@
    }
}
[Serializable]
public class TankViewModel : NodeViewModel
{
    [Category("计算参数")]
@@ -4469,7 +4349,7 @@
    }
}
[Serializable]
public class ValveNodeViewModel : NodeViewModel
{
    public string Node1 { get; set; }
@@ -4508,7 +4388,7 @@
    public string Setting { get; set; } = "GPVDefault";
}
[Serializable]
public class ValveViewModel : LinkViewModel
{
@@ -4551,7 +4431,7 @@
}
[Serializable]
public class TRegion
{
    public string Name { get; set; } = "新分区";
@@ -4566,7 +4446,7 @@
}
[Serializable]
public class Floor
{
    public int FloorIndex = 1;
@@ -4587,27 +4467,26 @@
        this.FloorIndex = other.FloorIndex;
        this.BackgroundImg = other.BackgroundImg;
        this.Elev = other.Elev;
        this.MapView = (other.MapView != null) ? other.MapView.DeepCopyByBin<MapDimensions>() : null;
        this.MapView = (other.MapView != null) ? other.MapView.MapTo<MapDimensions, MapDimensions>() : null;
    }
    public Floor(int floorIndex, string tempID, float floorElevation, MapDimensions otherInfo)
    public Floor(int floorIndex, Template temp, float floorElevation, MapDimensions otherInfo)
    {
        FloorIndex = floorIndex;
        TemplateID = tempID;
        template = temp;
        Elev = floorElevation;
        MapView = otherInfo;
    }
    public string TemplateID { get; set; } = null;
    public Template template { get { return TemplateList.GetTemplate(TemplateID); } }
    public Template template { get; set; }
}
[Serializable]
public class Template
{
    private string _ID;
@@ -4711,9 +4590,7 @@
    public string ImportExcelPath { get; set; }
    public int ImportExcelIndex { get; set; }
    [Category("计算参数")]
@@ -4721,9 +4598,8 @@
    public int MaxLevel { get; set; } = 99;
    [Browsable(true)]
    public TemplateType Type { get; set; }
    public PBS.eModelTemplateType Type { get; set; }
    public Template()
@@ -4734,7 +4610,7 @@
        filePath = null;
    }
    public Template(string ID, string name, string address, TemplateType type)
    public Template(string ID, string name, string address, PBS.eModelTemplateType type)
    {
        if (ID == null)
            this.ID = new Guid().ToString();
@@ -4949,10 +4825,10 @@
        {
            instance = new TemplateList();
            // 添加测试数据
            AddTemp(new Template(null, "小区模板", @"template\小区模板\", TemplateType.小区模板));
            AddTemp(new Template(null, "分区模板", @"template\单元分区模板\", TemplateType.单元分区模板));
            AddTemp(new Template(null, "单元模板", @"template\单元模板\", TemplateType.单元模板));
            AddTemp(new Template(null, "楼层1", @"template\楼层模板\楼层1.inp", TemplateType.楼层模板));
            AddTemp(new Template(null, "小区模板", @"template\自定义模板\", PBS.eModelTemplateType.Custom));
            AddTemp(new Template(null, "分区模板", @"template\地基模板\", PBS.eModelTemplateType.Foundation));
            AddTemp(new Template(null, "单元模板", @"template\单元模板\", PBS.eModelTemplateType.Unit));
            AddTemp(new Template(null, "楼层1", @"template\楼层模板\楼层1.inp", PBS.eModelTemplateType.Floor));
        }
        Inited = true;
    }
@@ -5010,6 +4886,7 @@
}
[Serializable]
public class WaterEquivalent
{
    public WaterEquivalent() { }
@@ -5077,7 +4954,7 @@
}
[Serializable]
public class WaterEquivalentCollection : List<WaterEquivalent>
{
    public WaterEquivalentCollection() { }
@@ -5090,6 +4967,7 @@
    }
}
[Serializable]
public class WaterEquivalentTemplate
{
    public WaterEquivalentTemplate() { }
@@ -5107,6 +4985,7 @@
    public WaterEquivalentCollection WaterEquivalentCollection { get; set; }
}
[Serializable]
public class WaterEquivalentSettings
{
@@ -5120,83 +4999,84 @@
}
[Serializable]
public class NetWork //: INetWork
{
    public NetWork()
    {
    }
    //public List<JunctionModel> Junctions
    //{
    //    get
    //    {
    //        var js = Nodes.Where(d => d is JunctionModel);
    //        return js?.Select(d => d as JunctionModel)?.ToList();
    //    }
    public List<JunctionModel> Junctions
    {
        get
        {
            var js = Nodes.Where(d => d is JunctionModel);
            return js?.Select(d => d as JunctionModel).ToList();
        }
    //}
    //public List<TankModel> Tanks
    //{
    //    get
    //    {
    //        var js = Nodes.Where(d => d is TankModel);
    //        return js?.Select(d => d as TankModel)?.ToList();
    //    }
    //}
    }
    public List<TankModel> Tanks
    {
        get
        {
            var js = Nodes.Where(d => d is TankModel);
            return js?.Select(d => d as TankModel).ToList();
        }
    }
    //public List<PipeModel> Pipes
    //{
    //    get
    //    {
    //        var js = Links.Where(d => d is PipeModel);
    //        return js?.Select(d => d as PipeModel)?.ToList();
    //    }
    //}
    public List<PipeModel> Pipes
    {
        get
        {
            var js = Links.Where(d => d is PipeModel);
            return js?.Select(d => d as PipeModel).ToList();
        }
    }
    //public List<PumpModel> Pumps
    //{
    //    get
    //    {
    //        var js = Links.Where(d => d is PumpModel);
    //        return js?.Select(d => d as PumpModel)?.ToList();
    //    }
    //}
    public List<PumpModel> Pumps
    {
        get
        {
            var js = Links.Where(d => d is PumpModel);
            return js?.Select(d => d as PumpModel).ToList();
        }
    }
    //public List<ValveModel> Valves
    //{
    //    get
    //    {
    //        var js = Links.Where(d => d is ValveModel);
    //        return js?.Select(d => d as ValveModel)?.ToList();
    //    }
    //}
    public List<ValveModel> Valves
    {
        get
        {
            var js = Links.Where(d => d is ValveModel);
            return js?.Select(d => d as ValveModel).ToList();
        }
    }
    //public List<ReservoisModel> Reservos
    //{
    //    get
    //    {
    //        var js = Nodes.Where(d => d is ReservoisModel);
    //        return js?.Select(d => d as ReservoisModel)?.ToList();
    //    }
    //}
    public List<ReservoisModel> Reservos
    {
        get
        {
            var js = Nodes.Where(d => d is ReservoisModel);
            return js?.Select(d => d as ReservoisModel).ToList();
        }
    }
    //public List<MeterModel> Meters
    //{
    //    get
    //    {
    //        var js = Nodes.Where(d => d is MeterModel);
    //        return js?.Select(d => d as MeterModel)?.ToList();
    //    }
    //}
    public List<MeterModel> Meters
    {
        get
        {
            var js = Nodes.Where(d => d is MeterModel);
            return js?.Select(d => d as MeterModel).ToList();
        }
    }
    public List<NozzleModel> Nozzles
    {
        get
        {
            var js = Nodes.Where(d => d is NozzleModel);
            return js?.Select(d => d as NozzleModel).ToList();
        }
    }
    //public List<NozzleModel> Nozzles
    //{
    //    get
    //    {
    //        var js = Nodes.Where(d => d is NozzleModel);
    //        return js?.Select(d => d as NozzleModel)?.ToList();
    //    }
    //}
    public virtual void AddJunction(JunctionModel junction)
    {
@@ -5581,7 +5461,7 @@
}
[Serializable]
public partial class MapViewNetWork : NetWork
{
    bool use_old = false;
@@ -5646,7 +5526,7 @@
    {
        get
        {
            return Nodes.FindAll(n => n is JunctionViewModel).Select(n => n as JunctionViewModel).ToList();
            return Nodes.FindAll(n => n is JunctionViewModel).Select(n => n as JunctionViewModel)?.ToList();
        }
        set
        {
@@ -5661,7 +5541,7 @@
    {
        get
        {
            return Nodes.FindAll(n => n is ReservoirViewModel).Select(n => n as ReservoirViewModel).ToList();
            return Nodes.FindAll(n => n is ReservoirViewModel).Select(n => n as ReservoirViewModel)?.ToList();
        }
        set
        {
@@ -5675,7 +5555,7 @@
    {
        get
        {
            return Nodes.FindAll(n => n is TankViewModel).Select(n => n as TankViewModel).ToList();
            return Nodes.FindAll(n => n is TankViewModel).Select(n => n as TankViewModel)?.ToList();
        }
        set
        {
@@ -5689,7 +5569,7 @@
    {
        get
        {
            return Nodes.FindAll(n => n is MeterViewModel).Select(n => n as MeterViewModel).ToList();
            return Nodes.FindAll(n => n is MeterViewModel).Select(n => n as MeterViewModel)?.ToList();
        }
        set
@@ -5704,7 +5584,7 @@
    {
        get
        {
            return Nodes.FindAll(n => n is NozzleViewModel).Select(n => n as NozzleViewModel).ToList();
            return Nodes.FindAll(n => n is NozzleViewModel).Select(n => n as NozzleViewModel)?.ToList();
        }
        set
@@ -5720,7 +5600,7 @@
    {
        get
        {
            return Links.FindAll(n => n is PipeViewModel).Select(n => n as PipeViewModel).ToList();
            return Links.FindAll(n => n is PipeViewModel).Select(n => n as PipeViewModel)?.ToList();
        }
        set
        {
@@ -5734,7 +5614,7 @@
    {
        get
        {
            return Links.FindAll(n => n is ValveViewModel).Select(n => n as ValveViewModel).ToList();
            return Links.FindAll(n => n is ValveViewModel).Select(n => n as ValveViewModel)?.ToList();
        }
        set
        {
@@ -5748,7 +5628,7 @@
    {
        get
        {
            return Nodes.FindAll(n => n is ValveNodeViewModel).Select(n => n as ValveNodeViewModel).ToList();
            return Nodes.FindAll(n => n is ValveNodeViewModel).Select(n => n as ValveNodeViewModel)?.ToList();
        }
        set
        {
@@ -5763,7 +5643,7 @@
    {
        get
        {
            return Links.FindAll(n => n is RepeaterViewModel).Select(n => n as RepeaterViewModel).ToList();
            return Links.FindAll(n => n is RepeaterViewModel).Select(n => n as RepeaterViewModel)?.ToList();
        }
        set
        {
@@ -5777,7 +5657,7 @@
    {
        get
        {
            return Links.FindAll(n => n is PumpViewModel).Select(n => n as PumpViewModel).ToList();
            return Links.FindAll(n => n is PumpViewModel).Select(n => n as PumpViewModel)?.ToList();
        }
        set
        {
@@ -5791,7 +5671,7 @@
    {
        get
        {
            return Nodes.FindAll(n => n is PumpNodeViewModel).Select(n => n as PumpNodeViewModel).ToList();
            return Nodes.FindAll(n => n is PumpNodeViewModel).Select(n => n as PumpNodeViewModel)?.ToList();
        }
        set
        {
@@ -6223,7 +6103,7 @@
            List<BaseModel> objects = new List<BaseModel>();
            objects.AddRange(Nodes);
            objects.AddRange(Links);
            return objects.Select(o => (IBaseViewModel)o).ToList();
            return objects.Select(o => (IBaseViewModel)o)?.ToList();
        }
    }
    public void Rename()
@@ -6239,7 +6119,7 @@
        Nodes.AddRange(repeater.netList.Nodes);
        Links.AddRange(repeater.netList.Links);
    }
    public void LoadRepeaters(int MaxLevel, dict<string, dynamic> param, Dictionary<TemplateType, bool> viewModel, bool ViewMode = true)
    public void LoadRepeaters(int MaxLevel, dict<string, dynamic> param, Dictionary<PBS.eModelTemplateType, bool> viewModel, bool ViewMode = true)
    {
@@ -6315,7 +6195,7 @@
    public List<NodeViewModel> GetNode(string node)
    {
        return Nodes.FindAll(n => n.ID == node).Select(n => (NodeViewModel)n).ToList();
        return Nodes.FindAll(n => n.ID == node).Select(n => (NodeViewModel)n)?.ToList();
    }
@@ -6326,9 +6206,9 @@
        Dictionary<string, List<string>> result_dict = new Dictionary<string, List<string>>();
        StringBuilder result_sb = new StringBuilder();
        //to-do
        var objs = Links.Select(o => o as LinkViewModel).ToList();//new List<LinkViewModel>() { Links[0] }; //Links.FindAll(o => o is LinkViewModel).Select(o => o as LinkViewModel).ToList();
        var objs = Links.Select(o => o as LinkViewModel)?.ToList();//new List<LinkViewModel>() { Links[0] }; //Links.FindAll(o => o is LinkViewModel).Select(o => o as LinkViewModel)?.ToList();
                                                                  //objs去掉重复的元素
        objs = objs.Distinct().ToList();
        objs = objs.Distinct()?.ToList();
        var visitedNodes = new HashSet<NodeViewModel>();
        FindObjs = new HashSet<IBaseViewModel>();
        objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes));
@@ -6453,6 +6333,7 @@
//构造一个List<LinkViewModel>类,能够实现List的所有功能
[Serializable]
public class LinkViewModelList : List<LinkCalcModel>
{
    //List<LinkCalcModel> base;
@@ -6473,7 +6354,7 @@
                list.Add((LinkViewModel)l);
            });
            return list;
            //return base.Select(l => (LinkViewModel)l).ToList();
            //return base.Select(l => (LinkViewModel)l)?.ToList();
        }
    }
@@ -6570,6 +6451,7 @@
}
[Serializable]
public class NodeViewModelList : List<NodeCalcModel>
{
    Dictionary<string, NodeCalcModel> dict;
@@ -6677,7 +6559,7 @@
}
public partial class MapViewNetWork
{
    public bool BuildFromInp(string filePath, bool use_old = false)
@@ -7073,7 +6955,7 @@
            k1++;
        }
        foreach (ValveNodeViewModel vn in valveNodes.ToList())
        foreach (ValveNodeViewModel vn in valveNodes?.ToList())
        {
            if (vn.Links.Count != 2) continue;
@@ -7107,7 +6989,7 @@
            Nodes.Remove(vn);
        }
        foreach (PumpNodeViewModel pn in pumpNodes.ToList())
        foreach (PumpNodeViewModel pn in pumpNodes?.ToList())
        {
            if (pn.Links.Count != 2) continue;
            if (pn.Links[0].ID != pn.Node1)
@@ -7577,8 +7459,7 @@
            var tempPath = Path.Combine(Directory.GetCurrentDirectory(), @"template\inp\导出模板.inp");
            if (!File.Exists(tempPath))
            {
                //MessageBox.Show($"模板文件不存在[{tempPath}]");
                return;
                throw new Exception($"模板文件不存在[{tempPath}]");
            }
            tempString = File.ReadAllText(tempPath);
        }
@@ -7597,7 +7478,7 @@
                {"{coor}","{6}" },
                {"{curve}","{7}" },
            };
        dictExchange.ToList().ForEach(m => tempString = tempString.Replace(m.Key, m.Value));
        dictExchange?.ToList().ForEach(m => tempString = tempString.Replace(m.Key, m.Value));
        StringBuilder junctionStringBuilder = new StringBuilder();
@@ -7766,6 +7647,7 @@
    }
}
[Serializable]
public class Vector3D
{
    public double X { get; set; }
@@ -7806,6 +7688,7 @@
    }
}
[Serializable]
public abstract class BaseModel
{
    public BaseModel() { }
@@ -7830,7 +7713,7 @@
}
[Serializable]
public class LinkModel : BaseModel
{
    public LinkModel() { }
@@ -7882,7 +7765,7 @@
    }
}
[Serializable]
public class LinkCalcModel : LinkModel
{
    public LinkCalcModel() { }
@@ -8010,7 +7893,7 @@
    public bool Hovered { get; set; }
}
[Serializable]
public class NodeModel : BaseModel
{
    public NodeModel() { }
@@ -8038,6 +7921,7 @@
}
[Serializable]
public class NodeCalcModel : NodeModel
{
    public NodeCalcModel() { }
@@ -8099,23 +7983,11 @@
    定速泵
}
public enum FlowCurveType
{
    流量扬程曲线 = 1,
    流量功率曲线 = 2,
    流量效率曲线 = 3
}
public enum FailType
{
    缺少Node1或Node2连接属性 = 1,
    喷头只能连接管道 = 2,
    缺少水箱或水池对象 = 3,
    管件对象连管件对象 = 4
}
[Serializable]
public class JunctionModel : NodeCalcModel
{
    public JunctionModel() { }
    /// 需水量
    public float Demand { get; set; }
@@ -8156,6 +8028,7 @@
    }
}
[Serializable]
public class MeterModel : NodeCalcModel
{
@@ -8184,6 +8057,7 @@
    }
}
[Serializable]
public class NozzleModel : NodeCalcModel
{
@@ -8230,6 +8104,7 @@
    }
}
[Serializable]
public class ReservoisModel : NodeCalcModel
{
@@ -8249,6 +8124,7 @@
}
[Serializable]
public class TankModel : NodeCalcModel
{
@@ -8294,6 +8170,7 @@
    }
}
[Serializable]
public class PipeModel : LinkCalcModel
{
    public override string ToString()
@@ -8303,6 +8180,7 @@
    }
}
[Serializable]
public class PumpModel : LinkCalcModel
{
@@ -8335,19 +8213,12 @@
    public string FlowCurveID { get; set; } = "PumpDefault";
    /// 参数
    public List<string> Parameters { get; set; }
    /// 流量曲线
    public FlowCurve FlowCurve { get; set; }
}
[Serializable]
public class ValveModel : LinkCalcModel
{
@@ -8361,19 +8232,9 @@
}/// <summary>
 /// 流量曲线
public class FlowCurve
{
    public string Name { get; set; }
    public FlowCurveType FlowCurveType { get; set; }
    public List<PointF> Data { get; set; } = new List<PointF>();
}
[Serializable]
public class Coor
{
    public string ID;
@@ -8384,6 +8245,8 @@
        this.Position = position;
    }
}
[Serializable]
public class Parts
{
    List<string> _parts = null;
@@ -8413,14 +8276,14 @@
    public Parts(string[] strings)
    {
        _parts = strings.ToList();
        _parts = strings?.ToList();
    }
    public Parts(string line)
    {
        List<string> sp = line.Split(new char[] {
'\t', ' '
}, StringSplitOptions.RemoveEmptyEntries).ToList();
}, StringSplitOptions.RemoveEmptyEntries)?.ToList();
        int pos = sp.IndexOf(";");
        if (pos > 0)
        {
@@ -8506,7 +8369,7 @@
}
[Serializable]
public class TimePoint
{
    public TimePoint()
@@ -8549,14 +8412,14 @@
}
[Serializable]
public class dict<TKey, TValue> : Dictionary<TKey, TValue>
{
    private List<TKey> keys
    {
        get
        {
            return this.Keys.ToList();
            return this.Keys?.ToList();
        }
    }
@@ -8566,87 +8429,15 @@
    {
    }
    public dict(int capacity) : base(capacity)
    {
    }
    public dict(IEnumerable<KeyValuePair<TKey, TValue>> collection) : base((IDictionary<TKey, TValue>)collection)
    {
    }
    public bool Value { get; set; }
    public bool SetKey(TKey key, dynamic Value)
    {
        if (this.Contains(key))
        {
            this[key] = Value;
            return false;
        }
        else
        {
            this.Add(key, Value);
            return true;
        }
    }
    public TKey[] GetKeys()
    {
        return this.Keys.ToArray();
    }
    public bool Contains(TKey[] keys)
    {
        foreach (var key in keys)
            if (!this.Contains(key)) return false;
        return true;
    }
    public bool Contains(TKey key)
    {
        return this.ContainsKey(key);
    }
    public bool Contains(KeyValuePair<TKey, dynamic> key)
    {
        return this.ContainsKey(key.Key);
    }
    public TValue Get(TKey key, TValue @default = default(TValue))
    {
        if (this.Contains(key))
            return this[key];
        else
            return @default;
    }
    public TValue Get(KeyValuePair<TKey, TValue> key, TValue @default = default(TValue))
    {
        if (this.Contains(key))
            return this[key.Key];
        else
            return @default;
    }
    public TValue pop(TKey key, TValue @default = default(TValue))
    {
        if (this.Contains(key))
        {
            var temp = this[key];
            this.Remove(key);
            return temp;
        }
        else
            return @default;
    }
    public TValue pop(KeyValuePair<TKey, TValue> key, TValue @default = default(TValue))
    {
        if (this.Contains(key))
        {
            var temp = this[key.Key];
            this.Remove(key);
            return temp;
        }
        else
            return @default;
    }
    public TValue this[KeyValuePair<TKey, TValue> key]
    {
        get { return this[key.Key]; }
        set { this[key.Key] = value; }
    }
    public TValue this[TKey key]
    {
        get
@@ -8687,66 +8478,17 @@
    }
    public TValue this[int index]
    {
        get
        {
            TKey key = default(TKey);
            if (typeof(TKey) == typeof(int))
                key = (TKey)(object)index;
            else
                key = keys[index];
            if (!base.ContainsKey(key))
                base.Add(key, default(TValue));
            return base[key];
        }
        set
        {
            TKey key = default(TKey);
            if (typeof(TKey) == typeof(int))
            {
                key = (TKey)(object)index;
                base[key] = value;
            }
            else
            {
                if (index < keys.Count)
                {
                    key = keys[index];
                    base[key] = value;
                }
            }
        }
    }
    public override string ToString()
    {
        return JsonConvert.SerializeObject(this);
    }
    public void LoadFromString(string s)
    {
        dict<TKey, TValue> d = JsonConvert.DeserializeObject<dict<TKey, TValue>>(s);
        this.Clear();
        foreach (var kp in d)
        {
            this.Add(kp.Key, kp.Value);
        }
    }
    public bool Remove(KeyValuePair<TKey, TValue> key)
    {
        return this.Remove(key.Key);
    }
    public List<TValue> values()
    {
        return this.Values.ToList();
    }
    #region 将Session的元素简单放进dict中,简单处理方便使用
    private DateTime 发送计时;
@@ -8777,374 +8519,8 @@
    #endregion
}
public partial class PropertyForm : UserControl
{
    private IBaseViewModel _selectedObject;
    private MapObjectType _selectedType = MapObjectType.全部;
    private List<SelectionSet> selectionSets;
    public SelectionSet selectionSet = new SelectionSet();
    private Form fr = null;
    public PropertyForm()
    {
        InitializeComponent();
    }
    public void SetEnabled(bool isReadOnly)
    {
        _isEnable = isReadOnly;
    }
    public void SetWindows(Form mg)
    {
        if (mg.WindowState == FormWindowState.Maximized)
        {
            //this.StartPosition = FormStartPosition.Manual; //设置窗体位置由程序控制
            this.Height = mg.Height - 50;
            this.Location = new Point(mg.Left + mg.Width - this.Width, mg.Top + 50); //设置新窗体位置,当前窗体的右侧(X轴方向)
        }
        else
        {
            //this.StartPosition = FormStartPosition.Manual; //设置窗体位置由程序控制
            this.Height = mg.Height;
            this.Location = new Point(mg.Left + mg.Width - 15, mg.Top); //设置新窗体位置,当前窗体的右侧(X轴方向)
        }
        fr = mg;
        //GlobalObject.PropertyForm.Show();
    }
    public Form GetWindow()
    {
        return this.fr;
    }
    public void SetObj(object o)
    {
        propertyGrid.SelectedObject = o;
        this.Text = o.GetType().Name;
    }
    public void SetObj(IBaseViewModel selectedObject)
    {
        lock (selectedObject)
        {
            _selectedObject = selectedObject;
            if (_selectedObject is JunctionViewModel junc)
            {
                _selectedType = MapObjectType.节点;
                propertyGrid.SelectedObjects = new JunctionViewModel[] { junc };
            }
            else if (_selectedObject is ReservoirViewModel res)
            {
                _selectedType = MapObjectType.水库;
                propertyGrid.SelectedObjects = new ReservoirViewModel[] { res };
            }
            else if (_selectedObject is TankViewModel tank)
            {
                _selectedType = MapObjectType.水池;
                propertyGrid.SelectedObjects = new TankViewModel[] { tank };
            }
            else if (_selectedObject is PipeViewModel pipe)
            {
                _selectedType = MapObjectType.管线;
                propertyGrid.SelectedObjects = new PipeViewModel[] { pipe };
            }
            else if (_selectedObject is ValveViewModel valve)
            {
                _selectedType = MapObjectType.阀门;
                propertyGrid.SelectedObjects = new ValveViewModel[] { valve };
            }
            else if (_selectedObject is RepeaterViewModel repeater)
            {
                _selectedType = MapObjectType.重复器;
                propertyGrid.SelectedObjects = new RepeaterViewModel[] { repeater };
            }
            //水表
            else if (_selectedObject is MeterViewModel meter)
            {
                _selectedType = MapObjectType.水表;
                propertyGrid.SelectedObjects = new MeterViewModel[] { meter };
            }
            //水泵
            else if (_selectedObject is PumpViewModel pump)
            {
                _selectedType = MapObjectType.水泵;
                propertyGrid.SelectedObjects = new PumpViewModel[] { pump };
            }
            //喷头Nozzle
            else if (_selectedObject is NozzleViewModel nozzle)
            {
                _selectedType = MapObjectType.喷头;
                propertyGrid.SelectedObjects = new NozzleViewModel[] { nozzle };
            }
            else
            {
                _selectedType = MapObjectType.全部;
                propertyGrid.SelectedObjects = new IBaseViewModel[] { selectedObject };
            }
            switch (_selectedType)
            {
                case MapObjectType.节点:
                    Text = "节点 Properties";
                    break;
                case MapObjectType.水库:
                    Text = "水库 Properties";
                    break;
                case MapObjectType.水池:
                    Text = "水池 Properties";
                    break;
                case MapObjectType.管线:
                    Text = "管线 Properties";
                    break;
                case MapObjectType.阀门:
                    Text = "阀门 Properties";
                    break;
                case MapObjectType.重复器:
                    Text = "重复器 Properties";
                    break;
            }
        }
    }
    public void SetNet(MapViewNetWork net)
    {
        selectionSet.net = net;
    }
    public void SetObjs(List<IBaseViewModel> selectedObjects)
    {
        if (selectedObjects == null) return;
        selectedObjects.RemoveAll(obj => obj == null);
        selectedObjects.ForEach(obj =>
        {
            if (obj.Tags == null)
            {
                obj.Tags = new TagList();
            }
        });
        selectionSet.selectedObjects = selectedObjects.ToList();
        if (selectedObjects.Count == 1)
            SetObj(selectedObjects[0]);
        else
            ShowProperties(selectedObjects);
        if (selectionSet.OnlyViewSelected)
            RefreshListBox();
    }
    private void PropertyForm_Load_1(object sender, EventArgs e)
    {
        foreach (var item in Enum.GetValues(typeof(MapObjectType)))
        {
            comboBox_type.Items.Add(item);
        }
        comboBox_type.SelectedIndex = 0;
        selectionSets = new List<SelectionSet>();
        selectionSet = new SelectionSet();
        listBox1.DataSource = selectionSet.View;
    }
    private void comboBox_type_SelectedIndexChanged(object sender, EventArgs e)
    {
        RefreshListBox();
    }
    void RefreshListBox()
    {
        if (selectionSet == null) return;
        string txt = comboBox_type.SelectedItem.ToString();
        MapObjectType selectedType = (MapObjectType)Enum.Parse(typeof(MapObjectType), txt);
        // 使用 LINQ 查询筛选选择集
        selectionSet.filterType = selectedType;
        selectionSet.FilterString = textBox_search.Text;
        listBox1.SelectedIndexChanged -= listBox1_SelectedIndexChanged;
        listBox1.DataSource = selectionSet.View;
        listBox1.SelectedIndexChanged += listBox1_SelectedIndexChanged;
    }
    private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (listBox1.SelectedItems.Count == 0)
        {
            return;
        }
        else if (listBox1.SelectedItems.Count == 1)
        {
            var objID = listBox1.SelectedItems[0];
            var findlist = selectionSet.net.MapObjects.FindAll(o => o.ID == objID);
            if (findlist.Count <= 0) return;
            IBaseViewModel mapObject = findlist[0];
            if (mapObject != null) SetObj(mapObject);
            GlobalObject.map.selectedObjs.ForEach(o => o.Selected = false); ;
            GlobalObject.map.selectedObjs.Clear();
            GlobalObject.map.selectedObjs.Add(mapObject);
            mapObject.Selected = true;
            GlobalObject.map.SetMapInvalidate();
        }
        else
        {
            List<IBaseViewModel> list = new List<IBaseViewModel>();
            foreach (var o in listBox1.SelectedItems)
            {
                var objID = listBox1.SelectedItems[0];
                IBaseViewModel mapObject = selectionSet.net.MapObjects.FindAll(obj => obj.ID == objID)[0];
                list.Add(mapObject);
            }
            ShowProperties(list);
            GlobalObject.map.selectedObjs.ForEach(o => o.Selected = false); ;
            GlobalObject.map.selectedObjs.Clear();
            list.ForEach(o => o.Selected = true);
            GlobalObject.map.selectedObjs.AddRange(list);
            GlobalObject.map.SetMapInvalidate();
        }
    }
    private void listBox1_DoubleClick(object sender, EventArgs e)
    {
        if (listBox1.SelectedItems.Count == 1)
        {
            var objID = listBox1.SelectedItems[0];
            IBaseViewModel mapObject = selectionSet.net.MapObjects.FindAll(obj => obj.ID == objID)[0];
            GlobalObject.map.setCenter(mapObject);
            GlobalObject.map.SetMapInvalidate();
        }
    }
    private void PropertyForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        e.Cancel = true;
        this.Hide();
    }
    bool _isEnable = true;
    private static Dictionary<object, List<object>> _selectedObjectsDict = new Dictionary<object, List<object>>();
    private void propertyGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
    {
        if (!_isEnable)
        {
            MessageBox.Show("当前状态的修改将不会被保存", "重复器展开中");
            _isEnable = true;
        }
        GlobalObject.map.SetMapInvalidate();
    }
    public void ShowProperties(IEnumerable<IBaseViewModel> selectedObjects)
    {
        IBaseViewModel[] objs = null;
        try
        {
            if (selectedObjects != null)
                objs = selectedObjects.ToArray();
        }
        catch
        {
            return;
        }
        propertyGrid.SelectedObjects = objs;
    }
    private void textBox_search_TextChanged(object sender, EventArgs e)
    {
        RefreshListBox();
    }
    private void checkBox_OnlyShowSelected_CheckedChanged(object sender, EventArgs e)
    {
        selectionSet.OnlyViewSelected = checkBox_OnlyShowSelected.Checked;
        RefreshListBox();
    }
    private void label_lock_Click(object sender, EventArgs e)
    {
        var label_lock = (Label)sender;
        GlobalObject.LockSelect = !GlobalObject.LockSelect;
        if (GlobalObject.LockSelect)
        {
            label_lock.BackColor = Color.Blue;
            label_lock.Text = "🔒";
        }
        else
        {
            label_lock.BackColor = Color.Green;
            label_lock.Text = "🔓";
        }
    }
    private void label_filter_Click(object sender, EventArgs e)
    {
    }
    private void PropertyForm_KeyDown(object sender, KeyEventArgs e)
    {
        //Ctrl+A,则选中当前listbox中的所有项
        if (e.Control && e.KeyCode == Keys.A)
        {
            for (int i = 0; i < listBox1.Items.Count; i++)
            {
                listBox1.SetSelected(i, true);
            }
        }
    }
    private void 全选ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        listBox1.SelectedIndexChanged -= listBox1_SelectedIndexChanged;
        for (int i = 0; i < listBox1.Items.Count; i++)
        {
            listBox1.SetSelected(i, true);
        }
        listBox1.SelectedIndexChanged += listBox1_SelectedIndexChanged;
        this.propertyGrid.SelectedObjects = selectionSet.CurrentSelectedObjects?.ToArray();
        GlobalObject.map.selectedObjs.ForEach(o => o.Selected = false);
        if (selectionSet.CurrentSelectedObjects != null)
        {
            GlobalObject.map.selectedObjs.AddRange(selectionSet.CurrentSelectedObjects);
            selectionSet.CurrentSelectedObjects.ForEach(o =>
            {
                o.Selected = true;
            });
        }
        GlobalObject.map.SetMapInvalidate();
    }
    private void listBox1_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Right)
        {
            if (listBox1.SelectedItems.Count > 0)
            {
                contextMenuStrip1.Show(listBox1, e.Location);
            }
        }
    }
}
[Serializable]
public class SelectionSet
{
    public string Name;
@@ -9221,237 +8597,16 @@
            }
            CurrentSelectedObjects = list;
            list_result = list.Select(o => o.ID).ToList();
            list_result = list.Select(o => o.ID)?.ToList();
            return list_result;
        }
    }
}
partial class PropertyForm
{
    private System.ComponentModel.IContainer components = null;
    /// Clean up any resources being used.
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }
    #region Windows Form Designer generated code
    private void InitializeComponent()
    {
        this.components = new System.ComponentModel.Container();
        this.propertyGrid = new System.Windows.Forms.PropertyGrid();
        this.listBox1 = new System.Windows.Forms.ListBox();
        this.comboBox_type = new System.Windows.Forms.ComboBox();
        this.splitContainer1 = new System.Windows.Forms.SplitContainer();
        this.panel1 = new System.Windows.Forms.Panel();
        this.checkBox_OnlyShowSelected = new System.Windows.Forms.CheckBox();
        this.textBox_search = new System.Windows.Forms.TextBox();
        this.label_filter = new System.Windows.Forms.Label();
        this.label_lock = new System.Windows.Forms.Label();
        this.label1 = new System.Windows.Forms.Label();
        this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
        this.全选ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
        this.splitContainer1.Panel1.SuspendLayout();
        this.splitContainer1.Panel2.SuspendLayout();
        this.splitContainer1.SuspendLayout();
        this.panel1.SuspendLayout();
        this.contextMenuStrip1.SuspendLayout();
        this.SuspendLayout();
        //
        // propertyGrid
        //
        this.propertyGrid.Dock = System.Windows.Forms.DockStyle.Fill;
        this.propertyGrid.Location = new System.Drawing.Point(0, 0);
        this.propertyGrid.Name = "propertyGrid";
        this.propertyGrid.Size = new System.Drawing.Size(202, 346);
        this.propertyGrid.TabIndex = 0;
        this.propertyGrid.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.propertyGrid_PropertyValueChanged);
        //
        // listBox1
        //
        this.listBox1.Dock = System.Windows.Forms.DockStyle.Fill;
        this.listBox1.FormattingEnabled = true;
        this.listBox1.ItemHeight = 12;
        this.listBox1.Location = new System.Drawing.Point(0, 41);
        this.listBox1.Name = "listBox1";
        this.listBox1.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
        this.listBox1.Size = new System.Drawing.Size(202, 75);
        this.listBox1.TabIndex = 1;
        this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged);
        this.listBox1.DoubleClick += new System.EventHandler(this.listBox1_DoubleClick);
        this.listBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.listBox1_MouseDown);
        //
        // comboBox_type
        //
        this.comboBox_type.Dock = System.Windows.Forms.DockStyle.Top;
        this.comboBox_type.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
        this.comboBox_type.FormattingEnabled = true;
        this.comboBox_type.Location = new System.Drawing.Point(0, 21);
        this.comboBox_type.Name = "comboBox_type";
        this.comboBox_type.Size = new System.Drawing.Size(202, 20);
        this.comboBox_type.TabIndex = 2;
        this.comboBox_type.SelectedIndexChanged += new System.EventHandler(this.comboBox_type_SelectedIndexChanged);
        //
        // splitContainer1
        //
        this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
        this.splitContainer1.Location = new System.Drawing.Point(0, 0);
        this.splitContainer1.Name = "splitContainer1";
        this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal;
        //
        // splitContainer1.Panel1
        //
        this.splitContainer1.Panel1.Controls.Add(this.propertyGrid);
        //
        // splitContainer1.Panel2
        //
        this.splitContainer1.Panel2.Controls.Add(this.listBox1);
        this.splitContainer1.Panel2.Controls.Add(this.comboBox_type);
        this.splitContainer1.Panel2.Controls.Add(this.panel1);
        this.splitContainer1.Size = new System.Drawing.Size(202, 466);
        this.splitContainer1.SplitterDistance = 346;
        this.splitContainer1.TabIndex = 3;
        //
        // panel1
        //
        this.panel1.Controls.Add(this.checkBox_OnlyShowSelected);
        this.panel1.Controls.Add(this.textBox_search);
        this.panel1.Controls.Add(this.label_filter);
        this.panel1.Controls.Add(this.label_lock);
        this.panel1.Controls.Add(this.label1);
        this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
        this.panel1.Location = new System.Drawing.Point(0, 0);
        this.panel1.Name = "panel1";
        this.panel1.Size = new System.Drawing.Size(202, 21);
        this.panel1.TabIndex = 4;
        //
        // checkBox_OnlyShowSelected
        //
        this.checkBox_OnlyShowSelected.AutoSize = true;
        this.checkBox_OnlyShowSelected.Checked = true;
        this.checkBox_OnlyShowSelected.CheckState = System.Windows.Forms.CheckState.Checked;
        this.checkBox_OnlyShowSelected.Location = new System.Drawing.Point(127, 2);
        this.checkBox_OnlyShowSelected.Name = "checkBox_OnlyShowSelected";
        this.checkBox_OnlyShowSelected.Size = new System.Drawing.Size(48, 16);
        this.checkBox_OnlyShowSelected.TabIndex = 3;
        this.checkBox_OnlyShowSelected.Text = "选择";
        this.checkBox_OnlyShowSelected.UseVisualStyleBackColor = true;
        this.checkBox_OnlyShowSelected.CheckedChanged += new System.EventHandler(this.checkBox_OnlyShowSelected_CheckedChanged);
        //
        // textBox_search
        //
        this.textBox_search.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
        this.textBox_search.Location = new System.Drawing.Point(44, 0);
        this.textBox_search.Name = "textBox_search";
        this.textBox_search.Size = new System.Drawing.Size(77, 21);
        this.textBox_search.TabIndex = 3;
        this.textBox_search.TextChanged += new System.EventHandler(this.textBox_search_TextChanged);
        //
        // label_filter
        //
        this.label_filter.BackColor = System.Drawing.Color.Green;
        this.label_filter.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
        this.label_filter.Font = new System.Drawing.Font("宋体", 12F);
        this.label_filter.ForeColor = System.Drawing.Color.White;
        this.label_filter.Location = new System.Drawing.Point(177, -1);
        this.label_filter.Name = "label_filter";
        this.label_filter.Size = new System.Drawing.Size(21, 21);
        this.label_filter.TabIndex = 4;
        this.label_filter.Text = "🔽";
        this.label_filter.Click += new System.EventHandler(this.label_filter_Click);
        //
        // label_lock
        //
        this.label_lock.BackColor = System.Drawing.Color.Green;
        this.label_lock.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
        this.label_lock.Font = new System.Drawing.Font("宋体", 12F);
        this.label_lock.ForeColor = System.Drawing.Color.White;
        this.label_lock.Location = new System.Drawing.Point(1, 0);
        this.label_lock.Name = "label_lock";
        this.label_lock.Size = new System.Drawing.Size(21, 21);
        this.label_lock.TabIndex = 4;
        this.label_lock.Text = "🔓";
        this.label_lock.Click += new System.EventHandler(this.label_lock_Click);
        //
        // label1
        //
        this.label1.BackColor = System.Drawing.SystemColors.AppWorkspace;
        this.label1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
        this.label1.Font = new System.Drawing.Font("宋体", 12F);
        this.label1.ForeColor = System.Drawing.Color.White;
        this.label1.Location = new System.Drawing.Point(22, 0);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(21, 21);
        this.label1.TabIndex = 4;
        this.label1.Text = "🔍";
        //
        // contextMenuStrip1
        //
        this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.全选ToolStripMenuItem});
        this.contextMenuStrip1.Name = "contextMenuStrip1";
        this.contextMenuStrip1.Size = new System.Drawing.Size(101, 26);
        //
        // 全选ToolStripMenuItem
        //
        this.全选ToolStripMenuItem.Name = "全选ToolStripMenuItem";
        this.全选ToolStripMenuItem.Size = new System.Drawing.Size(100, 22);
        this.全选ToolStripMenuItem.Text = "全选";
        this.全选ToolStripMenuItem.Click += new System.EventHandler(this.全选ToolStripMenuItem_Click);
        //
        // PropertyForm
        //
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.Controls.Add(this.splitContainer1);
        this.Name = "PropertyForm";
        this.Size = new System.Drawing.Size(202, 466);
        this.Load += new System.EventHandler(this.PropertyForm_Load_1);
        this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.PropertyForm_KeyDown);
        this.splitContainer1.Panel1.ResumeLayout(false);
        this.splitContainer1.Panel2.ResumeLayout(false);
        ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
        this.splitContainer1.ResumeLayout(false);
        this.panel1.ResumeLayout(false);
        this.panel1.PerformLayout();
        this.contextMenuStrip1.ResumeLayout(false);
        this.ResumeLayout(false);
    }
    #endregion
    public System.Windows.Forms.PropertyGrid propertyGrid;
    public System.Windows.Forms.ListBox listBox1;
    private System.Windows.Forms.ComboBox comboBox_type;
    private System.Windows.Forms.SplitContainer splitContainer1;
    private System.Windows.Forms.CheckBox checkBox_OnlyShowSelected;
    private System.Windows.Forms.TextBox textBox_search;
    private System.Windows.Forms.Panel panel1;
    private System.Windows.Forms.Label label1;
    private System.Windows.Forms.Label label_lock;
    private System.Windows.Forms.Label label_filter;
    private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
    private System.Windows.Forms.ToolStripMenuItem 全选ToolStripMenuItem;
}
[Serializable]
public class DRange
{
@@ -9511,6 +8666,8 @@
        return $"{Min:0.000}-{Max:0.000}";
    }
}
[Serializable]
public class MathSolver
{
    static double ErrNum = -1;
@@ -9603,142 +8760,8 @@
    }
}
public partial class InputBox : Form
{
    DialogResult _DialogResult;
    void initPosition()
    {
        this.StartPosition = FormStartPosition.Manual;
        int offsetX = -1 * this.Width / 2; // 距离鼠标左侧的间距
        int offsetY = -1 * this.Height / 2; // 距离鼠标顶部的间距
        int newWindowWidth = this.Width; // 新窗口的宽度
        int newWindowHeight = this.Height; // 新窗口的高度
        Point mousePosition = MousePosition; // 获取鼠标位置
        this.Location = new Point(mousePosition.X + offsetX, mousePosition.Y + offsetY); // 计算新窗口的位置
    }
    public InputBox()
    {
        InitializeComponent();
        initPosition();
    }
    public InputBox(string txt, string content = "")
    {
        InitializeComponent();
        initPosition();
        this.Text = txt;
        this.textBox1.Text = content;
    }
    private void button1_Click(object sender, EventArgs e)
    {
        _DialogResult = DialogResult.OK;
        this.Close();
    }
    private void button2_Click(object sender, EventArgs e)
    {
        _DialogResult = DialogResult.Cancel;
        this.Close();
    }
    public new string ShowDialog()
    {
        base.ShowDialog();
        if (_DialogResult == DialogResult.OK)
            return textBox1.Text;
        else
            return null;
    }
}
partial class InputBox
{
    private System.ComponentModel.IContainer components = null;
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }
    #region Windows Form Designer generated code
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    private void InitializeComponent()
    {
        System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InputBox));
        this.textBox1 = new System.Windows.Forms.TextBox();
        this.button1 = new System.Windows.Forms.Button();
        this.button2 = new System.Windows.Forms.Button();
        this.SuspendLayout();
        //
        // textBox1
        //
        this.textBox1.Location = new System.Drawing.Point(12, 12);
        this.textBox1.Name = "textBox1";
        this.textBox1.Size = new System.Drawing.Size(380, 21);
        this.textBox1.TabIndex = 0;
        //
        // button1
        //
        this.button1.Location = new System.Drawing.Point(268, 45);
        this.button1.Name = "button1";
        this.button1.Size = new System.Drawing.Size(59, 20);
        this.button1.TabIndex = 1;
        this.button1.Text = "确定";
        this.button1.UseVisualStyleBackColor = true;
        this.button1.Click += new System.EventHandler(this.button1_Click);
        //
        // button2
        //
        this.button2.Location = new System.Drawing.Point(333, 45);
        this.button2.Name = "button2";
        this.button2.Size = new System.Drawing.Size(59, 20);
        this.button2.TabIndex = 1;
        this.button2.Text = "取消";
        this.button2.UseVisualStyleBackColor = true;
        this.button2.Click += new System.EventHandler(this.button2_Click);
        //
        // InputBox
        //
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(404, 74);
        this.Controls.Add(this.button2);
        this.Controls.Add(this.button1);
        this.Controls.Add(this.textBox1);
        this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
        this.MaximizeBox = false;
        this.MinimizeBox = false;
        this.Name = "InputBox";
        this.Text = "输入名称";
        this.TopMost = true;
        this.ResumeLayout(false);
        this.PerformLayout();
    }
    #endregion
    private System.Windows.Forms.TextBox textBox1;
    private System.Windows.Forms.Button button1;
    private System.Windows.Forms.Button button2;
}
[Serializable]
public static class FileCopy
{
    public static void Copy(string source, string destination, bool isOverWrite = true)
@@ -9768,124 +8791,7 @@
    }
}
public static class PointFExtansion
{
    public static Point ToPoint(this PointF p)
    {
        return new Point((int)p.X, (int)p.Y);
    }
}
public static class DeepCopyClass
{
    public static T DeepCopyByBin<T>(this T obj)
    {
        object retval;
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            //序列化成流
            bf.Serialize(ms, obj);
            ms.Seek(0, SeekOrigin.Begin);
            //反序列化成对象
            retval = bf.Deserialize(ms);
            ms.Close();
        }
        return (T)retval;
    }
    public static void SerialToFile(this object obj, string filePath)
    {
        // 创建文件流
        FileStream fileStream = new FileStream(filePath, FileMode.Create);
        try
        {
            // 创建BinaryFormatter对象
            BinaryFormatter formatter = new BinaryFormatter();
            // 序列化并保存对象到文件流
            formatter.Serialize(fileStream, obj);
            Console.WriteLine("对象已经成功序列化并保存到文件中!");
        }
        catch (Exception ex)
        {
            Console.WriteLine("发生错误:" + ex.Message);
        }
        finally
        {
            // 关闭文件流
            fileStream.Close();
        }
    }
    private static T CloneModel<T>(T oModel)
    {
        var oRes = default(T);
        var oType = typeof(T);
        //create new obj
        oRes = (T)Activator.CreateInstance(oType);
        //pass 1 property
        var lstPro = oType.GetProperties();
        foreach (var oPro in lstPro)
        {
            var oValue = oPro.GetValue(oModel, null);
            oPro.SetValue(oRes, DeepCopy(oValue), null);
        }
        var lstField = oType.GetFields();
        foreach (var oField in lstField)
        {
            var oValue = oField.GetValue(oModel);
            oField.SetValue(oRes, DeepCopy(oValue));
        }
        return oRes;
    }
    public static object DeepCopy(this object obj)
    {
        if (obj == null)
            return null;
        Type type = obj.GetType();
        if (type.IsValueType || type == typeof(string))
        {
            return obj;
        }
        else if (type.IsArray)
        {
            Type elementType = Type.GetType(
                 type.FullName.Replace("[]", string.Empty));
            var array = obj as Array;
            Array copied = Array.CreateInstance(elementType, array.Length);
            for (int i = 0; i < array.Length; i++)
            {
                copied.SetValue(DeepCopy(array.GetValue(i)), i);
            }
            return Convert.ChangeType(copied, obj.GetType());
        }
        else if (type.IsClass)
        {
            object toret = Activator.CreateInstance(obj.GetType());
            FieldInfo[] fields = type.GetFields(BindingFlags.Public |
                        BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                object fieldValue = field.GetValue(obj);
                if (fieldValue == null)
                    continue;
                field.SetValue(toret, DeepCopy(fieldValue));
            }
            return toret;
        }
        else
            throw new ArgumentException("Unknown type");
    }
}
[Serializable]
public class message
{
    public static bool show(string caption, string content, MessageBoxButtons boxButtons = MessageBoxButtons.OKCancel)
@@ -9896,4 +8802,12 @@
        else
            return false;
    }
}
public static class PointFExtansion
{
    public static Point ToPoint(this PointF p)
    {
        return new Point((int)p.X, (int)p.Y);
    }
}