//using CloudWaterNetwork.Magnifier; using CommonBase; //using ConfigApp; //using DevExpress.Diagram.Core.Layout; //using DevExpress.DirectX.NativeInterop.Direct2D; //using DevExpress.Utils.Extensions; //using dict_py_Inner; using Hydro.MapView; using Hydro.MapView.Common; using Newtonsoft.Json; //using ReflectionManager_NameSpace; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Remoting.Metadata; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.DataVisualization.Charting; using static Hydro.Core.ObjectEnum; using static Hydro.MapView.MapViewEnum; using static System.Net.Mime.MediaTypeNames; using static System.Windows.Forms.AxHost; using static System.Windows.Forms.LinkLabel; using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button; using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrackBar; using Cursor = System.Windows.Forms.Cursor; namespace Hydro.MapUI { public partial class MapViewer : UserControl { #region 一、全局 #region 初始化 //public MapViewer() //{ // InitializeComponent(); // //_Template = new Template(); // //toolStrip1.Visible = false; // MapCenter = PointF.Empty; // zoom = 1.0f; // DoubleBuffered = true; // SetStyle(ControlStyles.SupportsTransparentBackColor, true); // BackColor = Color.Transparent; //} private bool _showToolBar = true; [DisplayName("显示工具栏")] public bool showToolBar { get { return _showToolBar;// this.panel1==null?true:Visible; } set { _showToolBar=value; if (this.panel1!=null) this.panel1.Visible = value; } } private bool _showStatusBar = true; [DisplayName("显示状态栏")] public bool ShowStatusBar { get { return _showStatusBar;// this.panel1==null?true:Visible; } set { _showStatusBar = value; if (this.statusStrip1 != null) this.statusStrip1.Visible = value; } } public MapViewer() { //this.showToolBar = false; InitializeComponent(); MapCenter = PointF.Empty; zoom = 1.0f; DoubleBuffered = true; SetStyle(ControlStyles.SupportsTransparentBackColor, true); BackColor = Color.Transparent; } public MapViewer(bool showToolBar = false) { this.showToolBar = showToolBar; InitializeComponent(); MapCenter = PointF.Empty; zoom = 1.0f; DoubleBuffered = true; SetStyle(ControlStyles.SupportsTransparentBackColor, true); BackColor = Color.Transparent; //if (!showToolBar) this.panel1.Visible = false; } private void MapViewer_Load(object sender, EventArgs e) { this.panel1.Visible = _showToolBar; this.statusStrip1.Visible = _showStatusBar; } #endregion #region 对外开放,全局控制方法 public bool LoadData(bool isDelCache = false) { if (_Template == null) return false; if (isDelCache || _Template.network == null) { if (!_Template.loadInpFile()) { //MessageBox.Show("读取地图失败"); _Template.network = new MapViewNetWork(); //return false; } } if (_ViewModel == null) { if (!_IsEditMode) { if (param == null) param = new dict(); _Template.network.LoadRepeaters(_Template.MaxLevel, param, _ViewModel, !_IsEditMode); } else { if (param == null) param = new dict(); _Template.network.LoadRepeaters(_Template.MaxLevel, param, null, !_IsEditMode); } } else { if (_IsEditMode) { if (param == null) param = new dict(); _Template.network.LoadRepeaters(_Template.MaxLevel, param, _ViewModel, !_IsEditMode); } else { if (param == null) param = new dict(); _Template.network.LoadRepeaters(_Template.MaxLevel, param, null, !_IsEditMode); } } if (GlobalObject.PropertyForm != null) { GlobalObject.PropertyForm.SetEnabled(_IsEditMode); GlobalObject.PropertyForm.SetNet(_Template.network); _Template.network.MapObjects.AddUndoRedoSupport(GlobalObject.PropertyForm.propertyGrid); } SetStartEndPoint(_Template.Node1, _Template.Node2); return true; } Dictionary _ViewModel = null; public void Clear() { _Template = null; MapCenter = PointF.Empty; zoom = 1.0f; Rotation = 0; RotationF = 90; Invalidate(); } public void SetData(Template template, dict param = null, Dictionary viewMode = null) { this.param = param; bool reLoad = _Template == template; this._Template = template; this._ViewModel = viewMode; ToolStripMenuItem_Floor.DropDownItems.Clear(); //if ( _Template?.Floors!=null) //{ // _Template.Floors.ForEach(f=> // { // var btn = new ToolStripButton(" "+f.Name+" "); // btn.Click += (s, e) => // { // this.mapOption.ShowFloor = f.FloorIndex; // if (f.MapView != null ) // { // this.mapOption= f.MapView.Copy(); // } // this.Invalidate(); // }; // ToolStripMenuItem_Floor.DropDownItems.Add(btn); // }); //} //_Template.network = null; if (!LoadData()) return; //LoadData(); // temp.network.LoadRepeaters(); // map.SetStartEndPoint(temp.Node1, temp.Node2); if (!reLoad) { if (_Template.view == null) InitCenter(); else { //MapCenter = _Template.view.Center; //zoom = _Template.view.zoom; //Rotation = _Template.view.rotation; //RotationF = _Template.view.rotationF; this.mapOption = _Template.view.Copy(); SetInvalidated(); } } Invalidate(); } private void InitCenter() { //MapCenter var p = PointF.Empty; float x0 = 99999999999f, y0 = 99999999999f, x1 = -99999999999f, y1 = -99999999999f; foreach (NodeViewModel junction in _Nodes) { p.X += (float)junction.X; p.Y += (float)junction.Y; if (x0 > junction.X) x0 = junction.X; if (y0 > junction.Y) y0 = junction.Y; if (x1 < junction.X) x1 = junction.X; if (y1 < junction.Y) y1 = junction.Y; } float x_span = x1 - x0, y_span = y1 - y0; zoom = Math.Min(Width / x_span, Height / y_span); zoom = Math.Max(zoom, MinZoom); zoom = Math.Min(zoom, MaxZoom); Rotation = 0; RotationF = 90; if (_Nodes.Count > 0) { p.X /= _Nodes.Count; p.Y /= _Nodes.Count; } MapCenter = p; } public void SetInvalidated() { Invalidate(); } public void SetStartEndPoint(String node1, string node2) { _StartPoint = node1; _EndPoint = node2; Invalidate(); } public void Set3DView(bool is3Dview, double 俯视角度) { this.RotationF = 俯视角度; this.is3Dview = is3Dview; Invalidate(); } public void SetRotation(double d) { this.Rotation = d; Invalidate(); } #endregion #region 基础坐标转换方法 /// /// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。 /// /// /// private PointF ScreenToVMap(PointF screenPos, float z = 0) { var centerX = Width / 2; var centerY = Height / 2; var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X; var worldY = (screenPos.Y - centerY) / Zoom.Y + 0; //if (is3Dview) worldY = -(screenPos.Y - centerY + 2 * z) / (0.5f* zoom) + center.Y; return new PointF(worldX, worldY); } /// /// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。 /// /// /// private PointF ScreenToMap(PointF screenPos, float z = 0) { var centerX = Width / 2; var centerY = Height / 2; var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X; var worldY = (screenPos.Y - centerY - Z(z).Y) / Zoom.Y + MapCenter.Y; //if (is3Dview) worldY = -(screenPos.Y - centerY + 2 * z) / (0.5f* zoom) + center.Y; return new PointF(worldX, worldY); } private PointF MapToScreen(PointF mapPos, float z = 0) { var centerX = Width / 2; var centerY = Height / 2; var screenX = (mapPos.X - MapCenter.X) * Zoom.X + centerX + Z(z).X; var screenY = (mapPos.Y - MapCenter.Y) * Zoom.Y + centerY + Z(z).Y; //if (is3Dview) screenY = -(mapPos.Y - center.Y) * (0.5f * zoom) + centerY - 2 * z; return new PointF(screenX, screenY); } // 根据旋转角度计算旋转后的坐标 // 根据旋转角度计算旋转后的坐标 private PointF Get平面旋转Point(PointF p) { PointF center = MapCenter; double radian = Rotation * Math.PI / 180; // 角度转弧度 float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X); float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y); return new PointF(x, y); } private PointF Get平面还原Point(PointF p) { PointF center = MapCenter; double radian = -Rotation * Math.PI / 180; // 角度转弧度 float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X); float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y); return new PointF(x, y); } private PointF Get俯视角旋转Point(PointF p, float z) { PointF center = MapCenter; double radian_fushi = 俯视弧度; float sin = (float)Math.Sin(radian_fushi); float cos = (float)Math.Cos(radian_fushi); float x = (float)p.X; float y = (float)(sin * (p.Y - center.Y) + center.Y) + cos * z; return new PointF(x, y); } private PointF Get俯视角还原Point(PointF p, float z) { PointF center = MapCenter; double radian_fushi = 俯视弧度; float sin = (float)Math.Sin(radian_fushi); float cos = (float)Math.Cos(radian_fushi); float x = (float)p.X; float y = (p.Y - center.Y - cos * z) / sin + center.Y; return new PointF(x, y); } private PointF GetRotateVector(PointF p, PointF p0) { double radian = Rotation * Math.PI / 180; // 角度转弧度 float x = (float)(Math.Cos(radian) * (p.X - p0.X) - Math.Sin(radian) * (p.Y - p0.Y)); float y = (float)(Math.Sin(radian) * (p.X - p0.X) + Math.Cos(radian) * (p.Y - p0.Y)); return new PointF(x, y); } /// /// 获取地图投影坐标 /// /// /// /// private PointF WorldPointToMapPoint(PointF point, float z, PointF3D offset = null) { if (offset == null) offset = new PointF3D(0, 0, 0); point = new PointF(point.X + offset.X, point.Y + offset.Y); var pointR = Get平面旋转Point(point); var pointT = Get俯视角旋转Point(pointR, z + offset.Z); //var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y)); return pointT; } private PointF WorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null) { PointF p; if (junction == null) return new PointF(0, 0); p = WorldPointToMapPoint(junction.Position, junction.Elev, offset); return p; } private List WorldPointToMapPoint(LinkViewModel pipe, PointF3D offset = null) { List list = new List(); PointF p; p = WorldPointToMapPoint(pipe.StartNode, offset); list.Add(p); p = WorldPointToMapPoint(pipe.EndNode, offset); list.Add(p); return list; } /// /// 获取地图投影坐标 /// /// /// /// private PointF MapPointToWorldPoint(PointF point, float z = 0) { var pointT = Get俯视角还原Point(point, z); pointT = Get平面还原Point(pointT); //var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y)); return pointT; } private PointF GetMapPoint_还原(NodeViewModel junction) { PointF p; p = MapPointToWorldPoint(junction.Position, junction.Elev); return p; } #endregion #region 判断可见性 private float Get_dist(PointF A, PointF B) { float dx = A.X - B.X; float dy = A.Y - B.Y; float dist = (float)Math.Sqrt(dx * dx + dy * dy); return dist; } PointF PMin_Show, PMax_Show; /// /// 判断是否在屏幕坐标内 /// /// /// 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; } /// /// 判断是否在屏幕坐标内 /// /// /// public bool isVisible(List list_MapPos) { bool visible = false; foreach (var MapPos in list_MapPos) { if (MapPos.X < PMin_Show.X || MapPos.X > PMax_Show.X || MapPos.Y < PMin_Show.Y || MapPos.Y > PMax_Show.Y) { } else { visible = true; return true; } } return visible; } #endregion #region 重绘函数 bool _needPaintAll = false; protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (float.IsInfinity(zoom)) return; label_center.Text = $"center:({MapCenter.X.ToString("0.00")} ,{MapCenter.Y.ToString("0.00")})"; label_zoom.Text = $"Zoom:{zoom.ToString("0.000")}"; toolStripStatusLabel_rotation.Text = $"Rotation:({Rotation.ToString("0")},{RotationF.ToString("0")})"; //if (!_needPaintAll) // return; int heightOfBar = showToolBar ? 24 : 0; if (!showToolBar) heightOfBar = 0; //if (e.ClipRectangle != new Rectangle(this.Left, heightOfBar, this.Width, this.Height - heightOfBar - statusStrip1.Height)) return; _needPaintAll = false; if (buffer == null || buffer.Width != Width || buffer.Height != Height) { buffer?.Dispose(); buffer = new Bitmap(Width, Height); } // 使用缓存绘制,避免在每次重绘时重新计算所有要绘制的元素 //if (bufferG == null) bufferG = Graphics.FromImage(buffer); using (var bufferG = Graphics.FromImage(buffer)) //using (var bufferG = e.Graphics) { // 先将控件的背景填充为白色 bufferG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; bufferG.Clear(Color.Transparent); bufferG.TranslateTransform(Width / 2, Height / 2); bufferG.ScaleTransform(Zoom.X, Zoom.Y); bufferG.TranslateTransform(-MapCenter.X, -MapCenter.Y); Draw(bufferG, _Template); if (_newTemplate.network != null) Draw(bufferG, _newTemplate); var r = 2f / zoom; if (_isDragging) { var _lastMousePosition = DragStartPos; // 绘制矩形 var start = new PointF((float)Math.Min(mousePosition.X, _lastMousePosition.X), (float)Math.Min(mousePosition.Y, _lastMousePosition.Y)); var size = new SizeF((float)Math.Abs(_lastMousePosition.X - mousePosition.X), (float)Math.Abs(_lastMousePosition.Y - mousePosition.Y)); var rectangle0 = new RectangleF(start, size); using (var pen = new Pen(Color.Black, 1 * r)) { bufferG.DrawRectangles(pen, new RectangleF[] { rectangle0 }); } } if (_isPainting) { using (var pen = new Pen(Color.Black, 1 * r)) { pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), _MousePosition); } } if (_isDrawingPolygon && polygonPoints.Count > 0) { List pf = polygonPoints.ToList(); pf.Add(new PointF(mousePosition.X, mousePosition.Y)); using (var pen = new Pen(Color.Black, 1 * r)) { // 绘制多边形虚线边框 pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; bufferG.DrawLines(pen, pf.ToArray()); } } if (_isSettingBackGroundPictur) { //var rightPos = MapPointToWorldPoint(mousePosition, _Template.BackGroundElev); //var Cps = new List //{ // BackGroudPicLeftPos, // new PointF(rightPos.X,BackGroudPicLeftPos.Y), // rightPos, // //new PointF(BackGroudPicLeftPos.X,rightPos.Y), //}; //var pen = new Pen(Color.Black, 1 * r); //List p = new List(); //Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, 0))); //var img = System.Drawing.Image.FromFile(_Template.BackGroundImg); //bufferG.FillPolygon(pen.Brush, p.ToArray()); //bufferG.DrawImage(img, p.ToArray()); var _lastMousePosition = DragStartPos; // 绘制矩形 var start = new PointF((float)Math.Min(mousePosition.X, _lastMousePosition.X), (float)Math.Min(mousePosition.Y, _lastMousePosition.Y)); var size = new SizeF((float)Math.Abs(_lastMousePosition.X - mousePosition.X), (float)Math.Abs(_lastMousePosition.Y - mousePosition.Y)); var rectangle0 = new RectangleF(start, size); using (var pen = new Pen(Color.Black, 1 * r)) { bufferG.DrawRectangles(pen, new RectangleF[] { rectangle0 }); } } if (_isMovingObject) { var newP = _MousePosition; //var p = MapPointToWorldPoint(, _OperaNode.Elev); var oldP3D = (PointF3D)_undoOldValue; var oldP = WorldPointToMapPoint(new PointF(oldP3D.X, oldP3D.Y), oldP3D.Z); List pf = new List { oldP, newP }; using (var pen = new Pen(Color.Black, 1 * r)) { // 绘制多边形虚线边框 pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; bufferG.DrawLines(pen, pf.ToArray()); } } } // 将生成的画布绘制到控件上 e.Graphics.DrawImage(buffer, 0, 0); } PointF[] getCurclePoints(int num) { PointF[] points = new PointF[num + 1]; float angle = 0; for (int i = 0; i < points.Length; i++) { float x = (float)Math.Cos(angle); float y = (float)Math.Sin(angle); points[i] = new PointF(x, y); angle += 2 * (float)Math.PI / num; } points[num] = points[0]; return points; } void Draw(Graphics bufferG, Template template) { if (template == null) return; var _Nodes = template.network.Nodes; var _Links = template.network.Links; var Cpoints = getCurclePoints(64).ToList(); var r = 1.73f / zoom; var rt = r; float minElve = float.MinValue; float maxElve = float.MaxValue; //if (this.mapOption!=null && this.mapOption.ShowFloor!=int.MinValue ) //{ // var fl = template.Floors.Find(f => f.FloorIndex == this.mapOption.ShowFloor); // var fl_1 = template.Floors.Find(f => f.FloorIndex == this.mapOption.ShowFloor+1); // if (fl!=null) // { // minElve = fl.Elev; // maxElve = fl_1!=null ? fl_1.Elev : float.MaxValue; // } //} r = r * Link_multiply; List diametersZoom = new List() { 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); //背景图绘制 if (this.mapOption.isShowPic && template != null && File.Exists(template.BackGroundImg_FullPath)) { //var gs = bufferG.Save(); // 应用矩阵变换以抵消之前的翻转效果 //bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y); // 恢复之前保存的绘图状态 var Cps = new List { template.BackGroundPoint1, new PointF(template.BackGroundPoint2.X,template.BackGroundPoint1.Y), new PointF(template.BackGroundPoint1.X,template.BackGroundPoint2.Y), //template.BackGroundPoint2, }; List p = new List(); Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet))); //bufferG.DrawImage(System.Drawing.Image.FromFile(@"C:\Users\cloud\Pictures\GenshinImpactCloudGame\QQ截图20230919105637.png"), p[0]); try { var img = System.Drawing.Image.FromFile(template.BackGroundImg_FullPath); if (img != null) { bufferG.FillPolygon(penN.Brush, p.ToArray()); bufferG.DrawImage(img, p.ToArray()); } } catch { } //bufferG.Restore(gs); } ////预处理节点 //List VisibleNodes = new List(); //foreach (NodeViewModel node in _Nodes) //{ // if (!node.Visible) continue; // if (node.Elev < minElve || node.Elev >= maxElve) continue; // float pr = (float)(r * 0.5); // pr = pr * junction_multiply; // PointF p = WorldPointToMapPoint(node, template.OffSet); // if (!isVisible(p)) continue; // PointF P_map = MapToScreen(p, node.Elev); // if ((int)(P_map.X/10)) //} // 绘制线 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; Pen pen = link.Status == Hydro.Core.ObjectEnum.StatusType.CLOSED ? penClosed : pen0; float zoomAtMin = 0; for (int i = 0; i < diametersZoom.Count; i++) { PointF point = diametersZoom[i]; if (link.Diameter >= point.X) continue; zoomAtMin = diametersZoom[i - 1].Y; break; } if (zoomAtMin >= zoom) continue; if (link is ValveViewModel) { if (link.Selected || _ShowValve) { var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 }); var valveShapeHeight = link.Selected ? 10 : 5; PointF[] points = new PointF[] { getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2), getRotatePoint(c.X - valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2), getRotatePoint(c.X + valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2), getRotatePoint(c.X + valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2), getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2), }; bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points); } } else if (link is PumpViewModel) { if (link.Selected || _ShowValve) { //var p1 = WorldPointToMapPoint(link.StartNode); //var p2 = WorldPointToMapPoint(link.EndNode); //var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); //bufferG.DrawLines(link.Selected ? valveChoosed : pen, new PointF[] { p1, p2 }); //PointF[] points = new PointF[] { // getRotatePoint(c.X - 3 * r, c.Y + 3 * r,c,p1,p2), // getRotatePoint(c.X - 3 * r, c.Y - 3 * r,c,p1,p2), // getRotatePoint(c.X + 3 * r, c.Y +0 * r,c,p1,p2), // getRotatePoint(c.X - 3 * r, c.Y + 3 * r,c,p1,p2), // //getRotatePoint(c.X - 3 * r, c.Y + 3 * r,c,p1,p2), //}; //bufferG.DrawLines(link.Selected ? valveChoosed : pen, points); var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); //bufferG.DrawLine(link.Selected ? pen_valveChoosed : pen, p1, p2); bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 }); // 绘制圆形部分(水泵的泵体) float radius = 5 * r; float diameter = radius * 2; #region 圆形拆分 //var p = new PointF[] //{ // getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2), // getRotatePoint(c.X + radius - radius, c.Y - radius, c, p1, p2), // getRotatePoint(c.X + radius - radius, c.Y + radius, c, p1, p2), // getRotatePoint(c.X - radius - radius, c.Y + radius, c, p1, p2), // getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2), //}; List p = new List(); Cpoints.ForEach(cp => p.Add(getRotatePoint(c.X + cp.X * radius - radius, c.Y + cp.Y * radius, c, p1, p2))); #endregion //RectangleF circleRect = new RectangleF(p[0].X, p[0].Y,p[1].X-p[0].X>0? diameter:-diameter,p[1].Y-p[0].Y>0? diameter:-diameter); //bufferG.FillEllipse(link.Selected ? pen_valveChoosed.Brush : pen.Brush, circleRect); bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray()); //// 绘制矩形部分(水泵的出口) //float rectangleWidth = 6*r; //float rectangleHeight = 2*r; //PointF rectTopLeft = new PointF(c.X - rectangleWidth / 2, c.Y + radius); //SizeF rectSize = new SizeF(rectangleWidth, rectangleHeight); //RectangleF rectangleRect = new RectangleF(rectTopLeft, rectSize); //bufferG.DrawRectangles(link.Selected ? pen_valveChoosed : pen,new RectangleF[] { rectangleRect }); // 绘制连接线 var valveShapeHeight = link.Selected ? radius * 2 : radius; PointF[] points = new PointF[] { getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2), getRotatePoint(c.X - valveShapeHeight , c.Y ,c,p1,p2), getRotatePoint(c.X + valveShapeHeight , c.Y ,c,p1,p2), getRotatePoint(c.X + valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2), getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2), }; bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points); } } else if (link is RepeaterViewModel re) { if (re.Status == RepeaterViewModel.RepeatStatus.收起 || _IsEditMode) { bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 }); var listNode = Get等分Nodes(p1, p2, Math.Max(re.RepeatTimes, 1)); for (int i = 0; i < listNode.Count; i++) { //foreach (var c in listNode) //{ var c = listNode[i]; RectangleF[] rects = new RectangleF[] { new RectangleF(c.X-10*r,c.Y-8*r,20*r,16*r), }; bufferG.FillRectangles(new SolidBrush(Color.White), rects); //bufferG.FillRectangles(link.Selected ? penChoosed.Brush : pen.Brush, new RectangleF[] //{ // new RectangleF(c.X-5*r,c.Y-5*r,3*r,3*r), // new RectangleF(c.X-5*r,c.Y+2*r,3*r,3*r), // new RectangleF(c.X+2*r,c.Y+2*r,3*r,3*r), // new RectangleF(c.X+2*r,c.Y-5*r,3*r,3*r), //}); // 保存当前绘图状态 var gs = bufferG.Save(); // 应用矩阵变换以抵消之前的翻转效果 bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y); int index = re.GetIndex(i); string indexString = index == 0 ? "" : index.ToString(); Font font = new Font(FontFamily.GenericSansSerif, 10); string text = $"{indexString}{re.NetworkShowName}"; SizeF textSize = bufferG.MeasureString(text, font); var center = new PointF(c.X * Zoom.X, c.Y * Zoom.Y); float textLeft = center.X - textSize.Width / 2; float textTop = center.Y - textSize.Height / 2; PointF p = new PointF(textLeft, textTop); bufferG.DrawString(text, font, link.Selected ? penChoosed.Brush : pen.Brush, p); // 恢复之前保存的绘图状态 bufferG.Restore(gs); if (textSize.Width / Zoom.X > rects[0].Width) { rects[0] = new RectangleF(c.X - textSize.Width / 2 / Zoom.X - 1 * r, c.Y - 8 * r, textSize.Width / Zoom.X + 2 * r, 16 * r); } try { bufferG.DrawRectangles(penN, rects); } catch { } } //var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); } //else //{ // DrawRepeater(bufferG,re); //} } else { if (link.StartNode == null || link.EndNode == null) continue; bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 }); } } } r = rt; //绘制点 penChoosed = new Pen(Color.Green, 1f * r); Brush brushChoosed = penChoosed.Brush; SolidBrush whiteBrush = new SolidBrush(Color.White); using (Pen pen = new Pen(Color.FromArgb(255, 0, 0), 1 * r)) { Brush brush = pen.Brush; foreach (NodeViewModel node in _Nodes) { if (!node.Visible) continue; if (node.Elev < minElve || node.Elev >= maxElve) continue; float pr = (float)(r * 0.5); pr = pr * junction_multiply; PointF p = WorldPointToMapPoint(node, template.OffSet); if (!isVisible(p)) continue; //var x = junction.Position.X * zoom + PanningOffset.X - radius / 2.0f; //var y = junction.Position.Y * zoom + PanningOffset.Y - radius / 2.0f; 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 || 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); 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); //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, rectangle); } else if (node.ID == _EndPoint) { var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr); bufferG.FillEllipse(whiteBrush, whiteRect); whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr); bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect); //whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr); //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, whiteRect); var p1 = new PointF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr); var p2 = new PointF(p1.X + 6 * pr, p1.Y + 6 * pr); bufferG.DrawLine(node.Selected ? penChoosed : pen, p1, p2); p1 = new PointF(rectangle.X + 2 * pr, rectangle.Y + 8 * pr); p2 = new PointF(p1.X + 6 * pr, p1.Y - 6 * pr); bufferG.DrawLine(node.Selected ? penChoosed : pen, p1, p2); //bufferG.FillEllipse(junction.Choosed ? brushChoosed : brush, rectangle); //var whiteRect = new RectangleF(rectangle.X + 1 * pr, rectangle.Y + 1 * pr, rectangle.Width - 2 * pr, rectangle.Height - 2 * pr); //bufferG.FillEllipse(whiteBrush, whiteRect); //whiteRect = new RectangleF(rectangle.X - 2 * pr, rectangle.Y - 2 * pr, rectangle.Width + 4 * pr, rectangle.Height + 4 * pr); //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, whiteRect); } else if (node is TankViewModel) { pr *= 2; rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr); RectangleF r0 = new RectangleF(rectangle.X, rectangle.Y + 5 * pr, 10 * pr, 5 * pr); RectangleF r1 = new RectangleF(rectangle.X + 2 * pr, rectangle.Y, 6 * pr, 5 * pr); bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r0); bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r1); } else if (node is ReservoirViewModel) { pr *= 2; rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr); RectangleF r0 = new RectangleF(rectangle.X, rectangle.Y + 2 * pr, rectangle.Width, 6 * pr); RectangleF r1 = new RectangleF(rectangle.X, rectangle.Y + 8 * pr, 1 * pr, 2 * pr); RectangleF r2 = new RectangleF(rectangle.X + 9 * pr, rectangle.Y + 8 * pr, 1 * pr, 2 * pr); bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r0); bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r1); bufferG.FillRectangle(node.Selected ? brushChoosed : brush, r2); } else if (node is MeterViewModel) { //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, rectangle); bufferG.FillEllipse(node.Selected ? brushChoosed : brush, rectangle); var whiteRect = new RectangleF(rectangle.X + 1 * pr, rectangle.Y + 1 * pr, rectangle.Width - 2 * pr, rectangle.Height - 2 * pr); bufferG.FillEllipse(whiteBrush, whiteRect); var p1 = new PointF(rectangle.X + 5 * pr, rectangle.Y); var p2 = new PointF(rectangle.X + 5 * pr, rectangle.Y + 10 * pr); bufferG.DrawLine(node.Selected ? penChoosed : pen, p1, p2); } else { if (node.Selected || _ShowJunction) bufferG.FillEllipse(node.Selected ? brushChoosed : brush, rectangle); } } } //r = r * Link_multiply; //using (Pen pen = new Pen(Color.FromArgb(0, 0, 255), 2 * r)) //{ // foreach (var link in _Links) // { // if (!link.Visible) continue; // if (!isVisible(WorldPointToMapPoint(link))) continue; // float zoomAtMin = 0; // for (int i = 0; i < diametersZoom.Count; i++) // { // PointF point = diametersZoom[i]; // if (link.Diameter >= point.X) continue; // zoomAtMin = diametersZoom[i - 1].Y; // break; // } // if (zoomAtMin >= zoom) continue; // if (link is Valve) // { // if (link.Selected) // { // var p1 = WorldPointToMapPoint(link.StartNode); // var p2 = WorldPointToMapPoint(link.EndNode); // var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); // bufferG.DrawLines(link.Selected ? valveChoosed : pen, new PointF[] { p1, p2 }); // bufferG.DrawLines(link.Selected ? valveChoosed : pen, new PointF[] { // getRotatePoint(c.X - 3 * r, c.Y + 3 * r,c,p1,p2), // getRotatePoint(c.X - 3 * r, c.Y - 2 * r,c,p1,p2), // getRotatePoint(c.X + 3 * r, c.Y + 2 * r,c,p1,p2), // getRotatePoint(c.X + 3 * r, c.Y - 2 * r,c,p1,p2), // getRotatePoint(c.X - 3 * r, c.Y + 2 * r,c,p1,p2), // }); // } // } // } //} } public List Get等分Nodes(PointF p1, PointF p2, int n) { // 计算线段长度 float len = (float)Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2)); if (len == 0) len = 0.00001f; // 计算单位向量 PointF u = new PointF((p2.X - p1.X) / len, (p2.Y - p1.Y) / len); // 计算间距 float d = len / (n + 1); // 计算n等分点 List nodes = new List(); for (int i = 1; i < n + 1; i++) { PointF node = new PointF(p1.X + i * d * u.X, p1.Y + i * d * u.Y); if (node.X == float.NaN || node.Y == float.NaN) node = p1; nodes.Add(node); } //nodes.RemoveAt(0); //nodes.RemoveAt(nodes.Count - 1); //// 绘制线段 //graphics.DrawLine(Pens.Black, p1, p2); //// 绘制3等分点和n等分点 //foreach (PointF node in node3) //{ // graphics.FillEllipse(Brushes.Red, node.X - 2, node.Y - 2, 4, 4); //} //foreach (PointF node in nodes) //{ // graphics.FillEllipse(Brushes.Blue, node.X - 2, node.Y - 2, 4, 4); //} return nodes; } private PointF getRotatePoint(float px, float py, PointF center, PointF x, PointF y) { PointF p = new PointF(px, py); return getRotatePoint(p, center, x, y); } private PointF[] getRotatePoints(PointF[] ps, PointF center, PointF x, PointF y) { return ps.ToList().Select(p => getRotatePoint(p, center, x, y)).ToArray(); } private PointF getRotatePoint(PointF p, PointF center, PointF x, PointF y) { float angle = (float)Math.Atan2(y.Y - x.Y, y.X - x.X); float distance = (float)Math.Sqrt(Math.Pow(p.X - center.X, 2) + Math.Pow(p.Y - center.Y, 2)); float rotationAngle = (float)(Math.Atan2(p.Y - center.Y, p.X - center.X) + angle); float rotatedX = center.X + distance * (float)Math.Cos(rotationAngle); float rotatedY = center.Y + distance * (float)Math.Sin(rotationAngle); return new PointF(rotatedX, rotatedY); } public new void Invalidate() { base.Invalidate(); _needPaintAll = true; PMin_Show = ScreenToMap(new PointF(0, Height)); PMax_Show = ScreenToMap(new PointF(Width, 0)); } protected override void OnResize(EventArgs e) { base.OnResize(e); // 当控件尺寸改变时,触发重绘 this.Invalidate(); } #endregion #region 鼠标事件 public PointF mouseXY = new PointF(0, 0); PointF DragStartPos; PointF _ClickStartPos; PointF RotaStartPos; PointF BackGroudPicLeftPos; bool _isPanning; bool _isDragging; bool _isRotating; bool _isPainting; public List selectedObjs = new List(); private List selectedNodes => selectedObjs.FindAll(o => o is NodeViewModel).Select(o => (NodeViewModel)o).ToList(); private List selectedLinks => selectedObjs.FindAll(o => o is LinkViewModel).Select(o => (LinkViewModel)o).ToList(); private NodeViewModel _OperaNode = null; PointF mousePosition; // control+鼠标中间按下缩放 bool _isInsertingObject = false; bool _isMovingObject = false; bool _isPastingObject = false; Cursor _lastCursor; object _undoOldValue = null; private List polygonPoints = new List(); public bool Lock2DView = false; private bool _isDrawingPolygon; protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); _ClickStartPos = new PointF(e.X, e.Y); if (e.Button == MouseButtons.Left && _isInsertingObject) { } else if (e.Button == MouseButtons.Middle || e.Button == MouseButtons.XButton2) { if (ModifierKeys == Keys.Control || ModifierKeys == Keys.Shift)//按下框选放大 { DragStartPos = ScreenToMap(new PointF(e.X, e.Y)); _isDragging = true; } else { _lastCursor = this.Cursor; this.Cursor = Cursors.SizeAll; MapCenter0 = MapCenter; mapOption0 = mapOption.Copy(); _isPanning = true; } } else if (e.Button == MouseButtons.Left && _mouseState == MouseState.无) { if (ModifierKeys == Keys.Shift) { var point = ScreenToMap(new PointF(e.X, e.Y)); if (!_isDrawingPolygon) { // 开始绘制多边形 polygonPoints.Clear(); _isDrawingPolygon = true; } polygonPoints.Add(point); mousePosition = _MousePosition = ScreenToMap(new PointF(e.X, e.Y)); Invalidate(); return; } if (_isDrawingPolygon) { return; } //移动 if (selectedObjs.Count >= 1) //&& selectedObjs[0].isNode()) { List nodes = selectedNodes; foreach (NodeViewModel node in nodes) { PointF mapPos = WorldPointToMapPoint(node); PointF currentPoint = MapToScreen(mapPos); if (Get_dist(new PointF(e.X, e.Y), currentPoint) < 15f) { _NewNet.Nodes.AddRange(selectedNodes); _NewNet.Links.AddRange(selectedLinks); _isMovingObject = true; _OperaNode = node; _undoOldValue = node.Position3D; break; } } } if (!_isMovingObject) { DragStartPos = ScreenToMap(new PointF(e.X, e.Y)); _isDragging = true; } } else if (e.Button == MouseButtons.Left && _mouseState == MouseState.设置底图范围) { _mouseState = MouseState.无; DragStartPos = ScreenToMap(new PointF(e.X, e.Y)); BackGroudPicLeftPos = MapPointToWorldPoint(ScreenToMap(new PointF(e.X, e.Y)), _Template.BackGroundElev); _isSettingBackGroundPictur = true; } else if (e.Button == MouseButtons.Right) { RotaStartPos = new PointF(e.X, e.Y); Rotation0 = Rotation; 俯视角度_start = RotationF; _lastCursor = this.Cursor; Cursor = Cursors.Hand; mapOption0 = mapOption.Copy(); _isRotating = true; } } private bool IsPointInPolygon(PointF point, List polygon) { int count = polygon.Count; bool inside = false; PointF p1, p2; for (int i = 0, j = count - 1; i < count; j = i++) { p1 = polygon[i]; p2 = polygon[j]; if (((p1.Y > point.Y) != (p2.Y > point.Y)) && (point.X < (p2.X - p1.X) * (point.Y - p1.Y) / (p2.Y - p1.Y) + p1.X)) { inside = !inside; } } return inside; } //protected override void OnMouseDoubleClick(MouseEventArgs e) //{ // //base.OnMouseDoubleClick(e); //} public void InsertNet(Template temp) { _isInsertingObject = true; _newTemplate = temp; _undoOldValue = new PointF3D(0, 0, 0); _OperaNode = temp.network.Nodes.Find(node => node.ID == temp.Node1); //if (_OperaNode == null) _OperaNode=_NewNet.Nodes[0]; } bool controlDown = false; PointF _MousePosition = new PointF(0, 0); protected override void OnMouseMove(MouseEventArgs e) { //base.OnMouseMove(e); bool needInvalidate = false; _MousePosition = ScreenToMap(new PointF(e.X, e.Y)); if (_isMovingObject) { var p = MapPointToWorldPoint(_MousePosition, _OperaNode.Elev); var oldP = (PointF3D)_undoOldValue; if (!float.IsInfinity(p.X) && !float.IsInfinity(p.Y)) _newTemplate.OffSet = new PointF3D(p.X - oldP.X, p.Y - oldP.Y, 0); //_OperaNode.Position = p; GlobalObject.PropertyForm.propertyGrid.Refresh(); needInvalidate = true; } else if (_isPainting) { needInvalidate = true; } else if (_isPanning) { var vector = GetRotateVector(new PointF(e.X, e.Y), new PointF(_lastMouseX, _lastMouseY)); MapCenter = new PointF(MapCenter.X - vector.X / Zoom.X, MapCenter.Y - vector.Y / Zoom.Y); label_center.Text = $"center:({MapCenter.X.ToString("0.000")} ,{MapCenter.Y.ToString("0.000")})"; needInvalidate = true; } else if (_isDragging || _isDrawingPolygon || _isSettingBackGroundPictur) { mousePosition = _MousePosition; // 绘制选择框 // Rectangle selectionRect = new Rectangle( // Math.Min((int)DragStartPos.X, (int)MP.X), // Math.Min((int)DragStartPos.Y, (int)MP.Y), // Math.Abs((int)DragStartPos.X - (int)MP.X), // Math.Abs((int)DragStartPos.Y - (int)MP.Y)); //DrawSelectionRect(selectionRect); needInvalidate = true; } else if (_isRotating) { mousePosition = _MousePosition; bool is下半屏幕 = RotaStartPos.Y >= this.Height / 2; if (ModifierKeys != Keys.Alt) Rotation = Rotation0 + ((float)e.X - (float)RotaStartPos.X) * 180 * 2.5 / (float)this.Width * (is下半屏幕 ? 1 : 1); if (ModifierKeys != Keys.Shift) RotationF = 俯视角度_start + ((float)e.Y - (float)RotaStartPos.Y) * 180 * 2.5 / (float)this.Height; if (RotationF > 90) RotationF = 90; if (RotationF < 0) RotationF = 0; needInvalidate = true; } if (_isInsertingObject) { var p = MapPointToWorldPoint(_MousePosition, _OperaNode.Elev); var oldP = (PointF3D)_undoOldValue; if (!float.IsInfinity(p.X) && !float.IsInfinity(p.Y)) _newTemplate.OffSet = new PointF3D(p.X - oldP.X, p.Y - oldP.Y, 0); //_OperaNode.Position = p; GlobalObject.PropertyForm.propertyGrid.Refresh(); needInvalidate = true; } if (needInvalidate) this.Invalidate(); label_mouse.Text = $"X:{e.X.ToString("0")} Y:{e.Y.ToString("0")} [Map]X:{_MousePosition.X.ToString("0.00")} Y:{_MousePosition.Y.ToString("0.00")}"; _lastMouseX = e.X; _lastMouseY = e.Y; } bool RectangContain(RectangleF r, PointF p) { var x = p.X; var y = p.Y; if (r.X <= x && x < r.X + r.Width && r.Y <= y) { return y < r.Y + r.Height; } return false; } /// /// 用于绘制管线 /// NodeViewModel _select_junction1 = null; NodeViewModel _select_junction2 = null; DateTime _lastMouseUp = DateTime.Now; int doubleClick_Delay = 500;//毫秒 bool recordView = false; protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); bool isMouseMoved = Get_dist(_ClickStartPos, new PointF(e.X, e.Y)) > 10; bool isdoubleClick = (DateTime.Now - _lastMouseUp).TotalMilliseconds <= doubleClick_Delay; _lastMouseUp = DateTime.Now; if (e.Button == MouseButtons.Middle || e.Button == MouseButtons.XButton2) { if (ModifierKeys == Keys.Control) { _isDragging = false; this.Cursor = _lastCursor; mapOption0 = mapOption; var _lastMousePosition = DragStartPos; List objs = new List(); // 绘制矩形 var start = new Point((int)Math.Min(mousePosition.X, _lastMousePosition.X), (int)Math.Min(mousePosition.Y, _lastMousePosition.Y)); var size = new Size((int)Math.Abs(_lastMousePosition.X - mousePosition.X), (int)Math.Abs(_lastMousePosition.Y - mousePosition.Y)); var rectangle0 = new Rectangle(start, size); var new_center = MapPointToWorldPoint(new PointF(start.X + size.Width / 2, start.Y + size.Height / 2)); this.MapCenter = new_center; this.zoom = Math.Max(1.0f * Width / size.Width, 1.0f * Height / size.Height); if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); label_center.Text = $"center:({MapCenter.X.ToString("0.000")} ,{MapCenter.Y.ToString("0.000")})"; label_zoom.Text = $"Zoom:{zoom.ToString("0.000")}"; Invalidate(); } if (ModifierKeys == Keys.Shift) { _isDragging = false; this.Cursor = _lastCursor; var _lastMousePosition = DragStartPos; List objs = new List(); // 绘制矩形 var start = new Point((int)Math.Min(mousePosition.X, _lastMousePosition.X), (int)Math.Min(mousePosition.Y, _lastMousePosition.Y)); var size = new Size((int)Math.Abs(_lastMousePosition.X - mousePosition.X), (int)Math.Abs(_lastMousePosition.Y - mousePosition.Y)); var rectangle0 = new Rectangle(start, size); for (int i = 0; i < _Nodes.Count; i++) { PointF p = WorldPointToMapPoint(_Nodes[i]); if (rectangle0.Contains(p.ToPoint())) { //_Nodes[i].Selected = true; //selectedObjs.Add(_Nodes[i]); objs.Add(_Nodes[i]); } } for (int i = 0; i < _Links.Count; i++) { //PointF p = GetPointF(Pipes[i]); if (rectangle0.Contains(_Links[i].Position.ToPoint())) { //_Links[i].Selected = true; //selectedObjs.Add(_Links[i]); objs.Add(_Links[i]); } } Form_Magnifier fr = new Form_Magnifier(objs); fr.ShowDialog(); } else { if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); this.Cursor = _lastCursor; _isPanning = false; } } else if (e.Button == MouseButtons.Left && _isSettingBackGroundPictur == true) { _Template.BackGroundPoint1 = BackGroudPicLeftPos; _Template.BackGroundPoint2 = MapPointToWorldPoint(mousePosition, _Template.BackGroundElev); _isSettingBackGroundPictur = false; mapOption.isShowPic = true; this.Cursor = _lastCursor; Invalidate(); } else if (e.Button == MouseButtons.Left) { if (_isInsertingObject) { var net = _newTemplate.network; //_OperaNode = net.EndPoint; //_OperaNode = _NewNet.Nodes.Find(node => node.ID == temp.Node2); //if (_OperaNode == null) _OperaNode = _NewNet.Nodes[0]; //PointF minPoint = new PointF(net.StartPoint.X, net.StartPoint.Y); List nodes = _Nodes; float minDist = 100f; NodeViewModel minNode = null; foreach (NodeViewModel node in nodes) { PointF mapPos = WorldPointToMapPoint(node); PointF currentPoint = MapToScreen(mapPos); float currentDist = 0; if (node != _OperaNode && (currentDist = Get_dist(new PointF(e.X, e.Y), currentPoint)) < 15f) { if (currentDist < minDist) currentDist = minDist; minNode = node; break; } } float dx, dy, dz; if (ModifierKeys != Keys.Alt && minNode != null) { var p1 = (PointF3D)_undoOldValue; var p2 = minNode.Position3D; var dd = _newTemplate.OffSet; dx = p2.X - p1.X; dy = p2.Y - p1.Y; dz = p2.Z - p1.Z; } else { _NewNet.Clear(); _OperaNode = null; _isInsertingObject = false; this.Invalidate(); return; var p1 = (PointF3D)_undoOldValue; var p2 = _OperaNode.Position3D; var dd = _newTemplate.OffSet; dx = dd.X; //p2.X - p1.X; dy = dd.Y;// p2.Y - p1.Y; dz = dd.Z;// p2.Z - p1.Z; } net.Nodes.ForEach(n => { n.Position3D = new PointF3D(n.X + dx, n.Y + dy, n.Elev + dz); }); var list = _Network.Add(net); var j = _Network.AddPipe(minNode, _OperaNode); j.Length = 0.0001f; list.Add(j); _OperaNode = null; _NewNet.Clear(); _Network.BuildRelation(); selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); list.ForEach(m => m.Selected = true); selectedObjs.AddRange(list); MapObjectExtensions.AddCommand(_Network, "Add", null, list); _isInsertingObject = false; //_OperaNode = null; //_Network.Nodes.AddRange(net.Nodes); //_Network.Links.AddRange(net.Links); Invalidate(); } else if (_isDrawingPolygon) { if (ModifierKeys != Keys.Shift) { _isDrawingPolygon = false; if (polygonPoints.Count >= 3) { _Nodes.ForEach(n => { if (IsPointInPolygon(WorldPointToMapPoint(n), polygonPoints)) { selectedObjs.Add(n); n.Selected = true; } }); _Links.ForEach(n => { if (IsPointInPolygon(WorldPointToMapPoint(n.Position, n.Elev), polygonPoints)) { selectedObjs.Add(n); n.Selected = true; } }); } Invalidate(); // 结束绘制多边形 } } else if (_isMovingObject) { if (isMouseMoved) { List nodes = _Nodes; float minDist = 100f; NodeViewModel minNode = null; foreach (NodeViewModel node in nodes) { PointF mapPos = WorldPointToMapPoint(node); PointF currentPoint = MapToScreen(mapPos); float currentDist = 0; if (node != _OperaNode && (currentDist = Get_dist(new PointF(e.X, e.Y), currentPoint)) < 15f) { if (currentDist < minDist) currentDist = minDist; minNode = node; break; } } if (ModifierKeys != Keys.Alt && minNode != null) { _isMovingObject = false; var p1 = (PointF3D)_undoOldValue; var p2 = minNode.Position3D; var dd = _newTemplate.OffSet; var dx = p2.X - p1.X; var dy = p2.Y - p1.Y; var dz = p2.Z - p1.Z; selectedNodes.ForEach(n => { n.Position3D = new PointF3D(n.X + dx, n.Y + dy, n.Elev + dz); }); List newPositons = selectedNodes.Select(n => n.Position3D).ToList(); List oldPositons = newPositons.Select(n => new PointF3D(n.X - dx, n.Y - dy, n.Z - dz)).ToList(); MapObjectExtensions.AddCommand(selectedNodes, "Position3D", oldPositons, newPositons); _OperaNode = null; _NewNet.Clear(); } else { _isMovingObject = false; var p1 = (PointF3D)_undoOldValue; var p2 = _OperaNode.Position3D; var dd = _newTemplate.OffSet; var dx = dd.X; //p2.X - p1.X; var dy = dd.Y;// p2.Y - p1.Y; var dz = dd.Z;// p2.Z - p1.Z; selectedNodes.ForEach(n => { n.Position3D = new PointF3D(n.X + dx, n.Y + dy, n.Elev + dz); }); List newPositons = selectedNodes.Select(n => n.Position3D).ToList(); List oldPositons = newPositons.Select(n => new PointF3D(n.X - dx, n.Y - dy, n.Z - dz)).ToList(); MapObjectExtensions.AddCommand(selectedNodes, "Position3D", oldPositons, newPositons); _OperaNode = null; _NewNet.Clear(); } } else { _isMovingObject = false; var p1 = (PointF3D)_undoOldValue; var p2 = _OperaNode.Position3D; var dd = _newTemplate.OffSet; var dx = dd.X; //p2.X - p1.X; var dy = dd.Y;// p2.Y - p1.Y; var dz = dd.Z;// p2.Z - p1.Z; //selectedNodes.ForEach(n => { n.Position3D = new PointF3D(n.X + dx, n.Y + dy, n.Elev + dz); }); //List newPositons = selectedNodes.Select(n => n.Position3D).ToList(); //List oldPositons = newPositons.Select(n => new PointF3D(n.X - dx, n.Y - dy, n.Z - dz)).ToList(); //MapObjectExtensions.AddCommand(selectedNodes, "Position3D", oldPositons, newPositons); _OperaNode = null; _NewNet.Clear(); } } else if (_mouseState != MouseState.无) { PointF p; float z; NodeViewModel n; switch (_mouseState) { case MouseState.新增节点: getPointAndHeight(e, out p, out z); n = _Network.AddJunction(p, z); MapObjectExtensions.AddCommand(_Network, "Add", null, new List() { n }); break; case MouseState.新建水表: getPointAndHeight(e, out p, out z); n = _Network.AddMeter(p); MapObjectExtensions.AddCommand(_Network, "Add", null, new List() { n }); break; case MouseState.新建水库: getPointAndHeight(e, out p, out z); n = _Network.AddReservoir(p); MapObjectExtensions.AddCommand(_Network, "Add", null, new List() { n }); break; case MouseState.新建水池: getPointAndHeight(e, out p, out z); n = _Network.AddTank(p); MapObjectExtensions.AddCommand(_Network, "Add", null, new List() { n }); break; case MouseState.新增管线: case MouseState.新建水泵: case MouseState.新建阀门: case MouseState.新建重复器: if (_select_junction1 == null) { getPointAndHeight(e, out p, out z); Set_junction1(e); } else { getPointAndHeight(e, _select_junction1, out p, out z); var l = AddLink(e, isdoubleClick, p, z); if (l.Count > 0) MapObjectExtensions.AddCommand(_Network, "Add", null, l); } break; } Invalidate(); } else if (isMouseMoved) { _isDragging = false; Cursor = Cursors.Default; 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); if (ModifierKeys == Keys.Control) { for (int i = 0; i < _Nodes.Count; i++) { if (!_Nodes[i].Visible) continue; PointF p = WorldPointToMapPoint(_Nodes[i]); if (RectangContain(rectangle0, p)) { if (selectedObjs.Contains(_Nodes[i])) { _Nodes[i].Selected = false; selectedObjs.Remove(_Nodes[i]); } else { _Nodes[i].Selected = true; selectedObjs.Add(_Nodes[i]); } } } for (int i = 0; i < _Links.Count; i++) { if (!_Links[i].Visible) continue; PointF p = WorldPointToMapPoint(_Links[i].Position, _Links[i].Elev); if (RectangContain(rectangle0, p)) { if (selectedObjs.Contains(_Links[i])) { _Links[i].Selected = false; selectedObjs.Remove(_Links[i]); } else { _Links[i].Selected = true; selectedObjs.Add(_Links[i]); } } } GlobalObject.PropertyForm.SetObjs(selectedObjs); Invalidate(); mousePosition = new PointF(0, 0); } else { selectedObjs.ForEach(obj => obj.Selected = false); selectedObjs.Clear(); for (int i = 0; i < _Nodes.Count; i++) { if (!_Nodes[i].Visible) continue; PointF p = WorldPointToMapPoint(_Nodes[i]); if (RectangContain(rectangle0, p)) { _Nodes[i].Selected = true; selectedObjs.Add(_Nodes[i]); } } for (int i = 0; i < _Links.Count; i++) { if (!_Links[i].Visible) continue; PointF p = WorldPointToMapPoint(_Links[i].Position, _Links[i].Elev); if (RectangContain(rectangle0, p)) { _Links[i].Selected = true; selectedObjs.Add(_Links[i]); } } GlobalObject.PropertyForm.SetObjs(selectedObjs); Invalidate(); mousePosition = new PointF(0, 0); } } else { _isDragging = false; // 遍历所有点,找出最近的点 PointF clickedPoint = new PointF(e.X, e.Y); //ScreenToMap(new PointF(e.X, e.Y)); var obj = GetObj_by_ScreenPoint(clickedPoint); bool isJunction = obj is NodeViewModel; if (ModifierKeys == Keys.Control) { if (obj != null) { if (selectedObjs.Contains(obj)) { obj.Selected = false; selectedObjs.Remove(obj); GlobalObject.PropertyForm.SetObjs(selectedObjs); Invalidate(); mousePosition = new PointF(0, 0); } else { obj.Selected = true; selectedObjs.Add(obj); GlobalObject.PropertyForm.SetObjs(selectedObjs); Invalidate(); mousePosition = new PointF(0, 0); } } } else { if (obj != null) { //if (isJunction) { selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); _OperaNode = null; obj.Selected = true; selectedObjs.Add(obj); //Invalidate(); //// 显示该点的属性 //ShowProperties(obj); GlobalObject.PropertyForm.SetObjs(selectedObjs); Invalidate(); mousePosition = new PointF(0, 0); } //else //{ // ChoosedObjs.ForEach(o => o.Choosed = false); // ChoosedObjs.Clear(); // obj.Choosed = true; // ChoosedObjs.Add(obj); // Invalidate(); // // 显示该点的属性 // ShowProperties(obj); //} } else { selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); _OperaNode = null; GlobalObject.PropertyForm.SetObjs(selectedObjs); Invalidate(); } } } //zoom *= (float)Math.Pow(2, e.Delta / 120.0 / 10.0); //zoom = Math.Max(0.1f, Math.Min(10.0f, zoom)); //center.X += e.Location.X / oldZoom - e.Location.X / zoom; //center.Y += e.Location.Y / oldZoom - e.Location.Y / zoom; label_center.Text = $"center:({MapCenter.X.ToString("0.000")} ,{MapCenter.Y.ToString("0.000")})"; label_zoom.Text = $"Zoom:{zoom.ToString("0.000")}"; Invalidate(); } else if (e.Button == MouseButtons.Right) { if (_isRotating) { _isRotating = false; this.Cursor = _lastCursor; if (!isMouseMoved) { 右键_Menu.Show(this, e.Location); 转换为ToolStripMenuItem.Enabled = selectedNodes.Count > 0; //(selectedObjs.Count == 1); 删除ToolStripMenuItem.Enabled = selectedObjs.Count > 0; } if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); mousePosition = new PointF(0, 0); } } } private void getPointAndHeight(MouseEventArgs e, out PointF p, out float z) { z = 0; if (RotationF != 0) { p = MapPointToWorldPoint(ScreenToMap(new PointF(e.X, e.Y), z)); } else { var m = ScreenToVMap(new PointF(e.X, e.Y)); z = m.Y; p = new PointF(m.X, 0); } } private void getPointAndHeight(MouseEventArgs e, NodeViewModel j, out PointF p, out float z) { z = j.Elev; if (RotationF != 0) { p = MapPointToWorldPoint(ScreenToMap(new PointF(e.X, e.Y), j.Elev), j.Elev); } else { var m = ScreenToVMap(new PointF(e.X, e.Y)); z = m.Y; p = new PointF(j.X, j.Y); } } IBaseViewModel GetObj_by_ScreenPoint(PointF clickedPoint) { float minDist = float.MaxValue; float DistLimit = 15f; int minIndex = -1; bool isJunction = true; IBaseViewModel obj = null; for (int i = 0; i < _Nodes.Count; i++) { if (!_Nodes[i].Visible) continue; PointF mapPos = WorldPointToMapPoint(_Nodes[i]); PointF currentPoint = MapToScreen(mapPos); float dist = Get_dist(clickedPoint, currentPoint); if (dist < minDist && dist <= DistLimit) { minDist = dist; minIndex = i; obj = _Nodes[i]; } } for (int i = 0; i < _Links.Count; i++) { if (!_Links[i].Visible) continue; //float dist = (clickedPoint.X - Pipes[i].X) * (clickedPoint.X - Pipes[i].X) + // (clickedPoint.Y - Pipes[i].Y) * (clickedPoint.Y - Pipes[i].Y); PointF mapPos = WorldPointToMapPoint(_Links[i].Position, _Links[i].Elev); PointF currentPoint = MapToScreen(mapPos); float dist = Get_dist(clickedPoint, currentPoint); if (dist < minDist && dist <= DistLimit) { minDist = dist; minIndex = i; isJunction = false; obj = _Links[i]; } } return obj; } protected override void OnMouseWheel(MouseEventArgs e) { base.OnMouseWheel(e); mapOption0 = mapOption.Copy(); float oldZoom = zoom; zoom *= (float)Math.Pow(2, e.Delta / 120.0 / 10.0); zoom = Math.Max(MinZoom, Math.Min(MaxZoom, zoom)); //center.X += e.Location.X / oldZoom - e.Location.X / zoom; //center.Y += e.Location.Y / oldZoom - e.Location.Y / zoom; if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); Invalidate(); } private int _lastMouseX; private int _lastMouseY; #endregion #endregion 一、全局 #region 二、工具栏 #region 视角工具 // 显示点属性 private void ShowProperties(IBaseViewModel obj) { string str = "point"; // TODO: 根据需要实现 if (obj is LinkViewModel) str = "pipe"; //MessageBox.Show($"{str}:({obj.X.ToString("0.000")} ,{obj.Y.ToString("0.000")})"); //label_choose.Text = $"{str}[{obj.ID}]({obj.X.ToString("0.000")},{obj.Y.ToString("0.000")})"; GlobalObject.PropertyForm.SetObj(obj); } private void label_center_Click(object sender, EventArgs e) { GlobalObject.PropertyForm.SetObj(MapCenter); } double 俯视角度_bak = 45; private void tool视角_ButtonClick(object sender, EventArgs e) { mapOption0 = mapOption.Copy(); if (RotationF == 90) { RotationF = 俯视角度_bak; } else { 俯视角度_bak = RotationF; RotationF = 90; } if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); Invalidate(); } private void tool设置俯视角度_Click(object sender, EventArgs e) { mapOption0 = mapOption.Copy(); double jiaodu = 45; var tool = sender as ToolStripItem; jiaodu = Convert.ToDouble(tool.Text); RotationF = jiaodu; if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); Invalidate(); } public void 重置视角ToolStripMenuItem_Click(object sender, EventArgs e) { mapOption0 = mapOption.Copy(); RotationF = 90; Rotation = 0; InitCenter(); if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); Invalidate(); } private void 正视图ToolStripMenuItem_Click(object sender, EventArgs e) { mapOption0 = mapOption.Copy(); RotationF = 0; if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); Invalidate(); } private void 俯视图ToolStripMenuItem_Click(object sender, EventArgs e) { mapOption0 = mapOption.Copy(); RotationF = 90; MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); Invalidate(); } private void 设为隐藏ToolStripMenuItem_Click(object sender, EventArgs e) { selectedObjs.ForEach(v => { if (v.Visible) { MapObjectExtensions.AddCommand(v, "Visible", v.Visible, false); v.Visible = false; } }); this.Invalidate(); } private void 设置长度ToolStripMenuItem_Click(object sender, EventArgs e) { double length = 0; DialogResult result; InputBox input = new InputBox("输入长度"); if (selectedObjs.Count == 1 && selectedObjs[0] is LinkViewModel l) { if (double.TryParse(input.ShowDialog(), out length)) { var count1 = _Links.FindAll(ll => ll.Node1 == l.StartNode.ID || ll.Node2 == l.StartNode.ID).Count; var count2 = _Links.FindAll(ll => ll.Node1 == l.EndNode.ID || ll.Node2 == l.EndNode.ID).Count; if (count1 > 1 && count2 <= 1) { MovePointbyLength(l.StartNode, l.EndNode, (float)length); } else if (count2 > 1 && count1 <= 1) { MovePointbyLength(l.EndNode, l.StartNode, (float)length); } else { MovePointbyLength(l.StartNode, l.EndNode, (float)length); } Invalidate(); } } this.Invalidate(); } void MovePointbyLength(NodeViewModel node1, NodeViewModel node2, float Length) { float distance = Vector3.Distance(new Vector3(node1.X, node1.Y, node1.Elev), new Vector3(node2.X, node2.Y, node2.Elev)); if (distance > 0) { // 如果 A 和 B 不是同一个点 // 计算要移动多少距离 float moveDistance = Length - distance; // 计算向量 AB(从 A 指向 B) Vector3 AB = new Vector3(node2.X - node1.X, node2.Y - node1.Y, node2.Elev - node1.Elev); // 计算 AB 的单位向量 Vector3 unitAB = Vector3.Normalize(AB); // 计算需要移动的距离的向量(与 AB 方向相同) Vector3 moveVector = unitAB * moveDistance; // 更新点 B 的坐标 node2.X += moveVector.X; node2.Y += moveVector.Y; node2.Elev += moveVector.Z; // 输出移动后的点 B 坐标 //Console.WriteLine("移动后点 B 的坐标为 ({0}, {1}, {2})", x2, y2, z2); } } private void 全部显示ToolStripMenuItem_Click(object sender, EventArgs e) { _Nodes.ForEach(v => { if (!v.Visible) { MapObjectExtensions.AddCommand(v, "Visible", v.Visible, true); v.Visible = true; } }); _Links.ForEach(v => { if (!v.Visible) { MapObjectExtensions.AddCommand(v, "Visible", v.Visible, true); v.Visible = true; } }); this.Invalidate(); } #endregion #region 文件工具 private void tool打开_ButtonClick(object sender, EventArgs e) { // 创建打开文件对话框 OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Filter = "INP Files (*.inp)|*.inp|All Files (*.*)|*.*"; if (openFileDialog.ShowDialog() == DialogResult.OK) { _Template = new Template(); _Template.network = new MapViewNetWork(); //_Template.network.use_old = false; // 获取选中文件的文件路径 string filePath = openFileDialog.FileName; { // 读取文件内容 _Network.BuildFromInp(filePath); _Template.filePath = filePath; //_filePath = filePath; SetData(_Template); } } } private void 旧版打开ToolStripMenuItem_Click(object sender, EventArgs e) { // 创建打开文件对话框 OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Filter = "INP Files (*.inp)|*.inp|All Files (*.*)|*.*"; if (openFileDialog.ShowDialog() == DialogResult.OK) { _Template = new Template(); _Template.network = new MapViewNetWork(); //_Template.network.use_old = true; // 获取选中文件的文件路径 string filePath = openFileDialog.FileName; { // 读取文件内容 _Network.BuildFromInp(filePath); _Template.filePath = filePath; //_filePath = filePath; SetData(_Template); } } } private void 打开文件位置ToolStripMenuItem_Click(object sender, EventArgs e) { if (_filePath == null) return; FileInfo fi = new FileInfo(_filePath); Process.Start("explorer.exe", $"/select,\"{_filePath}\""); //System.Diagnostics.Process.Start("explorer.exe", fi.Directory.FullName); } private void EPA中打开ToolStripMenuItem_Click(object sender, EventArgs e) { if (_filePath == null) return; Process.Start(@"epanetH\Epanet2wH.exe", _filePath); } private void 保存ToolStripMenuItem_Click(object sender, EventArgs e) { if (!_IsEditMode) { if (message.show("提醒", "浏览模式无法保存,是否恢复为编辑模式")) { _IsEditMode = true; } else return; } else _Network.BuildToInp(_filePath); } private void toolStripButton_save_Click(object sender, EventArgs e) { } private void 另存ToolStripMenuItem_Click(object sender, EventArgs e) { } private void 导出形状ToolStripMenuItem_Click(object sender, EventArgs e) { } #endregion #region 绘图工具 MouseState _mouseState = MouseState.无; public void toolStripButton_新建节点_Click(object sender, EventArgs e) { _mouseState = MouseState.新增节点; Cursor = Cursors.Cross; } public void toolStripButton_普通_Click(object sender, EventArgs e) { _mouseState = MouseState.无; Cursor = Cursors.Default; } public void toolStripButton_新建管线_Click(object sender, EventArgs e) { _mouseState = MouseState.新增管线; Cursor = Cursors.Cross; } private List AddLink(MouseEventArgs e, bool isdoubleClick, PointF p, float z) { List l = new List(); var node = GetObj_by_ScreenPoint(new PointF(e.X, e.Y)); if (node != null || isdoubleClick) { if (node != null && node is NodeViewModel j) { _select_junction2 = j; } else if (isdoubleClick) { _select_junction2 = _Network.AddJunction(p, z); l.Add(_select_junction2); } if (_mouseState == MouseState.新增管线) l.Add(_Network.AddPipe(_select_junction1, _select_junction2)); else if (_mouseState == MouseState.新建阀门) l.Add(_Network.AddValve(_select_junction1, _select_junction2)); else if (_mouseState == MouseState.新建重复器) l.Add(_Network.AddRepeater(_select_junction1, _select_junction2)); else if (_mouseState == MouseState.新建水泵) l.Add(_Network.AddPump(_select_junction1, _select_junction2)); _select_junction1 = null; _select_junction2 = null; _isPainting = false; } return l; } private void Set_junction1(MouseEventArgs e) { var node = GetObj_by_ScreenPoint(new PointF(e.X, e.Y)); if (node != null && node is NodeViewModel j) { _select_junction1 = j; _isPainting = true; } } public void toolStripButton_添加水表_Click(object sender, EventArgs e) { _mouseState = MouseState.新建水表; Cursor = Cursors.Cross; } public void toolStripButton_添加阀门_Click(object sender, EventArgs e) { _mouseState = MouseState.新建阀门; Cursor = Cursors.Cross; } public void toolStripButton_添加水泵_Click(object sender, EventArgs e) { _mouseState = MouseState.新建水泵; Cursor = Cursors.Cross; } public void toolStripButton_添加水库_Click(object sender, EventArgs e) { _mouseState = MouseState.新建水库; Cursor = Cursors.Cross; } public void toolStripButton_添加水池_Click(object sender, EventArgs e) { _mouseState = MouseState.新建水池; Cursor = Cursors.Cross; } public void toolStripButton_重复器_Click(object sender, EventArgs e) { _mouseState = MouseState.新建重复器; Cursor = Cursors.Cross; } bool Buzylock = false; private void MapViewer_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Escape) { Cursor = _lastCursor; if (_isPainting) { _select_junction1 = null; _isPainting = false; Invalidate(); } else if (_isDragging) { _isDragging = false; Invalidate(); } else if (_isPanning) { _isPanning = false; Invalidate(); } else if (_isRotating) { Rotation = Rotation0; _isRotating = false; Invalidate(); } else if (_isMovingObject) { _NewNet.Clear(); _isMovingObject = false; Invalidate(); } else if (_mouseState != MouseState.无) { _mouseState = MouseState.无; Cursor = Cursors.Default; } else if (_isInsertingObject) { _NewNet.Clear(); _isInsertingObject = false; _OperaNode = null; Invalidate(); } else { _Nodes.ForEach(o => o.Selected = false); _Links.ForEach(o => o.Selected = false); selectedObjs.Clear(); Invalidate(); } } if (e.KeyCode == Keys.Delete) { DeleteChoosedObj(); } if (e.KeyCode == Keys.A && e.Modifiers == Keys.Control) { selectedObjs.Clear(); _Nodes.ForEach(o => { o.Selected = true; selectedObjs.Add(o); }); _Links.ForEach(o => { o.Selected = true; selectedObjs.Add(o); }); Invalidate(); } if (e.KeyCode == Keys.C && e.Modifiers == Keys.Control) { 复制ToolStripMenuItem_Click(1, new EventArgs()); } if (e.KeyCode == Keys.V && e.Modifiers == Keys.Control) { _ClickStartPos = Cursor.Position; 粘贴ToolStripMenuItem1_Click(1, new EventArgs()); } if (e.KeyCode == Keys.D1 && e.Modifiers == Keys.Control) { 南北对齐ToolStripMenuItem_Click(1, new EventArgs()); } if (e.KeyCode == Keys.Oemtilde && e.Modifiers == Keys.Control) { 东西对齐ToolStripMenuItem_Click(1, new EventArgs()); } if (e.KeyCode == Keys.D2 && e.Modifiers == Keys.Control) { 竖直对齐ToolStripMenuItem_Click(1, new EventArgs()); } if (e.KeyCode == Keys.D3 && e.Modifiers == Keys.Control) { 自动对齐ToolStripMenuItem_Click(1, new EventArgs()); } } private void MapViewer_KeyPress(object sender, KeyPressEventArgs e) { if (ctrlPressed && e.KeyChar == 'Z' - 64) { // 执行相应的操作 buttonUndo_Click(sender, e); ctrlPressed = false; // 防止默认操作 e.Handled = true; } if (ctrlPressed && e.KeyChar == 'Y' - 64) { // 执行相应的操作 buttonRedo_Click(sender, e); ctrlPressed = false; // 防止默认操作 e.Handled = true; } if (ctrlPressed && e.KeyChar == 'R' - 64) { // 执行相应的操作 tool视角_ButtonClick(sender, e); ctrlPressed = false; // 防止默认操作 e.Handled = true; } } private void MapViewer_PreKeyPress(object sender, PreviewKeyDownEventArgs e) { if (e.Control && e.KeyCode == Keys.Z) { ctrlPressed = true; // 防止默认操作 e.IsInputKey = true; } if (e.Control && e.KeyCode == Keys.Y) { ctrlPressed = true; // 防止默认操作 e.IsInputKey = true; } if (e.Control && e.KeyCode == Keys.R) { ctrlPressed = true; // 防止默认操作 e.IsInputKey = true; } } public void setCenter(IBaseViewModel obj) { PointF position; if (obj is LinkViewModel link) position = link.Position; else position = obj.Position; PointF currentPos = MapToScreen(WorldPointToMapPoint(position, obj.Elev)); PointF centerScreen = new PointF(this.Width / 2, this.Height / 2); var vector = GetRotateVector(centerScreen, currentPos); MapCenter = new PointF( MapCenter.X - vector.X / Zoom.X, MapCenter.Y - vector.Y / Zoom.Y); } bool ctrlPressed = false; #endregion #region 右键菜单 private void 转换ToolStripMenuItem_Click(object sender, EventArgs e) { var nodes = selectedNodes; foreach (var obj in nodes) { if (obj == null) return; var toolItem = sender as ToolStripItem; NodeViewModel junc = null; int i = 0; string ID; switch (toolItem.Text) { case "水表": junc = _Network.AddMeter(obj.Position); i = 0; ID = $"{Default.GetPreString(junc)}{i}"; while (_Nodes.Find(p0 => p0.ID == ID) != null) { i++; ID = $"{Default.GetPreString(junc)}{i}"; } junc.ID = ID; break; case "基本节点": junc = _Network.AddJunction(obj.Position, obj.Elev); i = 0; ID = $"{Default.GetPreString(junc)}{i}"; while (_Nodes.Find(p0 => p0.ID == ID) != null) { i++; ID = $"{Default.GetPreString(junc)}{i}"; } junc.ID = ID; break; case "水库": junc = _Network.AddReservoir(obj.Position); i = 0; ID = $"{Default.GetPreString(junc)}{i}"; while (_Nodes.Find(p0 => p0.ID == ID) != null) { i++; ID = $"{Default.GetPreString(junc)}{i}"; } junc.ID = ID; break; case "水池": junc = _Network.AddTank(obj.Position); i = 0; ID = $"{Default.GetPreString(junc)}{i}"; while (_Nodes.Find(p0 => p0.ID == ID) != null) { i++; ID = $"{Default.GetPreString(junc)}{i}"; } junc.ID = ID; break; } //junc.ID = obj.ID; junc.Level = obj.Level; junc.Elev = obj.Elev; junc.Demand = obj.Demand; junc.Selected = true; foreach (var p in _Links) { if (p.StartNode == obj) { p.StartNode = junc; } else if (p.EndNode == obj) { p.EndNode = junc; } } selectedObjs.Add(junc); selectedObjs.Remove(obj); //MapObjectExtensions.AddCommand(obj, "Add", null, new List() { n }); _Nodes.Remove(obj); } Invalidate(); } public void 删除ToolStripMenuItem_Click(object sender, EventArgs e) { DeleteChoosedObj(); } private void DeleteChoosedObj() { var list = _Network.Remove(selectedObjs); MapObjectExtensions.AddCommand(_Network, "Remove", null, list); selectedObjs.Clear(); Invalidate(); } #endregion #region 编辑模式/浏览模式切换工具 private void toolStripComboBox_expandRepeater_ButtonClick(object sender, EventArgs e) { _IsEditMode = !_IsEditMode; //toolStripComboBox_浏览模式.Text = isEditMode ? "编辑模式" : "浏览模式"; LoadData(true); } private void 浏览模式ToolStripMenuItem_Click(object sender, EventArgs e) { var obj = sender as ToolStripItem; _IsEditMode = obj.Text == "编辑模式"; //toolStripComboBox_浏览模式.Text = isEditMode ? "编辑模式" : "浏览模式"; LoadData(true); } #endregion #region 分析工具 private void 水平旋转ToolStripMenuItem_Click(object sender, EventArgs e) { //if (!selectedObjs[0].isNode()) //{ // MessageBox.Show("围绕第一个节点旋转,选择集中第一个对象必须是"); //} var objs = GlobalObject.PropertyForm.selectionSet.selectedObjects; var selectobjs = GlobalObject.PropertyForm.listBox1.SelectedItems; if (objs.Count <= 1) return; if (selectobjs.Count != 1) { MessageBox.Show("围绕选中节点进行平面旋转,请在属性列表中选中一个旋转中心对象"); return; } if (!(selectobjs[0] as IBaseViewModel).isNode()) { MessageBox.Show("围绕选中节点进行平面旋转,请在属性列表中选中一个节点类对象"); return; } NodeViewModel origin = selectobjs[0] as NodeViewModel; var nodes = objs.FindAll(o => o.isNode()); float jiaodu = float.Parse(toolStripTextBox_水平旋转角度.Text.ToString()); var NewPositions = GetRotatedPoints(nodes.Select(n => n.Position).ToList(), origin.Position, jiaodu); var OldPositions = nodes.Select(n => n.Position).ToList(); for (int i = 0; i < nodes.Count; i++) { nodes[i].Position = NewPositions[i]; } MapObjectExtensions.AddCommand(nodes, "Position", OldPositions, NewPositions); Invalidate(); } public List GetRotatedPoints(List points, PointF origin, float angle) { // 将角度转换为弧度 float radians = angle * (float)Math.PI / 180.0f; // 计算正余弦值 float cos = (float)Math.Cos(radians); float sin = (float)Math.Sin(radians); // 定义结果集合,并遍历输入点集合进行旋转处理 List result = new List(points.Count); foreach (PointF point in points) { // 将点相对于旋转中心点平移,使其成为以原点为中心的坐标系 float translatedX = point.X - origin.X; float translatedY = point.Y - origin.Y; // 应用旋转变换 float rotatedX = translatedX * cos - translatedY * sin; float rotatedY = translatedX * sin + translatedY * cos; // 将点相对于原坐标系平移回去 float finalX = rotatedX + origin.X; float finalY = rotatedY + origin.Y; // 添加到结果集合中 result.Add(new PointF(finalX, finalY)); } return result; } public List GetRotatedPoints(List points, Vector3 line, float angle) { // 将角度转换为弧度 float radians = (float)(angle * Math.PI / 180.0f); // 根据旋转直线的方向矢量和旋转角度计算旋转矩阵 float cos = (float)Math.Cos(radians); float sin = (float)Math.Sin(radians); float x = line.X; float y = line.Y; float z = line.Z; float[,] rotationMatrix = new float[,] { {cos + x * x * (1 - cos), x * y * (1 - cos) - z * sin, x * z * (1 - cos) + y * sin}, {y * x * (1 - cos) + z * sin, cos + y * y * (1 - cos), y * z * (1 - cos) - x * sin}, {z * x * (1 - cos) - y * sin, z * y * (1 - cos) + x * sin, cos + z * z * (1 - cos)} }; // 定义结果集合,并遍历输入点集合进行旋转处理 List result = new List(points.Count); foreach (PointF3D point in points) { // 将点按照旋转中心线平移,使其成为以原点为中心的坐标系 Vector3 translatedPoint = new Vector3(point.X - line.X, point.Y - line.Y, point.Z - line.Z); // 应用旋转变换 Vector3 rotatedPointVector = new Vector3( translatedPoint.X * rotationMatrix[0, 0] + translatedPoint.Y * rotationMatrix[0, 1] + translatedPoint.Z * rotationMatrix[0, 2], translatedPoint.X * rotationMatrix[1, 0] + translatedPoint.Y * rotationMatrix[1, 1] + translatedPoint.Z * rotationMatrix[1, 2], translatedPoint.X * rotationMatrix[2, 0] + translatedPoint.Y * rotationMatrix[2, 1] + translatedPoint.Z * rotationMatrix[2, 2]); // 将点相对于原坐标系平移回去 float finalX = rotatedPointVector.X + line.X; float finalY = rotatedPointVector.Y + line.Y; float finalZ = rotatedPointVector.Z + line.Z; // 将旋转后的点添加到结果集合中 result.Add(new PointF3D(finalX, finalY, finalZ)); } return result; } private void 缩放ToolStripMenuItem_Click(object sender, EventArgs e) { var objs = GlobalObject.PropertyForm.selectionSet.selectedObjects; var selectobjs = GlobalObject.PropertyForm.listBox1.SelectedItems; if (objs.Count <= 1) return; if (selectobjs.Count != 1) { MessageBox.Show("围绕选中节点进行三维缩放,请在属性列表中选中一个缩放中心对象"); return; } if (!(selectobjs[0] as IBaseViewModel).isNode()) { MessageBox.Show("围绕选中节点进行三维缩放,请在属性列表中选中一个[节点类]缩放中心对象"); return; } NodeViewModel origin = selectobjs[0] as NodeViewModel; var nodes = objs.FindAll(o => o.isNode()).Select(o => o as NodeViewModel).ToList(); ToolStripMenuItem item = sender as ToolStripMenuItem; float jiaodu; switch (item.Text) { case "缩小2倍": jiaodu = 0.5f; break; case "放大2倍": jiaodu = 2f; break; default: jiaodu = float.Parse(toolStripTextBox_缩放比例.Text.ToString()); break; } var OldPositions = nodes.Select(n => n.Position3D).ToList(); var NewPositions = ScalePoints(nodes.Select(n => n.Position3D).ToList(), origin.Position3D, jiaodu); for (int i = 0; i < nodes.Count; i++) { nodes[i].X = NewPositions[i].X; nodes[i].Y = NewPositions[i].Y; nodes[i].Elev = NewPositions[i].Z; } MapObjectExtensions.AddCommand(nodes, "Position3D", OldPositions, NewPositions); Invalidate(); } public static List ScalePoints(List points, PointF3D centerPoint, float scale) { //定义结果集合,并遍历输入点集合进行缩放处理 List result = new List(points.Count); foreach (PointF3D point in points) { //将点相对于缩放中心点平移,使其成为以原点为中心的坐标系 Vector3 translatedPoint = new Vector3(point.X - centerPoint.X, point.Y - centerPoint.Y, point.Z - centerPoint.Z); //应用缩放变换 Vector3 scaledPointVector = new Vector3( translatedPoint.X * scale + centerPoint.X, translatedPoint.Y * scale + centerPoint.Y, translatedPoint.Z * scale + centerPoint.Z); //将缩放后的点添加到结果集合中 result.Add(new PointF3D(scaledPointVector.X, scaledPointVector.Y, scaledPointVector.Z)); } return result; } private void toolStripButton_刷新_Click(object sender, EventArgs e) { LoadData(); } public void 关阀搜索ToolStripMenuItem_Click(object sender, EventArgs e) { if (selectedObjs.Count > 0)//&& selectedObjs[0] is Link l { var objs = selectedObjs.ToList(); var selectsValve = objs.FindAll(o => o is ValveViewModel); selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); TraversePipeNetwork(objs, null, false); selectsValve.ForEach(o => o.Selected = false); this.Invalidate(); } } private void 关阀搜索考虑水源ToolStripMenuItem_Click(object sender, EventArgs e) { if (selectedObjs.Count > 0)//&& selectedObjs[0] is Link l { var objs = selectedObjs.ToList(); var selectsValve = objs.FindAll(o => o is ValveViewModel); selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); TraversePipeNetwork(objs, null); selectsValve.ForEach(o => o.Selected = false); this.Invalidate(); } } //Queue queue2 = null; List LinksToFindSource = null; Dictionary> Sets = null; Dictionary Sets_hasSource = null; private void TraversePipeNetwork(List startObjs, HashSet visitedNodes = null, bool consider = true) { LinksToFindSource = new List(); if (visitedNodes == null) visitedNodes = new HashSet(); startObjs.ForEach(o => { if (o is LinkViewModel l) { TraversePipeNetwork(l, visitedNodes); } else if (o is NodeViewModel n) { n.Links.ForEach(link => TraversePipeNetwork(link, visitedNodes)); } }); if (!consider) return; Sets = new Dictionary>(); Sets_hasSource = new Dictionary(); LinksToFindSource.ForEach(l => { TraversePipeNetwork_Set(l, visitedNodes); }); foreach (var kp in Sets) { if (!Sets_hasSource[kp.Key]) { kp.Value.ForEach(o => { if (!(o is ValveViewModel)) { o.Selected = true; selectedObjs.Add(o); } }); } } GlobalObject.PropertyForm.SetObjs(selectedObjs); } private void TraversePipeNetwork(LinkViewModel startLink, HashSet visitedNodes = null) { Queue queue = new Queue(); queue.Enqueue(startLink); if (visitedNodes == null) visitedNodes = new HashSet(); //visitedNodes.Add(startLink.StartNode); //visitedNodes.Add(startLink.EndNode); while (queue.Count > 0) { LinkViewModel currentLink = queue.Dequeue(); //Console.WriteLine("Traversing Link: " + currentLink.ID); foreach (var node in new NodeViewModel[] { currentLink.StartNode, currentLink.EndNode }) { if (!visitedNodes.Contains(node) && node != null) { visitedNodes.Add(node); node.Selected = true; selectedObjs.Add(node); //Console.WriteLine("Visiting Node: " + node.ID); foreach (var link in node.Links) { if (!visitedNodes.Contains(link.StartNode) || !visitedNodes.Contains(link.EndNode)) { link.Selected = true; selectedObjs.Add(link); if (!(link is ValveViewModel)) { queue.Enqueue(link); } else { LinksToFindSource.Add(link); } } } } } } } private void TraversePipeNetwork_Set(LinkViewModel startLink, HashSet visitedNodes = null) { Queue queue = new Queue(); queue.Enqueue(startLink); if (visitedNodes == null) visitedNodes = new HashSet(); //visitedNodes.Add(startLink.StartNode); //visitedNodes.Add(startLink.EndNode); Sets.Add(startLink, new List()); Sets_hasSource.Add(startLink, false); while (queue.Count > 0) { LinkViewModel currentLink = queue.Dequeue(); //Console.WriteLine("Traversing Link: " + currentLink.ID); foreach (var node in new NodeViewModel[] { currentLink.StartNode, currentLink.EndNode }) { if (node == null) continue; if (!visitedNodes.Contains(node)) { Sets[startLink].Add(node); visitedNodes.Add(node); if (node is TankViewModel || node is ReservoirViewModel) { Sets_hasSource[startLink] = true; } //Console.WriteLine("Visiting Node: " + node.ID); foreach (var link in node.Links) { if (!visitedNodes.Contains(link.StartNode) || !visitedNodes.Contains(link.EndNode)) { Sets[startLink].Add(link); queue.Enqueue(link); } } } else { foreach (var kp in Sets) { if (kp.Key != startLink && kp.Value.Contains(node)) { kp.Value.AddRange(Sets[startLink]); Sets_hasSource[kp.Key] = Sets_hasSource[startLink] || Sets_hasSource[kp.Key]; Sets.Remove(startLink); Sets_hasSource.Remove(startLink); startLink = kp.Key; break; } } } } } } private bool FindSouce(LinkViewModel startLink, HashSet visitedLinks, HashSet visitedLinks2, Dictionary hasSource = null) { foreach (var node in new NodeViewModel[] { startLink.StartNode, startLink.EndNode }) { if (!hasSource.ContainsKey(node)) { //hasSource.Add(node, false); hasSource[node] = FindSouce(node, visitedLinks, visitedLinks2, hasSource); } if (hasSource[node] == true) return true; } return false; } private bool FindSouce(NodeViewModel startNode, HashSet visitedLinks, HashSet visitedLinks2, Dictionary hasSource = null) { foreach (var link in startNode.Links) { if (hasSource.ContainsKey(link) && hasSource[link] == true) return true; if (visitedLinks.Contains(link) && startNode == link.StartNode) continue; if (visitedLinks2.Contains(link) && startNode == link.EndNode) continue; if (startNode == link.StartNode) visitedLinks.Add(link); else visitedLinks2.Add(link); if (!hasSource.ContainsKey(link)) { //hasSource.Add(link,false); hasSource[link] = FindSouce(link, visitedLinks, visitedLinks2, hasSource); } if (hasSource[link] == true) return true; } return false; } private void 联通性ToolStripMenuItem_Click(object sender, EventArgs e) { if (selectedObjs.Count > 0)//&& selectedObjs[0] is Link l { var objs = selectedObjs.FindAll(o => o is LinkViewModel).Select(o => o as LinkViewModel).ToList(); var visitedNodes = new HashSet(); objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes)); this.Invalidate(); } } private void TraversePipeNetworkALL(LinkViewModel startLink, HashSet visitedNodes = null) { Queue queue = new Queue(); queue.Enqueue(startLink); if (visitedNodes == null) visitedNodes = new HashSet(); //visitedNodes.Add(startLink.StartNode); //visitedNodes.Add(startLink.EndNode); while (queue.Count > 0) { LinkViewModel currentLink = queue.Dequeue(); //Console.WriteLine("Traversing Link: " + currentLink.ID); foreach (var node in new NodeViewModel[] { currentLink.StartNode, currentLink.EndNode }) { if (node != null && !visitedNodes.Contains(node)) { visitedNodes.Add(node); node.Selected = true; selectedObjs.Add(node); //Console.WriteLine("Visiting Node: " + node.ID); foreach (var link in node.Links) { if (!visitedNodes.Contains(link.StartNode) || !visitedNodes.Contains(link.EndNode)) { link.Selected = true; selectedObjs.Add(link); queue.Enqueue(link); } } } } } } #endregion #region 显示选项 private void 显示节点ToolStripMenuItem_Click(object sender, EventArgs e) { _ShowJunction = true; Invalidate(); } private void 隐藏节点ToolStripMenuItem_Click(object sender, EventArgs e) { _ShowJunction = false; Invalidate(); } private void 大ToolStripMenuItem_Click(object sender, EventArgs e) { var item = sender as ToolStripItem; if (item.Text == "大") { junction_multiply = 1f; } else if (item.Text == "中") { junction_multiply = 0.6667f; } else { junction_multiply = 0.4f; } Invalidate(); } private void 显示阀门ToolStripMenuItem_Click(object sender, EventArgs e) { _ShowValve = true; Invalidate(); } private void 隐藏阀门ToolStripMenuItem_Click(object sender, EventArgs e) { _ShowValve = false; Invalidate(); } private void 大ToolStripMenuItem1_Click(object sender, EventArgs e) { var item = sender as ToolStripItem; if (item.Text == "大") { Link_multiply = 1f; } else if (item.Text == "中") { Link_multiply = 0.6667f; } else { Link_multiply = 0.4f; } Invalidate(); } #endregion #endregion 二、工具栏 #region 方法 private void 标高推测ToolStripMenuItem_Click(object sender, EventArgs e) { int num = UpdateNodesEle(); if (num > 0) { MessageBox.Show($"更新成功,更新节点数量:{num}个"); } else { MessageBox.Show($"没有需要更新的节点"); } } public int UpdateNodesEle() { int num = 0; foreach (NodeViewModel node in _Nodes) { if (node.Elev == 0 && node is JunctionViewModel) { HashSet nodeSet = new HashSet(); nodeSet.Add(node); List nonZeroNeighbors = new List(); FindNonZeroNeighbors(node, nonZeroNeighbors, nodeSet); if (nonZeroNeighbors.Count != 0) { float sum = 0; float weightSum = 0; foreach (NodeViewModel neighbor in nonZeroNeighbors) { float dist = Get_dist(node.Position, neighbor.Position); if (dist == 0) { dist = 0.0000000001f; } float weight = 1 / dist;// CalculateWeight(node, neighbor); sum += neighbor.Elev * weight; weightSum += weight; } float average = sum / weightSum; node.Elev = average; num++; } } } return num; } private void FindNonZeroNeighbors(NodeViewModel node, List result, HashSet origin) { foreach (LinkViewModel link in node.Links) { NodeViewModel neighbor = null; if (link.StartNode == node) { neighbor = link.EndNode; } else { neighbor = link.StartNode; } if (neighbor.Elev != 0) { result.Add(neighbor); } else if (!origin.Contains(neighbor)) { origin.Add(neighbor); FindNonZeroNeighbors(neighbor, result, origin); } } } private void 标高导出ToolStripMenuItem_Click(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Columns.Add("ID"); dt.Columns.Add("Elev", typeof(float)); foreach (NodeViewModel node in _Nodes) { if (node is JunctionViewModel junction) { var dr = dt.NewRow(); dr.ItemArray = new object[] { junction.ID, junction.Elev }; dt.Rows.Add(dr); } } dtToSql(dt); } void dtToCsv(DataTable dt) { // 创建 SaveFileDialog 对象 SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "CSV Files (*.csv)|*.csv"; saveFileDialog.FileName = "output.csv"; // 如果用户选择了保存位置和文件名,则执行保存操作 if (saveFileDialog.ShowDialog() == DialogResult.OK) { // 获取用户选择的保存路径和文件名 string filePath = saveFileDialog.FileName; // 假设 dt 是包含数据的 DataTable 对象 // 构建 CSV 字符串 StringBuilder csvContent = new StringBuilder(); // 写入表头 foreach (DataColumn column in dt.Columns) { csvContent.Append(column.ColumnName); csvContent.Append(","); } csvContent.AppendLine(); // 写入数据行 foreach (DataRow row in dt.Rows) { for (int i = 0; i < dt.Columns.Count; i++) { csvContent.Append(row[i]); csvContent.Append(","); } csvContent.AppendLine(); } // 将 CSV 内容写入文件 File.WriteAllText(filePath, csvContent.ToString()); // 显示保存成功消息框 MessageBox.Show("文件保存成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } } void dtToSql(DataTable dt) { // 创建 SaveFileDialog 对象 SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "Txt Files (*.txt)|*.txt"; // 如果用户选择了保存位置和文件名,则执行保存操作 if (saveFileDialog.ShowDialog() == DialogResult.OK) { // 获取用户选择的保存路径和文件名 string filePath = saveFileDialog.FileName; // 假设 dt 是包含数据的 DataTable 对象 string tableString = @" IF OBJECT_ID('Elev', 'U') IS NOT NULL BEGIN -- 清空表 TRUNCATE TABLE Elev; END ELSE BEGIN -- 创建表 CREATE TABLE Elev ( ID NVARCHAR(50), Elev REAL ); END "; // 构建 CSV 字符串 StringBuilder csvContent = new StringBuilder(); csvContent.AppendLine(tableString); //// 写入表头 //foreach (DataColumn column in dt.Columns) //{ // csvContent.Append(column.ColumnName); // csvContent.Append(","); //} //csvContent.AppendLine(); int i = 0; int j = 0; while (i < dt.Rows.Count) { if (j == 0) csvContent.AppendLine("INSERT INTO Elev (ID, Elev) VALUES"); // 写入数据行 DataRow row = dt.Rows[i]; csvContent.Append($"('{row[0]}',{row[1]})"); csvContent.Append(i == dt.Rows.Count - 1 || j == 999 ? ";" : ","); csvContent.AppendLine(); i++; j++; if (j == 1000) j = 0; } // 将 CSV 内容写入文件 File.WriteAllText(filePath, csvContent.ToString()); // 显示保存成功消息框 MessageBox.Show("文件保存成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } } private void 导入jsonToolStripMenuItem_Click(object sender, EventArgs e) { var ofd = new OpenFileDialog(); ofd.Filter = "json文件|*.json"; var result = ofd.ShowDialog(); if (result == DialogResult.OK) { _Template = new Template(new Guid().ToString(), "新建", "复制", TemplateType.其他); string json = File.ReadAllText(ofd.FileName); _Template.network = JsonConvert.DeserializeObject(json); _Template.network.BuildRelation(); TemplateList.AddTemp(_Template); LoadData(); } } public void buttonUndo_Click(object sender, EventArgs e) { GlobalObject.map.SetInvalidated(); GlobalObject.PropertyForm.propertyGrid.Refresh(); MapObjectExtensions.Undo(); } public void buttonRedo_Click(object sender, EventArgs e) { GlobalObject.map.SetInvalidated(); GlobalObject.PropertyForm.propertyGrid.Refresh(); MapObjectExtensions.Redo(); } private void ePA导出ToolStripMenuItem_Click(object sender, EventArgs e) { } public void toolStripButton_save_ButtonClick(object sender, EventArgs e) { if (_Template == null) return; if (!_IsEditMode) { if (message.show("提醒", "浏览模式无法保存,是否恢复为编辑模式")) { _IsEditMode = true; } else return; } else { bool isReplace = false; //isReplace = !message.show("模板选择", "使用模板新增/替换当前文件", MessageBoxButtons.YesNo); _Network.BuildToInp(_filePath, null, null, false); //if (message.show("保存视角", "是否保存视角")) //{ // if (_Template.view == null) _Template.view = new MapDimensions(); // _Template.view.Center = MapCenter; // _Template.view.zoom = zoom; // _Template.view.rotation = Rotation; // _Template.view.rotationF = 俯视角度; //} } } private void 以当前视角另存ToolStripMenuItem_Click(object sender, EventArgs e) { if (_Template == null) return; StringBuilder sb = new StringBuilder(); sb.AppendLine("[COORDINATES]"); sb.AppendLine(";Node X-Coord Y-Coord"); _Nodes.ForEach(n => { var p = WorldPointToMapPoint(n); sb.AppendLine($"{n.ID} {p.X} {p.Y}"); }); SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "Inp Files (*.inp)|*.inp"; saveFileDialog.InitialDirectory = Directory.GetCurrentDirectory() + $@"\template\"; if (_filePath != null) saveFileDialog.FileName = _filePath; if (saveFileDialog.ShowDialog() == DialogResult.OK) { string filePath = saveFileDialog.FileName; // 使用 filePath 变量来保存文件 //temp.路径 = filePath; _Network.BuildToInp(filePath, sb.ToString(), _filePath); //_filePath = filePath; } } private void 另存为ToolStripMenuItem_Click(object sender, EventArgs e) { bool isReplace = false; //isReplace = !message.show("模板选择", "使用模板新增/替换当前文件", MessageBoxButtons.YesNo); SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "Inp Files (*.inp)|*.inp"; saveFileDialog.InitialDirectory = Directory.GetCurrentDirectory() + $@"\template\"; if (_filePath != null) saveFileDialog.FileName = _filePath; if (saveFileDialog.ShowDialog() == DialogResult.OK) { string filePath = saveFileDialog.FileName; // 使用 filePath 变量来保存文件 //temp.路径 = filePath; _Network.BuildToInp(filePath, null, _filePath, isReplace); //_filePath = filePath; } } private void 连通性检查ToolStripMenuItem1_Click(object sender, EventArgs e) { if (selectedObjs.Count > 0)//&& selectedObjs[0] is Link l { var objs = selectedObjs.FindAll(o => o is LinkViewModel).Select(o => o as LinkViewModel).ToList(); var visitedNodes = new HashSet(); objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes)); this.Invalidate(); } } public void 复制ToolStripMenuItem_Click(object sender, EventArgs e) { if (selectedObjs.Count <= 0) return; if (selectedNodes.Count <= 0) return; _OperaNode = selectedNodes[0]; MapViewNetWork net = new MapViewNetWork(); net.StartPoint = _OperaNode; net.Nodes.AddRange(selectedObjs.FindAll(o => o is NodeViewModel).Select(o => o as NodeViewModel)); net.Links.AddRange(selectedObjs.FindAll(o => o is LinkViewModel).Select(o => o as LinkViewModel)); string json = net.WriteToJson(); try { Clipboard.SetText(json); this.Invalidate(); } catch { } } public void 粘贴ToolStripMenuItem1_Click(object sender, EventArgs e) { //MessageBox.Show("未完成"); //return; //try { var net = new MapViewNetWork(); string json = Clipboard.GetText(); net.ReadFromJson(json); PointF minPoint = new PointF(net.StartPoint.X, net.StartPoint.Y); //foreach (Node node in net.Nodes) //{ // if (node.X { obj.X = obj.X + basePoint.X - minPoint.X; obj.Y = obj.Y + basePoint.Y - minPoint.Y; }); //if (message.show("粘贴选项","鼠标位置粘贴:原位置粘贴",MessageBoxButtons.YesNo)) //{ selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); //} //net.Nodes.ForEach(o => o.Selected = false); //net.Links.ForEach(o => o.Selected = false); selectedObjs.AddRange(net.Nodes); selectedObjs.AddRange(net.Links); //net.Nodes.ForEach(o => selectedNodes.); //net.Links.ForEach(o => o.Selected = false) ; var list = _Network.Add(net); MapObjectExtensions.AddCommand(_Network, "Add", null, list); //_OperaNode = null; //_Network.Nodes.AddRange(net.Nodes); //_Network.Links.AddRange(net.Links); Invalidate(); } //catch(Exception ex) //{ // MessageBox.Show(ex.Message); //} } private void 增量保存ToolStripMenuItem_Click(object sender, EventArgs e) { if (_Template == null) return; if (!_IsEditMode) { if (message.show("提醒", "浏览模式无法保存,是否恢复为编辑模式")) { _IsEditMode = true; } else return; } else { bool isReplace = true; //isReplace = !message.show("模板选择", "使用模板新增/替换当前文件", MessageBoxButtons.YesNo); _Network.BuildToInp(_filePath, null, null, false); } } private void 设为关闭ToolStripMenuItem_Click(object sender, EventArgs e) { selectedObjs.ForEach(obj => { if (obj is LinkViewModel link) link.Status = StatusType.CLOSED; }); Invalidate(); } private void 显示全部楼层ToolStripMenuItem_Click(object sender, EventArgs e) { this.mapOption.ShowFloor = int.MinValue; this.Invalidate(); } private void 保存楼层视角ToolStripMenuItem_Click(object sender, EventArgs e) { //if (_Template?.Floors!=null) //{ // var fl = _Template.Floors.Find(f => f.FloorIndex == this.mapOption.ShowFloor); // if (fl!=null)fl.MapView = this.mapOption.Copy(); //} } public void 南北对齐ToolStripMenuItem_Click(object sender, EventArgs e) { if (selectedNodes.Count < 1) return; List list = new List(); List list1 = new List(); selectedNodes.ForEach(n => { list.Add(n.X); n.X = selectedNodes[0].X; list1.Add(n.X); }); MapObjectExtensions.AddCommand(selectedNodes, "X", list, list1); this.Invalidate(); } public void 东西对齐ToolStripMenuItem_Click(object sender, EventArgs e) { if (selectedNodes.Count < 1) return; List list = new List(); List list1 = new List(); selectedNodes.ForEach(n => { list.Add(n.Y); n.Y = selectedNodes[0].Y; list1.Add(n.Y); }); MapObjectExtensions.AddCommand(selectedNodes, "Y", list, list1); this.Invalidate(); } public void 竖直对齐ToolStripMenuItem_Click(object sender, EventArgs e) { if (selectedNodes.Count < 1) return; List list = new List(); List list1 = new List(); selectedNodes.ForEach(n => { list.Add(n.Position); n.Position = selectedNodes[0].Position; list1.Add(n.Position); }); MapObjectExtensions.AddCommand(selectedNodes, "Position", list, list1); this.Invalidate(); } public void 自动对齐ToolStripMenuItem_Click(object sender, EventArgs e) { if (selectedNodes.Count < 3) return; List OldPosition3Ds = selectedNodes.Select(n => n.Position3D).ToList(); List NewPosition3Ds = ProjectPointsToLine(OldPosition3Ds); for (int i = 0; i < selectedNodes.Count; i++) { selectedNodes[i].Position3D = NewPosition3Ds[i]; } MapObjectExtensions.AddCommand(selectedNodes, "Position3D", OldPosition3Ds, NewPosition3Ds); this.Invalidate(); } List ProjectPointsToLine(List points) { // 使用最小二乘法构造直线,并将点投影到直线上 // 计算均值 double sumX = 0; double sumY = 0; double sumZ = 0; foreach (PointF3D point in points) { sumX += point.X; sumY += point.Y; sumZ += point.Z; } double meanX = sumX / points.Count; double meanY = sumY / points.Count; double meanZ = sumZ / points.Count; // 计算最小二乘法拟合直线的参数 double sumXY = 0; double sumX2 = 0; foreach (PointF3D point in points) { double devX = point.X - meanX; double devY = point.Y - meanY; double devZ = point.Z - meanZ; sumXY += devX * devY; sumX2 += devX * devX; } double slope = sumXY / sumX2; double interceptY = meanY - slope * meanX; double interceptZ = meanZ - slope * meanX; // 计算点投影到直线上的坐标 List projectedPoints = new List(); foreach (PointF3D point in points) { double projectedY = slope * point.X + interceptY; double projectedZ = slope * point.X + interceptZ; projectedPoints.Add(new PointF3D(point.X, (float)projectedY, (float)projectedZ)); } return projectedPoints; } public void 添加底图ToolStripMenuItem_Click(object sender, EventArgs e) { if (_Template == null) return; OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Filter = "Image Files (*.bmp;*.jpg;*.jpeg;*.png;*.gif)|*.bmp;*.jpg;*.jpeg;*.png;*.gif"; openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); if (openFileDialog.ShowDialog() == DialogResult.OK) { var backgroundImagePath = openFileDialog.FileName; Global.ClearFileReadOnly(_Template.BackGroundImg_FullPath); try { File.Copy(backgroundImagePath, _Template.BackGroundImg_FullPath, true); } catch { } 设置底图ToolStripMenuItem_Click(1, new EventArgs()); } } bool _isSettingBackGroundPictur = false; public void 设置底图ToolStripMenuItem_Click(object sender, EventArgs e) { string inputValue = Prompt.ShowDialog("请输入底图标高", ""); float BackGroundElev = 0; if (float.TryParse(inputValue, out float result)) { BackGroundElev = result; } else { BackGroundElev = 0; } _Template.BackGroundElev = BackGroundElev; _mouseState = MouseState.设置底图范围; this._lastCursor = this.Cursor; this.Cursor = Cursors.Cross; } public void 显示隐藏底图ToolStripMenuItem_Click(object sender, EventArgs e) { mapOption.isShowPic = !mapOption.isShowPic; Invalidate(); } private dict param = null; public void 清除底图ToolStripMenuItem_Click(object sender, EventArgs e) { mapOption.isShowPic = false; Invalidate(); try { File.Delete(_Template.BackGroundImg_FullPath); } catch { } } private void label_zoom_Click(object sender, EventArgs e) { string inputValue = Prompt.ShowDialog("请输入比例", ""); if (float.TryParse(inputValue, out float result)) { zoom = result; } } private void label_file_DoubleClick(object sender, EventArgs e) { if (_filePath == null) return; FileInfo fi = new FileInfo(_filePath); Process.Start("explorer.exe", $"/select,\"{_filePath}\""); } private void label_file_Click(object sender, EventArgs e) { if (_filePath == null) return; FileInfo fi = new FileInfo(_filePath); Process.Start("explorer.exe", $"/select,\"{_filePath}\""); } private void 设为立管点ToolStripMenuItem_Click(object sender, EventArgs e) { if (selectedNodes.Count == 1) { _Template.Node2 = _EndPoint = selectedNodes[0].ID; } } public class Prompt : Form { private static TextBox textBox; private static Button okButton; public static string ShowDialog(string text, string caption, string defaultTxt = "") { Form prompt = new Form() { Width = 200, Height = 150, FormBorderStyle = FormBorderStyle.FixedDialog, Text = caption, StartPosition = FormStartPosition.CenterScreen }; Label textLabel = new Label() { Left = 20, Top = 20, Text = text }; textBox = new TextBox() { Left = 20, Top = 50, Width = 150 }; textBox.Text = defaultTxt; okButton = new Button() { Text = "确定", Left = 75, Width = 75, Top = 80 }; okButton.Click += (sender, e) => { prompt.Close(); }; prompt.Controls.Add(textBox); prompt.Controls.Add(textLabel); prompt.Controls.Add(okButton); prompt.ShowDialog(); return textBox.Text; } } #endregion } }