using Yw.WinFrmUI.Q3D; using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Drawing; using System.IO; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using static Yw.WinFrmUI.Q3D.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; using Yw.WinFrmUI.Q3D; using Yw.WinFrmUI.Q3D; namespace Yw.WinFrmUI.Q3D { public partial class Map : UserControl { #region 一、全局 #region 初始化 public Map() { InitializeComponent(); this.DoubleBuffered = true; MapCenter = PointF.Empty; zoom = 1.0f; SetStyle(ControlStyles.SupportsTransparentBackColor, true); BackColor = Color.Transparent; } public void SetEditMode(bool isEditMode) { IsEditMode = isEditMode; } private void MapViewer_Load(object sender, EventArgs e) { //GlobalObject.PropertyForm = this.propertyForm; int i = 0; //遍历ColourType this.TC = TC; this.DrawNet = Draw; this.DrawNetNew = Draw; this.DrawBackGroundPic = DrawBackGroud; this.DrawAuxiliary = DrawH; this.onMouseDown = mapMouseDown; this.onMouseMove = mapMouseMove; this.onMouseUp = mapMouseUp; this.onMouseWheel = mapMouseWheel; this.Inited = true; this.Status = DrawingStatus.Ready; //TContainer TCCube = new TContainer(); //TCCube.settings = new Settings(); //TCCube.settings.network = new MapViewNetWork(); //TCCube.settings.network.Areas = new List(); //Cube cb = new Cube(); //foreach (var item in cb.FacesVertices) //{ // AreaViewModel area = new AreaViewModel(); // area.ID = item.Key.ToString(); // area.InnerNodes = new List(); // //area.Name= item.Key.ToString(); // //6个面设置不一样的颜色 // switch (item.Key) // { // case 1: // area.color = Color.Red; // area.Name = "右"; // break; // case 2: // area.color = Color.SkyBlue; // area.Name = "左"; // break; // case 3: // area.color = Color.Green; // area.Name = "后"; // break; // case 4: // area.color = Color.DarkBlue; // area.Name = "前"; // break; // case 5: // area.color = Color.Purple; // area.Name = "上"; // break; // case 6: // area.color = Color.Orange; // area.Name = "下"; // break; // default: // area.color = Color.White; // break; // } // foreach (var p in item.Value) // { // NodeViewModel node = new NodeViewModel(); // node.X = p.X; // node.Y = p.Y; // node.Z = p.Z; // area.InnerNodes.Add(node); // } // TCCube.settings.network.Areas.Add(area); //} } #endregion #region 对外开放,全局控制方法 private bool LoadData(bool isDelCache = false) { if (_Template == null) return false; if (isDelCache || _network == null) { _network = new MapViewNetWork(); } SuspendLayout(); SetStartEndPoint(_Template.Node1, _Template.Node2); ResumeLayout(false); return true; } Dictionary _ViewModel = null; public void Clear() { _Template = null; MapCenter = PointF.Empty; zoom = 1.0f; Rotation = 0; RotationF = 90; SetMapInvalidate(); } public void SetData(MapViewNetWork netWork, Settings template = null) { bool reLoad = _network == netWork; this._Template = template; this._network = netWork; if (_Template == null) _Template = new Settings(); if (!LoadData()) return; if (!reLoad) { if (_Template.view == null) InitCenter(); else { this.mapOption = _Template.view.Copy(); SetMapInvalidate(); } } //将$"{MapCenter.X.ToString("0.00")},{MapCenter.Y.ToString("0.00")}"通过CenterChanged传出 CenterChanged?.Invoke(this, $"{MapCenter.X.ToString("0.00")},{MapCenter.Y.ToString("0.00")}"); //将zoom.ToString("0.000")通过ZoomChanged传出 ZoomChanged?.Invoke(this, zoom.ToString("0.000")); //将Rotation.ToString("0")通过RotationChanged传出 RotationChanged?.Invoke(this, Rotation.ToString("0")); //将RotationF.ToString("0")通过RotationFChanged传出 RotationFChanged?.Invoke(this, RotationF.ToString("0")); } 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(this.Width / x_span, this.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 SetMapInvalidate() { _needPaintAll = true; PMin_Show = ScreenToMap(new PointF(0, this.Height)); PMax_Show = ScreenToMap(new PointF(this.Width, 0)); _timerDraw = true; } public void SetStartEndPoint(String node1, string node2) { _StartPoint = node1; _EndPoint = node2; SetMapInvalidate(); } public void Set3DView(bool is3Dview, double 俯视角度) { this.RotationF = 俯视角度; this.is3Dview = is3Dview; SetMapInvalidate(); } public void SetRotation(double d) { this.Rotation = d; SetMapInvalidate(); } #endregion #region 重绘函数 bool _needPaintAll { get { return __needpaintall; } set { __needpaintall = value; } } 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; } private void timer_draw_Tick(object sender, EventArgs e) { _mouseHoverCheckFlag = true; if (_timerDraw && this.Status == DrawingStatus.Ready) { this.Invalidate(); _timerDraw = false; } } protected override void OnResize(EventArgs e) { base.OnResize(e); // 当控件尺寸改变时,触发重绘 this.SetMapInvalidate(); } #endregion #region 鼠标事件 void mapMouseDown(MouseEventArgs e) { base.OnMouseDown(e); _ClickStartPos = new PointF(e.X, e.Y); DragStartPos = ScreenToMap(new PointF(e.X, e.Y)); mousePosition = _MousePosition = ScreenToMap(new PointF(e.X, e.Y)); if (e.Button == MouseButtons.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)); SetMapInvalidate(); return; } if (_isDrawingPolygon) { return; } 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; } bool controlDown = false; PointF _MousePosition = new PointF(0, 0); void mapMouseMove(MouseEventArgs e) { //base.OnMouseMove(e); bool needInvalidate = false; _MousePosition = ScreenToMap(new PointF(e.X, e.Y)); if (_isMovingObject) { var p = MapPointToWorldPoint(_MousePosition, _OperaNode.Z); 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); //将$"{MapCenter.X.ToString("0.00")},{MapCenter.Y.ToString("0.00")}"通过CenterChanged传出 CenterChanged?.Invoke(this, $"{MapCenter.X.ToString("0.00")},{MapCenter.Y.ToString("0.00")}"); 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; } else if (_isInsertingObject) { var p = MapPointToWorldPoint(_MousePosition, _OperaNode.Z); 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; SelectedObjectsChanged?.Invoke(this, null); needInvalidate = true; } //else /*判断是否触碰到对象*/ if (_mouseHoverCheckFlag) { _mouseHoverCheckFlag = false; // 遍历所有对象,找出范围内的对象 PointF clickedPoint = new PointF(e.X, e.Y); //ScreenToMap(new PointF(e.X, e.Y)); var obj = GetObj_by_ScreenPoint(clickedPoint); if (hoveredObjs.Count > 0 && hoveredObjs[0] == obj || hoveredObjs.Count == 0 && obj == null) { //needInvalidate = false; } else { needInvalidate = true; hoveredObjs.ForEach(o => o.Hovered = false); hoveredObjs.Clear(); if (obj != null) { obj.Hovered = true; hoveredObjs.Add(obj); } } } if (needInvalidate) this.SetMapInvalidate(); //将$"{e.X.ToString("0")},{e.Y.ToString("0")}"通过MousePositionChanged传出 MousePositionChanged?.Invoke(this, $"{_MousePosition.X.ToString("0.00")},{_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; void mapMouseUp(MouseEventArgs e) { //BookMark :鼠标抬起事件 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 /*框选放大*/(ModifierKeys == Keys.Control && (e.Button == MouseButtons.Middle || e.Button == MouseButtons.XButton2)) { _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 * this.Width / size.Width, 1.0f * this.Height / size.Height); if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); CenterChanged?.Invoke(this, $"{MapCenter.X.ToString("0.00")},{MapCenter.Y.ToString("0.00")}"); //将zoom.ToString("0.000")通过ZoomChanged传出 ZoomChanged?.Invoke(this, zoom.ToString("0.000")); SetMapInvalidate(); return; } if /*平移视角*/(ModifierKeys == Keys.None && (e.Button == MouseButtons.Middle || e.Button == MouseButtons.XButton2)) { if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); //将$"{MapCenter.X.ToString("0.00")},{MapCenter.Y.ToString("0.00")}"通过CenterChanged传出 CenterChanged?.Invoke(this, $"{MapCenter.X.ToString("0.00")},{MapCenter.Y.ToString("0.00")}"); this.Cursor = _lastCursor; _isPanning = false; return; } if /*设置背景*/(e.Button == MouseButtons.Left && _isSettingBackGroundPictur) { _Template.BackGroundPoint1 = BackGroudPicLeftPos; _Template.BackGroundPoint2 = MapPointToWorldPoint(mousePosition, _Template.BackGroundElev); _isSettingBackGroundPictur = false; mapOption.isShowPic = true; this.Cursor = _lastCursor; SetMapInvalidate(); return; } if /*多边形选择*/(_isDrawingPolygon && e.Button == MouseButtons.Left && ModifierKeys == Keys.None) { _isDrawingPolygon = false; if (polygonPoints.Count >= 3) { _Nodes.ForEach(n0 => { var n = (NodeViewModel)n0; if (IsPointInPolygon(WorldPointToMapPoint(n), polygonPoints)) { selectedObjs.Add(n); n.Selected = true; } }); _Links.ForEach(n0 => { var n = (LinkViewModel)n0; if (IsPointInPolygon(WorldPointToMapPoint(n.Position, n.Z), polygonPoints)) { selectedObjs.Add(n); n.Selected = true; } }); //将选中的对象通过SelectedObjectsChanged传出 SelectedObjectsChanged?.Invoke(this, selectedObjs); } SetMapInvalidate(); // 结束绘制多边形 return; } if /*取消移动对象*/(_isMovingObject && !isMouseMoved && e.Button == MouseButtons.Left) { _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(); return; } if /*叠加框选*/(isMouseMoved && _mouseState == MouseState.无 && e.Button == MouseButtons.Left && ModifierKeys == Keys.Control) { _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); for (int i = 0; i < _Nodes.Count; i++) { var node = _Nodes[i] as NodeViewModel; if (!node.Visible) continue; PointF p = WorldPointToMapPoint(node); if (RectangContain(rectangle0, p)) { if (selectedObjs.Contains(node)) { node.Selected = false; selectedObjs.Remove(node); } else { node.Selected = true; selectedObjs.Add(node); } } } for (int i = 0; i < _Links.Count; i++) { var link = _Links[i] as LinkViewModel; if (!link.Visible) continue; PointF p = WorldPointToMapPoint(link.Position, link.Z); if (RectangContain(rectangle0, p)) { if (selectedObjs.Contains(link)) { link.Selected = false; selectedObjs.Remove(link); } else { link.Selected = true; selectedObjs.Add(link); } } } SelectedObjectsChanged?.Invoke(this, selectedObjs); SetMapInvalidate(); mousePosition = new PointF(0, 0); return; } if /*框选*/(isMouseMoved && _mouseState == MouseState.无 && e.Button == MouseButtons.Left && ModifierKeys == Keys.None) { _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); selectedObjs.ForEach(obj => obj.Selected = false); selectedObjs.Clear(); for (int i = 0; i < _Nodes.Count; i++) { var node = _Nodes[i] as NodeViewModel; if (!node.Visible) continue; PointF p = WorldPointToMapPoint(node); if (RectangContain(rectangle0, p)) { node.Selected = true; selectedObjs.Add(node); } } for (int i = 0; i < _Links.Count; i++) { var link = _Links[i] as LinkViewModel; if (!link.Visible) continue; PointF p = WorldPointToMapPoint(link.Position, link.Z); if (RectangContain(rectangle0, p)) { link.Selected = true; selectedObjs.Add(link); } } //将selectedObjs通过SelectedObjectsChanged传出 SelectedObjectsChanged?.Invoke(this, selectedObjs); SetMapInvalidate(); mousePosition = new PointF(0, 0); return; } if /*点选*/(!isMouseMoved && _mouseState == MouseState.无 && e.Button == MouseButtons.Left && ModifierKeys == Keys.None) { _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 (obj != null) { selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); obj.Selected = true; selectedObjs.Add(obj); SelectedObjectsChanged?.Invoke(this, selectedObjs); _OperaNode = null; SetMapInvalidate(); mousePosition = new PointF(0, 0); } else { //GlobalObject.LockSelect selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); SelectedObjectsChanged?.Invoke(this, selectedObjs); _OperaNode = null; SetMapInvalidate(); } return; } if (/*叠加点选*/!isMouseMoved && _mouseState == MouseState.无 && e.Button == MouseButtons.Left && ModifierKeys == Keys.Control) { _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 (obj != null) { if (selectedObjs.Contains(obj)) { obj.Selected = false; selectedObjs.Remove(obj); SelectedObjectsChanged?.Invoke(this, selectedObjs); SetMapInvalidate(); mousePosition = new PointF(0, 0); } else { obj.Selected = true; selectedObjs.Add(obj); SelectedObjectsChanged?.Invoke(this, selectedObjs); SetMapInvalidate(); mousePosition = new PointF(0, 0); } } return; } if (/*旋转*/e.Button == MouseButtons.Right && _isRotating) { _isRotating = false; this.Cursor = _lastCursor; if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); mousePosition = new PointF(0, 0); //将Rotation.ToString("0")通过RotationChanged传出 RotationChanged?.Invoke(this, Rotation.ToString("0")); //将RotationF.ToString("0")通过RotationFChanged传出 RotationFChanged?.Invoke(this, RotationF.ToString("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.Z; if (RotationF != 0) { p = MapPointToWorldPoint(ScreenToMap(new PointF(e.X, e.Y), j.Z), j.Z); } 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 DistLimit = 15f) { float minDist = float.MaxValue; int minIndex = -1; bool isJunction = true; IBaseViewModel obj = null; for (int i = 0; i < _Nodes.Count; i++) { var node = _Nodes[i] as NodeViewModel; if (!node.Visible) continue; PointF mapPos = WorldPointToMapPoint(node); PointF currentPoint = MapToScreen(mapPos); float dist = Get_dist(clickedPoint, currentPoint); if (dist < minDist && dist <= DistLimit) { minDist = dist; minIndex = i; obj = node; } } for (int i = 0; i < _Links.Count; i++) { var link = _Links[i] as LinkViewModel; if (!link.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 mapPos1 = WorldPointToMapPoint(link.StartNode.Position, link.StartNode.Z); PointF currentPoint1 = MapToScreen(mapPos1); PointF mapPos2 = WorldPointToMapPoint(link.EndNode.Position, link.EndNode.Z); PointF currentPoint2 = MapToScreen(mapPos2); //根据currentPoint1和currentPoint2,判断clickedPoint离线段currentPoint1和currentPoint2的距离 float dist = Get_dist(clickedPoint, currentPoint1, currentPoint2, DistLimit); //float dist = Get_dist(clickedPoint, currentPoint); if (dist < minDist && dist <= DistLimit) { minDist = dist; minIndex = i; isJunction = false; obj = link; } } return obj; } List GetObjs_by_ScreenPoint(PointF clickedPoint, float DistLimit = 15f) { float minDist = float.MaxValue; int minIndex = -1; IBaseViewModel obj = null; List objs = new List(); for (int i = 0; i < _Nodes.Count; i++) { var node = _Nodes[i] as NodeViewModel; if (!node.Visible) continue; PointF mapPos = WorldPointToMapPoint(node); PointF currentPoint = MapToScreen(mapPos); float dist = Get_dist(clickedPoint, currentPoint); if (dist <= DistLimit) { objs.Add(node); } } for (int i = 0; i < _Links.Count; i++) { var link = _Links[i] as LinkViewModel; if (!link.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 mapPos1 = WorldPointToMapPoint(link.StartNode.Position, link.StartNode.Z); PointF currentPoint1 = MapToScreen(mapPos1); PointF mapPos2 = WorldPointToMapPoint(link.EndNode.Position, link.EndNode.Z); PointF currentPoint2 = MapToScreen(mapPos2); //根据currentPoint1和currentPoint2,判断clickedPoint离线段currentPoint1和currentPoint2的距离 float dist = Get_dist(clickedPoint, currentPoint1, currentPoint2, DistLimit); //float dist = Get_dist(clickedPoint, currentPoint); if (dist < minDist && dist <= DistLimit) { objs.Add(link); } } return objs; } /// /// 鼠标滚轮事件 /// /// void mapMouseWheel(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)); if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); SetMapInvalidate(); } private int _lastMouseX; private int _lastMouseY; #endregion #region CubeView鼠标事件 void CubeViewMouseDown(MouseEventArgs e) { base.OnMouseDown(e); _ClickStartPos = new PointF(e.X, e.Y); DragStartPos = ScreenToMap(new PointF(e.X, e.Y)); mousePosition = _MousePosition = ScreenToMap(new PointF(e.X, e.Y)); if (e.Button == MouseButtons.Left && _isInsertingObject) { } else if (e.Button == MouseButtons.Left && _mouseState == MouseState.无) { } else if (e.Button == MouseButtons.Left && _mouseState == MouseState.设置底图范围) { } 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; } } void CubeViewMouseMove(MouseEventArgs e) { //base.OnMouseMove(e); bool needInvalidate = false; _MousePosition = ScreenToMap(new PointF(e.X, e.Y)); 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; } //else /*判断是否触碰到对象*/ if (_mouseHoverCheckFlag) { _mouseHoverCheckFlag = false; // 遍历所有对象,找出范围内的对象 PointF clickedPoint = new PointF(e.X, e.Y); //ScreenToMap(new PointF(e.X, e.Y)); var obj = GetObj_by_ScreenPoint(clickedPoint); if (hoveredObjs.Count > 0 && hoveredObjs[0] == obj || hoveredObjs.Count == 0 && obj == null) { //needInvalidate = false; } else { needInvalidate = true; hoveredObjs.ForEach(o => o.Hovered = false); hoveredObjs.Clear(); if (obj != null) { obj.Hovered = true; hoveredObjs.Add(obj); } } } if (needInvalidate) this.SetMapInvalidate(); MousePositionChanged?.Invoke(this, $"{_MousePosition.X.ToString("0.00")},{_MousePosition.Y.ToString("0.00")}"); _lastMouseX = e.X; _lastMouseY = e.Y; } void CubeViewMouseUp(MouseEventArgs e) { //BookMark :鼠标抬起事件 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 /*点选*/(!isMouseMoved && _mouseState == MouseState.无 && e.Button == MouseButtons.Left && ModifierKeys == Keys.None) { _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 (obj != null) { selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); obj.Selected = true; selectedObjs.Add(obj); SelectedObjectsChanged?.Invoke(this, selectedObjs); _OperaNode = null; SetMapInvalidate(); mousePosition = new PointF(0, 0); } else { //GlobalObject.LockSelect selectedObjs.ForEach(o => o.Selected = false); selectedObjs.Clear(); SelectedObjectsChanged?.Invoke(this, selectedObjs); _OperaNode = null; SetMapInvalidate(); } return; } if (/*叠加点选*/!isMouseMoved && _mouseState == MouseState.无 && e.Button == MouseButtons.Left && ModifierKeys == Keys.Control) { _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 (obj != null) { if (selectedObjs.Contains(obj)) { obj.Selected = false; selectedObjs.Remove(obj); SelectedObjectsChanged?.Invoke(this, selectedObjs); SetMapInvalidate(); mousePosition = new PointF(0, 0); } else { obj.Selected = true; selectedObjs.Add(obj); SelectedObjectsChanged?.Invoke(this, selectedObjs); SetMapInvalidate(); mousePosition = new PointF(0, 0); } } return; } if (e.Button == MouseButtons.Right) { if (_isRotating) { _isRotating = false; this.Cursor = _lastCursor; if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); mousePosition = new PointF(0, 0); } } } #endregion #endregion 一、全局 #region 二、工具栏 #region 视角工具 // 显示点属性 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); SetMapInvalidate(); } 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); SetMapInvalidate(); } public void 重置视角ToolStripMenuItem_Click(object sender, EventArgs e) { mapOption0 = mapOption.Copy(); RotationF = 90; Rotation = 0; InitCenter(); if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); SetMapInvalidate(); } private void 正视图ToolStripMenuItem_Click(object sender, EventArgs e) { mapOption0 = mapOption.Copy(); RotationF = 0; if (recordView) MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); SetMapInvalidate(); } private void 俯视图ToolStripMenuItem_Click(object sender, EventArgs e) { mapOption0 = mapOption.Copy(); RotationF = 90; MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); SetMapInvalidate(); } private void 默认视角ToolStripMenuItem_Click(object sender, EventArgs e) { mapOption0 = mapOption.Copy(); InitCenter(); RotationF = 45; Rotation = -45; MapObjectExtensions.AddCommand(mapOption, "Map", mapOption0, mapOption); SetMapInvalidate(); } 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.SetMapInvalidate(); } 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); } SetMapInvalidate(); } } this.SetMapInvalidate(); } void MovePointbyLength(NodeViewModel node1, NodeViewModel node2, float Length) { float distance = Vector3.Distance(new Vector3(node1.X, node1.Y, node1.Z), new Vector3(node2.X, node2.Y, node2.Z)); 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.Z - node1.Z); // 计算 AB 的单位向量 Vector3 unitAB = Vector3.Normalize(AB); // 计算需要移动的距离的向量(与 AB 方向相同) Vector3 moveVector = unitAB * moveDistance; // 更新点 B 的坐标 node2.X += moveVector.X; node2.Y += moveVector.Y; node2.Z += moveVector.Z; // 输出移动后的点 B 坐标 //Console.WriteLine("移动后点 B 的坐标为 ({0}, {1}, {2})", x2, y2, z2); } } private void 全部显示ToolStripMenuItem_Click(object sender, EventArgs e) { _Nodes.Select(n => (NodeViewModel)n).ToList().ForEach(v => { if (!v.Visible) { MapObjectExtensions.AddCommand(v, "Visible", v.Visible, true); v.Visible = true; } }); _Links.Select(n => (LinkViewModel)n).ToList().ForEach(v0 => { var v = (LinkViewModel)v0; if (!v.Visible) { MapObjectExtensions.AddCommand(v, "Visible", v.Visible, true); v.Visible = true; } }); this.SetMapInvalidate(); } #endregion #region 绘图工具 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; if (_isPainting) { _select_junction1 = null; _isPainting = false; SetMapInvalidate(); } else if (_isDragging) { _isDragging = false; SetMapInvalidate(); } else if (_isPanning) { _isPanning = false; SetMapInvalidate(); } else if (_isRotating) { Rotation = Rotation0; _isRotating = false; SetMapInvalidate(); } else if (_isMovingObject) { _NewNet.Clear(); _isMovingObject = false; SetMapInvalidate(); } else if (_mouseState != MouseState.无) { _mouseState = MouseState.无; Cursor = Cursors.Default; } else if (_isInsertingObject) { _NewNet.Clear(); _isInsertingObject = false; _OperaNode = null; SetMapInvalidate(); } else { _Nodes.ForEach(o => ((NodeViewModel)o).Selected = false); _Links.ForEach(o => ((LinkViewModel)o).Selected = false); selectedObjs.Clear(); SetMapInvalidate(); } } public void toolStripButton_新建管线_Click(object sender, EventArgs e) { _mouseState = MouseState.新增管线; Cursor = Cursors.Cross; } public void toolStripButton_新建立管_Click(object sender, EventArgs e) { _mouseState = MouseState.新增立管; Cursor = Cursors.Cross; } private List AddLink(PointF e, bool isdoubleClick, PointF p, float z) { List l = new List(); var node = GetObj_by_ScreenPoint(e); 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.新增管线 || _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.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; public void MapViewer_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Escape) { Cursor = _lastCursor; if (_isPainting) { _select_junction1 = null; _isPainting = false; SetMapInvalidate(); } else if (_isDragging) { _isDragging = false; SetMapInvalidate(); } else if (_isPanning) { _isPanning = false; SetMapInvalidate(); } else if (_isRotating) { Rotation = Rotation0; _isRotating = false; SetMapInvalidate(); } else if (_isMovingObject) { _NewNet.Clear(); _isMovingObject = false; SetMapInvalidate(); } else if (_mouseState != MouseState.无) { _mouseState = MouseState.无; Cursor = Cursors.Default; } else if (_isInsertingObject) { _NewNet.Clear(); _isInsertingObject = false; _OperaNode = null; SetMapInvalidate(); } else { _Nodes.ForEach(o => ((NodeViewModel)o).Selected = false); _Links.ForEach(o => ((LinkViewModel)o).Selected = false); selectedObjs.Clear(); SetMapInvalidate(); } } if (IsEditMode && e.KeyCode == Keys.Delete) { DeleteChoosedObj(); } if (e.KeyCode == Keys.A && e.Modifiers == Keys.Control) { selectedObjs.Clear(); _Nodes.ForEach(o => { ((NodeViewModel)o).Selected = true; selectedObjs.Add((NodeViewModel)o); }); _Links.ForEach(o => { ((LinkViewModel)o).Selected = true; selectedObjs.Add((LinkViewModel)o); }); SetMapInvalidate(); } } private void MapViewer_KeyPress(object sender, KeyPressEventArgs e) { if (IsEditMode && ctrlPressed && e.KeyChar == 'Z' - 64) { // 执行相应的操作 buttonUndo_Click(sender, e); ctrlPressed = false; // 防止默认操作 e.Handled = true; } if (IsEditMode && 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 (IsEditMode && e.Control && e.KeyCode == Keys.Z) { ctrlPressed = true; // 防止默认操作 e.IsInputKey = true; } if (IsEditMode && 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.Z)); 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.Z); 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.Z = obj.Z; 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); } SetMapInvalidate(); } 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(); SetMapInvalidate(); } #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 分析工具 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; } 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 btn_拓扑检查_Click(object sender, EventArgs e) { Dictionary> result = _network.CheckValidate(); if (result.Count > 0) { ListBox listBox1 = new ListBox(); listBox1.Dock = DockStyle.Fill; listBox1.Width = 200; listBox1.Height = 400; listBox1.Items.AddRange(result.Keys.ToArray()); listBox1.SelectedIndexChanged += (s, e) => { //listBox2.Items.Clear(); if (listBox1.SelectedIndex >= 0) { var arr = result[listBox1.SelectedItem.ToString()].ToHashSet(); List Objs = new List(); Objs.AddRange(_Nodes.Select(n => (NodeViewModel)n)); Objs.AddRange(_Links.Select(l => (LinkViewModel)l)); var nodes = _Nodes.FindAll(o => arr.Contains(o.ID)); var links = _Links.FindAll(o => arr.Contains(o.ID)); //listBox2.Items.AddRange(result[listBox1.SelectedItem.ToString()].ToArray()); selectedObjs.ForEach(obj => obj.Selected = false); selectedObjs.Clear(); nodes.ForEach(obj => { obj.Selected = true; selectedObjs.Add((NodeViewModel)obj); }); links.ForEach(obj => { obj.Selected = true; selectedObjs.Add((LinkViewModel)obj); }); SelectedObjectsChanged?.Invoke(this, selectedObjs); SetMapInvalidate(); } }; Form ResultForm = new Form(); ResultForm.Text = "拓扑检查结果"; ResultForm.Width = 300; ResultForm.Height = 400; ResultForm.StartPosition = FormStartPosition.CenterScreen; ResultForm.Controls.Add(listBox1); ResultForm.MinimizeBox = false; ResultForm.MaximizeBox = false; ResultForm.Show(); } else { MessageBox.Show("拓扑检查通过"); } } 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.Select(oo => oo as LinkViewModel).ToList().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); } }); } } SelectedObjectsChanged?.Invoke(this, 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.ViewLinks) { 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(); 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.ViewLinks) { 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.ViewLinks) { 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 TraversePipeNetworkALL(LinkViewModel startLink, HashSet visitedNodes = null, int direction = 0) { 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 (direction == 1 && currentLink.EN_FLOW >= 0 && node == currentLink.StartNode) continue; if (direction == -1 && currentLink.EN_FLOW <= 0 && node == currentLink.EndNode) continue; 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.ViewLinks) { 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) { IsShowJunction = true; SetMapInvalidate(); } private void 隐藏节点ToolStripMenuItem_Click(object sender, EventArgs e) { IsShowJunction = false; SetMapInvalidate(); } 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; } SetMapInvalidate(); } private void 显示阀门ToolStripMenuItem_Click(object sender, EventArgs e) { IsShowValve = true; SetMapInvalidate(); } private void 隐藏阀门ToolStripMenuItem_Click(object sender, EventArgs e) { IsShowValve = false; SetMapInvalidate(); } 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; } SetMapInvalidate(); } #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.Z == 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.Z * weight; weightSum += weight; } float average = sum / weightSum; node.Z = average; num++; } } } return num; } private void FindNonZeroNeighbors(NodeViewModel node, List result, HashSet origin) { foreach (LinkViewModel link in node.ViewLinks) { NodeViewModel neighbor = null; if (link.StartNode == node) { neighbor = link.EndNode; } else { neighbor = link.StartNode; } if (neighbor.Z != 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.Z }; 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 Settings(new Guid().ToString(), "新建", "复制", TemplateType.其他); string json = File.ReadAllText(ofd.FileName); _network = JsonConvert.DeserializeObject(json); _network.BuildRelation(); TemplateList.AddTemp(_Template); LoadData(); } } public void buttonUndo_Click(object sender, EventArgs e) { SetMapInvalidate(); SelectedObjectsChanged?.Invoke(this, null); MapObjectExtensions.Undo(); } public void buttonRedo_Click(object sender, EventArgs e) { SetMapInvalidate(); SelectedObjectsChanged?.Invoke(this, null); MapObjectExtensions.Redo(); } 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(); if (objs.Count == 0) selectedObjs.FindAll(o => o is NodeViewModel).Select(o => o as NodeViewModel).ToList().ForEach(o => objs.AddRange(o.Links.Select(l => l as LinkViewModel).ToList())); //objs去掉重复的元素 objs = objs.Distinct().ToList(); var visitedNodes = new HashSet(); objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes)); this.SetMapInvalidate(); } } 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(); if (objs.Count == 0) selectedObjs.FindAll(o => o is NodeViewModel).Select(o => o as NodeViewModel).ToList().ForEach(o => { objs.AddRange(o.Links.Select(oo => oo as LinkViewModel).ToList().FindAll(oo => oo.StartNode == o ? oo.EN_FLOW > 0 : oo.EN_FLOW < 0)); }); //objs去掉重复的元素 objs = objs.Distinct().ToList(); var visitedNodes = new HashSet(); objs.ForEach(o => TraversePipeNetworkALL(o, visitedNodes, 1)); this.SetMapInvalidate(); } } 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; } bool _isSettingBackGroundPictur = false; private bool __needpaintall = false; #endregion } }