using Hydro.MapView; using Hydro.MapView.Base; using Hydro.MapView.Common; using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using System.Numerics; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace Hydro.MapUI { partial class empty { } //定义一个委托,用来存储void Draw(Graphics bufferG, Template template) public delegate void DrawDelegate(Graphics bufferG, Template template); public delegate void MouseDelegate(MouseEventArgs e); partial class MapViewer { void DrawBackGroud(Graphics bufferG,Template template) { if (template == null) return; var _Nodes = template.network.Nodes.ViewNodes; var _Links = template.network.Links.ViewLinks; var Cpoints = getCurclePoints(64).ToList(); var r = 1.73f / zoom; var rt = r; float minElve = float.MinValue; float maxElve = 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); //背景图绘制 if (this.mapOption.isShowPic && template != null && File.Exists(template.BackGroundImg_FullPath)) { //var gs = bufferG.Save(); // 应用矩阵变换以抵消之前的翻转效果 //bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y); List p = new List(); if (!this.mapOption.isAutoBackgroundImage) { var Cps = new List { template.BackGroundPoint1, new PointF(template.BackGroundPoint2.X,template.BackGroundPoint1.Y), new PointF(template.BackGroundPoint1.X,template.BackGroundPoint2.Y), //template.BackGroundPoint2, }; Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet))); } else { // 恢复之前保存的绘图状态 //var Cps = new List //{ // template.BackGroundPoint1, // new PointF(template.BackGroundPoint2.X,template.BackGroundPoint1.Y), // new PointF(template.BackGroundPoint1.X,template.BackGroundPoint2.Y), // //template.BackGroundPoint2, //}; var p1 = new PointF(template.BackGroundImgX, template.BackGroundImgY); var p2 = new PointF(template.BackGroundImgX + template.BackGroundImgWidth, template.BackGroundImgY + template.BackGroundImgHeight); var f = template.BackGroundImgRotaAngle / 180 * Math.PI; var djx = Math.Sqrt((Math.Pow(template.BackGroundImgWidth, 2) + Math.Pow(template.BackGroundImgHeight, 2))); var p3 = new PointF(p1.X + (float)(Math.Cos(f) * template.BackGroundImgWidth), p1.Y + (float)(Math.Sin(f) * template.BackGroundImgWidth)); var p4 = new PointF(p1.X - (float)(Math.Sin(f) * template.BackGroundImgHeight), p1.Y + (float)(Math.Cos(f) * template.BackGroundImgHeight)); p3.Y = p4.Y; //p4.Y = -p4.Y; var Cps = new List { //template.BackGroundPoint1, //new PointF(template.BackGroundImgX,template.BackGroundImgY), p4, p3,p1 //template.BackGroundPoint2, }; template.BackGroundPoint1 = p4; template.BackGroundPoint2 = new PointF(p3.X, p1.Y); //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); } } void Draw(Graphics bufferG, Template template) { if (template == null) return; var _Nodes = template.network.Nodes.ViewNodes; var _Links = template.network.Links.ViewLinks; var _Areas = template.network.Areas; var Cpoints = getCurclePoints(64).ToList(); var r = 1.73f / zoom; var rt = r; 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); Pen penHovered = new Pen(Color.DeepSkyBlue, 5 * r); //绘制面 using (Pen pen0 = new Pen(Color.FromArgb(0, 0, 255), 2 * r)) { foreach (var area in _Areas) { if (!area.Visible) continue; if (!IsFaceVisibleToCamera(area, GetCameraPosition())) continue; if (area.Elev < minElve || area.Elev >= maxElve) continue; var p = new List(); foreach (var node in area.InnerNodes) { p.Add(CubeWorldPointToMapPoint(node, template.OffSet)); } if (p.Count < 3) continue; pen0.Color = penClosed.Color = area.color; Pen pen = pen0; if (area.Hovered) pen = penHovered; bufferG.FillPolygon(pen.Brush, p.ToArray()); bufferG.DrawPolygon(pen, p.ToArray()); //显示area的名称 var c = new PointF(p.Average(p0 => p0.X), p.Average(p0 => p0.Y)); var brush=new SolidBrush(Color.White); var gs = bufferG.Save(); // 应用矩阵变换以抵消之前的翻转效果 bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y); Font font = new Font(FontFamily.GenericSansSerif, 10*10*zoom); SizeF textSize = bufferG.MeasureString(area.Name, font); var center = new PointF(c.X * Zoom.X, c.Y * Zoom.Y); float textLeft = center.X - textSize.Width / 2; float textTop = center.Y - textSize.Height / 2; PointF pd = new PointF(textLeft, textTop); bufferG.DrawString(area.Name, font, brush, pd); // 恢复之前保存的绘图状态 bufferG.Restore(gs); } } // 绘制线 HashSet dict_flow_direction = new HashSet(); using (Pen pen0 = new Pen(Color.FromArgb(0, 0, 255), 2 * r)) { foreach (var link in _Links) { if (!link.Visible) continue; if (link.Elev < minElve || link.Elev >= maxElve) continue; //if (_isMovingObject && (link.StartNode == _OperaNode || link.EndNode == _OperaNode)) continue; var p1 = WorldPointToMapPoint(link.StartNode, template.OffSet); var p2 = WorldPointToMapPoint(link.EndNode, template.OffSet); if (!isVisible(p1) && !isVisible(p2)) continue; if (LinkColour != null) { pen0.Color = penClosed.Color = GraphHelper.getLinkColor(LinkColour, link); } Pen pen = pen0; #if DEBUG #else if (_Template != null && _Template.mapOption._ShowStatus && link.Status == Hydro.Core.ObjectEnum.StatusType.CLOSED) pen = penClosed; #endif if (link.Hovered) pen = penHovered; float zoomAtMin = 0; for (int i = 0; i < diametersZoom.Count; i++) { PointF point = diametersZoom[i]; if (link.Diameter >= point.X) continue; zoomAtMin = diametersZoom[i - 1].Y; break; } if (zoomAtMin >= zoom) continue; if (link is ValveViewModel) { if (link.Selected || _ShowValve) { var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 }); var valveShapeHeight = link.Selected ? 10 : 5; PointF[] points = new PointF[] { GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2), GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2), GraphHelper.getRotatePoint(c.X + valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2), GraphHelper.getRotatePoint(c.X + valveShapeHeight * r, c.Y - valveShapeHeight * r,c,p1,p2), GraphHelper.getRotatePoint(c.X - valveShapeHeight * r, c.Y + valveShapeHeight * r,c,p1,p2), }; bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points); } } else if (link is PumpViewModel) { if (link.Selected || _ShowValve) { var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); //bufferG.DrawLine(link.Selected ? pen_valveChoosed : pen, p1, p2); bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 }); // 绘制圆形部分(水泵的泵体) float radius = 5 * r; float diameter = radius * 2; #region 圆形拆分 //var p = new PointF[] //{ // GraphHelper.getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2), // GraphHelper.getRotatePoint(c.X + radius - radius, c.Y - radius, c, p1, p2), // GraphHelper.getRotatePoint(c.X + radius - radius, c.Y + radius, c, p1, p2), // GraphHelper.getRotatePoint(c.X - radius - radius, c.Y + radius, c, p1, p2), // GraphHelper.getRotatePoint(c.X - radius - radius, c.Y - radius, c, p1, p2), //}; List p = new List(); Cpoints.ForEach(cp => p.Add(GraphHelper.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[] { GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2), GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y ,c,p1,p2), GraphHelper.getRotatePoint(c.X + valveShapeHeight , c.Y ,c,p1,p2), GraphHelper.getRotatePoint(c.X + valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2), GraphHelper.getRotatePoint(c.X - valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2), }; 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 = GraphHelper.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; try { bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 }); } catch (Exception ex) { } if (_Template.mapOption._ShowFlowDirection) { var c = new PointF((p1.X + p2.X) / 2, (p1.Y + p2.Y) / 2); var ps = MapToScreen(c); //将ps转换为ulong,精度为20,并加入到dict_flow_direction中 var ps_20 = GraphHelper.GetUlongByPoint(ps, 5); if (!dict_flow_direction.Contains(ps_20)) { dict_flow_direction.Add(ps_20); bufferG.DrawLines(link.Selected ? penChoosed : pen, new PointF[] { p1, p2 }); // 绘制圆形部分(水泵的泵体) float radius = 5 * r; float diameter = radius * 2; #region 圆形拆分 float activeD = 1; if (link.EN_FLOW < 0) activeD = -1; List p = new List(); Cpoints.ForEach(cp => p.Add(GraphHelper.getRotatePoint(c.X - activeD * cp.X * radius + activeD * radius, c.Y + cp.Y * radius, c, p1, p2))); #endregion bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray()); var valveShapeHeight = link.Selected ? radius * 2 : radius; PointF[] points = new PointF[] { GraphHelper.getRotatePoint(c.X -activeD* valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2), GraphHelper.getRotatePoint(c.X , c.Y ,c,p1,p2), GraphHelper.getRotatePoint(c.X - activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2), GraphHelper.getRotatePoint(c.X + activeD*valveShapeHeight , c.Y - valveShapeHeight,c,p1,p2), GraphHelper.getRotatePoint(c.X + activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2), GraphHelper.getRotatePoint(c.X - activeD*valveShapeHeight , c.Y + valveShapeHeight ,c,p1,p2), }; bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, points); } } } } } r = rt; HashSet dict_point = new HashSet(); //绘制点 penChoosed = new Pen(Color.Green, 1f * r); Brush brushChoosed = penChoosed.Brush; SolidBrush whiteBrush = new SolidBrush(Color.White); using (Pen pen0 = new Pen(Color.FromArgb(255, 0, 0), 1 * r)) { foreach (NodeViewModel node in _Nodes) { if (!node.Visible) continue; if (node.Elev < minElve || node.Elev >= maxElve) continue; Pen pen = pen0; Brush brush = pen.Brush; float pr = (float)(r * 0.5); pr = pr * junction_multiply; PointF p = WorldPointToMapPoint(node, template.OffSet); if (!isVisible(p)) continue; var ps_20 = GraphHelper.GetUlongByPoint(p, 0.1f); if (dict_point.Contains(ps_20)) continue; dict_point.Add(ps_20); //var x = junction.Position.X * zoom + PanningOffset.X - radius / 2.0f; //var y = junction.Position.Y * zoom + PanningOffset.Y - radius / 2.0f; if (NodeColour != null) { pen.Color = penChoosed.Color = GraphHelper.getNodeColor(NodeColour, node); brush = pen.Brush; brushChoosed = penChoosed.Brush; } if (node.Hovered) { pen = penHovered; brush = pen.Brush; pr = pr * 2; } var rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr); float zoomAtMin = 0; for (int i = 0; i < diametersZoom.Count; i++) { PointF point = diametersZoom[i]; if (node.MaxDiameter >= point.X) continue; zoomAtMin = diametersZoom[i - 1].Y; break; } if (zoomAtMin >= zoom) continue; //if(node.ID == _StartPoint) //{ // var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr); // bufferG.FillEllipse(whiteBrush, whiteRect); // whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr); // bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect); // whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr); // bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect); //} //else if (node == _OperaNode) { //bufferG.DrawEllipse(junction.Choosed ? penChoosed : pen, rectangle); var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr); bufferG.FillEllipse(whiteBrush, whiteRect); whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr); bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect); 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 { rectangle = new RectangleF((float)p.X - 3 * pr, (float)p.Y - 3 * pr, 6 * pr, 6 * pr); if (node.Selected || _ShowJunction) bufferG.FillEllipse(node.Selected ? brushChoosed : brush, rectangle); } } } using (Pen pen = new Pen(Color.FromArgb(255, 0, 0), 1 * r)) { Brush brush = pen.Brush; //获取_Nodes中自由水压最小的节点 var node = _Nodes.Where(n => n is JunctionViewModel || n is MeterViewModel && n.EN_PRESSURE != float.NaN).OrderBy(n => n.EN_PRESSURE).FirstOrDefault(); //判断node.EN_PRESSURE不是float.NaN if (node != null && !float.IsNaN(node.EN_PRESSURE)) { //if (node.Elev < minElve || node.Elev >= maxElve) continue; float pr = (float)(r * 0.5); pr = pr * junction_multiply; PointF p = WorldPointToMapPoint(node, template.OffSet); var ps_20 = GraphHelper.GetUlongByPoint(p, 0.1f); dict_point.Add(ps_20); //var x = junction.Position.X * zoom + PanningOffset.X - radius / 2.0f; //var y = junction.Position.Y * zoom + PanningOffset.Y - radius / 2.0f; if (NodeColour != null) { pen.Color = GraphHelper.getNodeColor(NodeColour, node); brush = pen.Brush; brushChoosed = penChoosed.Brush; } var rectangle = new RectangleF((float)p.X - 5 * pr, (float)p.Y - 5 * pr, 10 * pr, 10 * pr); float zoomAtMin = 0; for (int i = 0; i < diametersZoom.Count; i++) { PointF point = diametersZoom[i]; if (node.MaxDiameter >= point.X) continue; zoomAtMin = diametersZoom[i - 1].Y; break; } //var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr); //bufferG.FillEllipse(whiteBrush, whiteRect); //whiteRect = new RectangleF(rectangle.X + 2 * pr, rectangle.Y + 2 * pr, rectangle.Width - 4 * pr, rectangle.Height - 4 * pr); //bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect); //whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr); //bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect); var p1 = new PointF((float)p.X - 4 * pr, (float)p.Y - 2 * pr); var p2 = new PointF((float)p.X + 4 * pr, (float)p.Y - 2 * pr); var p3 = new PointF((float)p.X, (float)p.Y - 4 * pr); bufferG.DrawPolygon(node.Selected ? penChoosed : pen, new PointF[] { p1, p2, p3 }); var whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr); bufferG.FillEllipse(whiteBrush, whiteRect); whiteRect = new RectangleF(rectangle.X - 4 * pr, rectangle.Y - 4 * pr, rectangle.Width + 8 * pr, rectangle.Height + 8 * pr); bufferG.DrawEllipse(node.Selected ? penChoosed : pen, whiteRect); } } } //绘制辅助线 void DrawH(Graphics bufferG, Template template) { var r = 2f / zoom; if (_isDragging && DragStartPos != new PointF(0, 0) && mousePosition != new PointF(0, 0)) { label_center.Text = $"S:{DragStartPos.X}:{DragStartPos.Y} E:{mousePosition.X}:{mousePosition.Y}"; var _lastMousePosition = DragStartPos; // 绘制矩形 var start = new PointF((float)Math.Min(mousePosition.X, _lastMousePosition.X), (float)Math.Min(mousePosition.Y, _lastMousePosition.Y)); var size = new SizeF((float)Math.Abs(_lastMousePosition.X - mousePosition.X), (float)Math.Abs(_lastMousePosition.Y - mousePosition.Y)); if (size.Width == 0) size.Width = 0.01f; if (size.Height == 0) size.Height = 0.01f; var rectangle0 = new RectangleF(start, size); using (var pen = new Pen(Color.Black, 0.5f * r)) { bufferG.DrawRectangles(pen, new RectangleF[] { rectangle0 }); } } if (_isPainting) { if (_mouseState == MapViewEnum.MouseState.新增立管) { var wPos = GetZZWorldPoint(_select_junction1.Position3D, _MousePosition, new Vector3(0, 0, 1)); using (var pen = new Pen(Color.Black, 1 * r)) { pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), WorldPointToMapPoint(wPos)); } } else { using (var pen = new Pen(Color.Black, 1 * r)) { pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; if (mapOption.IsOrtho) { var wPos = GetZZWorldPoint(_select_junction1.Position3D, _MousePosition, new Vector3(1, 1, 0)); //getPointAndHeight(e, _select_junction1, out p, out z); var mapPos = WorldPointToMapPoint(wPos); bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), mapPos); } else { bufferG.DrawLine(pen, WorldPointToMapPoint(_select_junction1), _MousePosition); } } } } 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 _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()); } } } #region 基础坐标转换方法 /// /// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。 /// /// /// private PointF ScreenToVMap(PointF screenPos, float z = 0) { var centerX = this.map.Width / 2; var centerY = this.map.Height / 2; var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X; var worldY = (screenPos.Y - centerY) / Zoom.Y + 0; //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 = this.map.Width / 2; var centerY = this.map.Height / 2; var worldX = (screenPos.X - centerX - Z(z).X) / Zoom.X + MapCenter.X; var worldY = (screenPos.Y - centerY - Z(z).Y) / Zoom.Y + MapCenter.Y; //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 = this.map.Width / 2; var centerY = this.map.Height / 2; var screenX = (mapPos.X - MapCenter.X) * Zoom.X + centerX + Z(z).X; var screenY = (mapPos.Y - MapCenter.Y) * Zoom.Y + centerY + Z(z).Y; //if (is3Dview) screenY = -(mapPos.Y - center.Y) * (0.5f * zoom) + centerY - 2 * z; return new PointF(screenX, screenY); } // 根据旋转角度计算旋转后的坐标 // 根据旋转角度计算旋转后的坐标 private PointF Get平面旋转Point(PointF p, PointF MapC) { PointF center = MapC ; double radian = Rotation * Math.PI / 180; // 角度转弧度 float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X); float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y); return new PointF(x, y); } private PointF Get平面还原Point(PointF p, PointF MapC) { PointF center = MapC; double radian = -Rotation * Math.PI / 180; // 角度转弧度 float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X); float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y); return new PointF(x, y); } private PointF Get俯视角旋转Point(PointF p, float z, PointF MapC) { PointF center = MapC; double radian_fushi = 俯视弧度; float sin = (float)Math.Sin(radian_fushi); float cos = (float)Math.Cos(radian_fushi); float x = (float)p.X; float y = (float)(sin * (p.Y - center.Y) + center.Y) + cos * z; return new PointF(x, y); } private PointF Get俯视角还原Point(PointF p, float z, PointF MapC) { PointF center = MapC; double radian_fushi = 俯视弧度; float sin = (float)Math.Sin(radian_fushi); float cos = (float)Math.Cos(radian_fushi); float x = (float)p.X; float y = (p.Y - center.Y - cos * z) / sin + center.Y; return new PointF(x, y); } private PointF GetRotateVector(PointF p, PointF p0) { double radian = Rotation * Math.PI / 180; // 角度转弧度 float x = (float)(Math.Cos(radian) * (p.X - p0.X) - Math.Sin(radian) * (p.Y - p0.Y)); float y = (float)(Math.Sin(radian) * (p.X - p0.X) + Math.Cos(radian) * (p.Y - p0.Y)); return new PointF(x, y); } /// /// 获取世界投影坐标 /// /// /// /// private PointF 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, MapCenter); var pointT = Get俯视角旋转Point(pointR, z + offset.Z, MapCenter); //var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y)); return pointT; } private PointF WorldPointToMapPoint(PointF3D point, PointF3D offset = null) { return WorldPointToMapPoint(new PointF(point.X, point.Y), point.Z, offset); } private PointF WorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null) { PointF p; if (junction == null) return new PointF(0, 0); p = WorldPointToMapPoint(junction.Position, junction.Elev, offset); return p; } private PointF CubeWorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null) { PointF p; if (junction == null) return new PointF(0, 0); var point = junction.Position; var z = junction.Elev; if (offset == null) offset = new PointF3D(0, 0, 0); point = new PointF(point.X + offset.X, point.Y + offset.Y); var pointR = Get平面旋转Point(point, new PointF(0, 0)); var pointT = Get俯视角旋转Point(pointR, z + offset.Z, new PointF(0, 0)); //var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y)); return pointT; } 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 PointF3D GetZZWorldPoint(PointF3D position3D, PointF mousePosition, Vector3 vector3) { //做一条通过position3D的平行于vector3的直线, if (vector3 == new Vector3(0, 0, 1)) { return GetLGWorldPoint(position3D, mousePosition); } else { var p2 = MapPointToWorldPoint(mousePosition, position3D.Z); var vector = new Vector2(p2.X - position3D.X, p2.Y - position3D.Y); //判断二维向量vector在第几象限,距离哪个轴最近 var x = vector.X; var y = vector.Y; var x1 = Math.Abs(x); var y1 = Math.Abs(y); if (x1 > y1) { if (x > 0) { //第一象限 return new PointF3D(position3D.X + Math.Abs(x), position3D.Y, position3D.Z); } else { //第三象限 return new PointF3D(position3D.X - Math.Abs(x), position3D.Y, position3D.Z); } } else { if (y > 0) { //第二象限 return new PointF3D(position3D.X, position3D.Y + Math.Abs(y), position3D.Z); } else { //第四象限 return new PointF3D(position3D.X, position3D.Y - Math.Abs(y), position3D.Z); } } } } /// /// 获取正交投影坐标,返回的是世界坐标 /// /// 世界坐标 /// 地图坐标 /// 投影向量 /// /// private PointF3D GetLGWorldPoint(PointF3D position3D, PointF p2) { double radian_fushi = 俯视弧度; float sin = (float)Math.Sin(radian_fushi); float cos = (float)Math.Cos(radian_fushi); var p1 = WorldPointToMapPoint(position3D); var dy = p2.Y - p1.Y; float dz = dy / cos; return new PointF3D(position3D.X, position3D.Y, position3D.Z + dz); } private PointF MapPointToWorldPoint(PointF3D point) { return MapPointToWorldPoint(new PointF(point.X, point.Y), point.Z); } /// /// 获取地图投影坐标 /// /// /// /// public PointF MapPointToWorldPoint(PointF point, float z = 0) { var pointT = Get俯视角还原Point(point, z,MapCenter); pointT = Get平面还原Point(pointT, MapCenter); //var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y)); return pointT; } private PointF GetMapPoint_还原(NodeViewModel junction) { PointF p; p = MapPointToWorldPoint(junction.Position, junction.Elev); return p; } #endregion #region 计算三维相机 public PointF3D GetCameraPosition( float distance=1) { // 将角度转换为弧度 float rotationRadians = (float)Rotation * (float)Math.PI / 180; float rotationFRadians = (float)RotationF * (float)Math.PI / 180; // 计算相机的球坐标系位置 float x = distance * (float)Math.Sin(rotationFRadians) * (float)Math.Cos(rotationRadians); float y = distance * (float)Math.Sin(rotationFRadians) * (float)Math.Sin(rotationRadians); float z = distance * (float)Math.Cos(rotationFRadians); return new PointF3D(x, y, z); } public bool IsFaceVisibleToCamera(AreaViewModel area, PointF3D cameraPosition) { //正面是2,右面是1,左面是3,背面是4 //Rotation为0时,只显示正面,Rotation为90时,只显示右面,Rotation为180时,只显示背面,Rotation为270时,只显示左面 int delta = 5; bool flag = false; switch (area.Name) { case "左": //Rotation为0~180时显示 if (RotationF<=90-delta && Rotation >= 0 + delta && Rotation <= 180 - delta) flag = true; break; case "前": //Rotation为0~180时显示 if (RotationF <= 90 - delta && Rotation >= -90 + delta && Rotation <= 90 - delta) flag = true; break; case "右": //Rotation为0~180时显示 if (RotationF <= 90 - delta && Rotation >= -180 + delta && Rotation <= 0 - delta) flag = true; break; case "后": //Rotation为0~180时显示 if (RotationF <= 90 - delta && ((Rotation >= 90 + delta && Rotation<=180)||( Rotation>=-180 && Rotation <= -90 - delta))) flag = true; break; case "上": if (RotationF >= 0 + delta) flag = true; break; case "下": if (RotationF <= 0 - delta) flag = true; break; } return flag; var faceVertices = area.InnerNodes; if (faceVertices.Count < 3) return false; PointF3D faceVertexA = faceVertices[0].Position3D; PointF3D faceVertexB = faceVertices[1].Position3D; PointF3D faceVertexC = faceVertices[2].Position3D; // 计算法向量 PointF3D AB = faceVertexB - faceVertexA; PointF3D AC = faceVertexC - faceVertexA; PointF3D normal = AB ^ AC; // 计算从相机位置到面的向量 PointF3D PD = faceVertexA - cameraPosition; // 计算点积 float dotProduct = normal * PD; // 判断面是否朝向相机 bool isFacingCamera = dotProduct > 0; return isFacingCamera; } #endregion #region 判断可见性 private float Get_dist(PointF A, PointF B) { float dx = A.X - B.X; float dy = A.Y - B.Y; float dist = (float)Math.Sqrt(dx * dx + dy * dy); return dist; } //判断A距离线段B和C的距离,如果超出了线段的范围,则返回到最近的端点的距离;距离线段中心点越远,返回的距离越大; private float Get_dist(PointF A, PointF B, PointF C, float MaxOff) { //PointF A, PointF B,PointF C,求点A到B、C构成线段的中心点的距离 float dist_off = GetDistanceFromPointAToMidpointOfLineSegmentBC(A, B, C); //使用dist_off 跟 线段A、B的长度比较,如果大于1/2,则返回MaxOff,否则按照比例返回 float dist_len = Get_dist(B, C); if (dist_len < 5) dist_len = 5; float dist_add = (dist_off / dist_len > 0.5 ? MaxOff : dist_off / dist_len * 2 * MaxOff); float dx = C.X - B.X; float dy = C.Y - B.Y; float dist = (float)Math.Sqrt(dx * dx + dy * dy); if (dist == 0) return Get_dist(A, B) + dist_add; float t = ((A.X - B.X) * dx + (A.Y - B.Y) * dy) / (dist * dist); if (t < 0) return Get_dist(A, B) + dist_add; if (t > 1) return Get_dist(A, C) + dist_add; float x = B.X + t * dx; float y = B.Y + t * dy; return Get_dist(A, new PointF(x, y)) + dist_add; } private float GetDistanceFromPointAToMidpointOfLineSegmentBC(PointF A, PointF B, PointF C) { // Calculate the midpoint of the line segment BC PointF midpoint = new PointF((B.X + C.X) / 2, (B.Y + C.Y) / 2); // Calculate the distance from point A to the midpoint float dx = midpoint.X - A.X; float dy = midpoint.Y - A.Y; float distance = (float)Math.Sqrt(dx * dx + dy * dy); return distance; } PointF PMin_Show, PMax_Show; /// /// 判断是否在屏幕坐标内 /// /// /// 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 } }