using Hydro.MapView;
|
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 Draw(Graphics bufferG, Template template)
|
{
|
if (template == null) return;
|
var _Nodes = template.network.Nodes.ViewNodes;
|
var _Links = template.network.Links.ViewLinks;
|
|
var Cpoints = getCurclePoints(64).ToList();
|
|
var r = 1.73f / zoom;
|
var rt = r;
|
|
float minElve = float.MinValue;
|
float maxElve = float.MaxValue;
|
//if (this.mapOption!=null && this.mapOption.ShowFloor!=int.MinValue )
|
//{
|
// var fl = template.Floors.Find(f => f.FloorIndex == this.mapOption.ShowFloor);
|
// var fl_1 = template.Floors.Find(f => f.FloorIndex == this.mapOption.ShowFloor+1);
|
// if (fl!=null)
|
// {
|
// minElve = fl.Elev;
|
|
// maxElve = fl_1!=null ? fl_1.Elev : float.MaxValue;
|
// }
|
|
//}
|
r = r * Link_multiply;
|
List<PointF> diametersZoom = new List<PointF>() { new PointF(0, 0.08f), new PointF(150, 0.03f), new PointF(300, 0.001f), new PointF(800, 0.0001f) };
|
|
Pen penN = new Pen(Color.FromArgb(0, 0, 255), 1 * r);
|
|
Pen penChoosed = new Pen(Color.Purple, 5 * r);
|
Pen pen_valveChoosed = new Pen(Color.Red, 5 * r);
|
|
Pen penClosed = new Pen(Color.OrangeRed, 2 * r);
|
Pen penHovered = new Pen(Color.DeepSkyBlue, 5 * r);
|
//背景图绘制
|
if (this.mapOption.isShowPic && template != null && File.Exists(template.BackGroundImg_FullPath))
|
|
|
{
|
//var gs = bufferG.Save();
|
// 应用矩阵变换以抵消之前的翻转效果
|
//bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
|
|
|
|
// 恢复之前保存的绘图状态
|
|
var Cps = new List<PointF>
|
{
|
template.BackGroundPoint1,
|
new PointF(template.BackGroundPoint2.X,template.BackGroundPoint1.Y),
|
new PointF(template.BackGroundPoint1.X,template.BackGroundPoint2.Y),
|
//template.BackGroundPoint2,
|
|
|
};
|
|
|
|
List<PointF> p = new List<PointF>();
|
Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet)));
|
|
//bufferG.DrawImage(System.Drawing.Image.FromFile(@"C:\Users\cloud\Pictures\GenshinImpactCloudGame\QQ截图20230919105637.png"), p[0]);
|
try
|
{
|
var img = System.Drawing.Image.FromFile(template.BackGroundImg_FullPath);
|
if (img != null)
|
{
|
bufferG.FillPolygon(penN.Brush, p.ToArray());
|
bufferG.DrawImage(img, p.ToArray());
|
}
|
}
|
catch
|
{
|
|
}
|
|
//bufferG.Restore(gs);
|
}
|
|
|
// 绘制线
|
|
HashSet<long> dict_flow_direction = new HashSet<long>();
|
using (Pen pen0 = new Pen(Color.FromArgb(0, 0, 255), 2 * r))
|
{
|
|
foreach (var link in _Links)
|
{
|
if (!link.Visible) continue;
|
if (link.Elev < minElve || link.Elev >= maxElve) continue;
|
//if (_isMovingObject && (link.StartNode == _OperaNode || link.EndNode == _OperaNode)) continue;
|
var p1 = WorldPointToMapPoint(link.StartNode, template.OffSet);
|
var p2 = WorldPointToMapPoint(link.EndNode, template.OffSet);
|
if (!isVisible(p1) && !isVisible(p2)) continue;
|
if (LinkColour != null)
|
{
|
pen0.Color = penClosed.Color = 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<PointF> p = new List<PointF>();
|
Cpoints.ForEach(cp => p.Add(GraphHelper.getRotatePoint(c.X + cp.X * radius - radius, c.Y + cp.Y * radius, c, p1, p2)));
|
|
#endregion
|
|
//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<PointF> p = new List<PointF>();
|
Cpoints.ForEach(cp => p.Add(GraphHelper.getRotatePoint(c.X - activeD * cp.X * radius + activeD * radius, c.Y + cp.Y * radius, c, p1, p2)));
|
|
#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<long> dict_point = new HashSet<long>();
|
//绘制点
|
penChoosed = new Pen(Color.Green, 1f * r);
|
Brush brushChoosed = penChoosed.Brush;
|
SolidBrush whiteBrush = new SolidBrush(Color.White);
|
|
using (Pen pen0 = new Pen(Color.FromArgb(255, 0, 0), 1 * r))
|
{
|
|
foreach (NodeViewModel node in _Nodes)
|
{
|
if (!node.Visible) continue;
|
if (node.Elev < minElve || node.Elev >= maxElve) continue;
|
Pen pen = pen0;
|
Brush brush = pen.Brush;
|
float pr = (float)(r * 0.5);
|
pr = pr * junction_multiply;
|
PointF p = WorldPointToMapPoint(node, template.OffSet);
|
if (!isVisible(p)) continue;
|
var ps_20 = 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<PointF> pf = polygonPoints.ToList();
|
pf.Add(new PointF(mousePosition.X, mousePosition.Y));
|
using (var pen = new Pen(Color.Black, 1 * r))
|
{
|
// 绘制多边形虚线边框
|
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
|
bufferG.DrawLines(pen, pf.ToArray());
|
}
|
}
|
if (_isSettingBackGroundPictur)
|
{
|
|
var _lastMousePosition = DragStartPos;
|
// 绘制矩形
|
var start = new PointF((float)Math.Min(mousePosition.X, _lastMousePosition.X), (float)Math.Min(mousePosition.Y, _lastMousePosition.Y));
|
var size = new SizeF((float)Math.Abs(_lastMousePosition.X - mousePosition.X), (float)Math.Abs(_lastMousePosition.Y - mousePosition.Y));
|
var rectangle0 = new RectangleF(start, size);
|
using (var pen = new Pen(Color.Black, 1 * r))
|
{
|
bufferG.DrawRectangles(pen, new RectangleF[] { rectangle0 });
|
}
|
}
|
|
if (_isMovingObject)
|
{
|
var newP = _MousePosition;
|
//var p = MapPointToWorldPoint(, _OperaNode.Elev);
|
var oldP3D = (PointF3D)_undoOldValue;
|
var oldP = WorldPointToMapPoint(new PointF(oldP3D.X, oldP3D.Y), oldP3D.Z);
|
List<PointF> pf = new List<PointF> { oldP, newP };
|
using (var pen = new Pen(Color.Black, 1 * r))
|
{
|
// 绘制多边形虚线边框
|
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
|
bufferG.DrawLines(pen, pf.ToArray());
|
}
|
}
|
}
|
|
#region 基础坐标转换方法
|
/// <summary>
|
/// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
|
/// </summary>
|
/// <param name="screenPos"></param>
|
/// <returns></returns>
|
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);
|
}
|
|
|
/// <summary>
|
/// 将屏幕坐标转换为世界坐标。输入屏幕坐标 (x,y),返回世界坐标 (wx, wy)。
|
/// </summary>
|
/// <param name="screenPos"></param>
|
/// <returns></returns>
|
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 center = MapCenter;
|
double radian = Rotation * Math.PI / 180; // 角度转弧度
|
float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X);
|
float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y);
|
return new PointF(x, y);
|
}
|
private PointF Get平面还原Point(PointF p)
|
{
|
PointF center = MapCenter;
|
double radian = -Rotation * Math.PI / 180; // 角度转弧度
|
float x = (float)(Math.Cos(radian) * (p.X - center.X) - Math.Sin(radian) * (p.Y - center.Y) + center.X);
|
float y = (float)(Math.Sin(radian) * (p.X - center.X) + Math.Cos(radian) * (p.Y - center.Y) + center.Y);
|
return new PointF(x, y);
|
}
|
|
|
|
private PointF Get俯视角旋转Point(PointF p, float z)
|
{
|
PointF center = MapCenter;
|
double radian_fushi = 俯视弧度;
|
float sin = (float)Math.Sin(radian_fushi);
|
float cos = (float)Math.Cos(radian_fushi);
|
float x = (float)p.X;
|
float y = (float)(sin * (p.Y - center.Y) + center.Y) + cos * z;
|
return new PointF(x, y);
|
}
|
private PointF Get俯视角还原Point(PointF p, float z)
|
{
|
PointF center = MapCenter;
|
double radian_fushi = 俯视弧度;
|
float sin = (float)Math.Sin(radian_fushi);
|
float cos = (float)Math.Cos(radian_fushi);
|
float x = (float)p.X;
|
float y = (p.Y - center.Y - cos * z) / sin + center.Y;
|
return new PointF(x, y);
|
}
|
|
|
private PointF GetRotateVector(PointF p, PointF p0)
|
{
|
|
double radian = Rotation * Math.PI / 180; // 角度转弧度
|
float x = (float)(Math.Cos(radian) * (p.X - p0.X) - Math.Sin(radian) * (p.Y - p0.Y));
|
float y = (float)(Math.Sin(radian) * (p.X - p0.X) + Math.Cos(radian) * (p.Y - p0.Y));
|
return new PointF(x, y);
|
}
|
/// <summary>
|
/// 获取地图投影坐标
|
/// </summary>
|
/// <param name="point"></param>
|
/// <param name="z"></param>
|
/// <returns></returns>
|
private PointF WorldPointToMapPoint(PointF point, float z, PointF3D offset = null)
|
{
|
if (offset == null) offset = new PointF3D(0, 0, 0);
|
point = new PointF(point.X + offset.X, point.Y + offset.Y);
|
|
var pointR = Get平面旋转Point(point);
|
|
var pointT = Get俯视角旋转Point(pointR, z + offset.Z);
|
|
//var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y));
|
return pointT;
|
}
|
private PointF WorldPointToMapPoint(PointF3D point, PointF3D offset = null)
|
{
|
return WorldPointToMapPoint(new PointF(point.X, point.Y), point.Z, offset);
|
|
}
|
private PointF WorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null)
|
{
|
PointF p;
|
if (junction == null) return new PointF(0, 0);
|
p = WorldPointToMapPoint(junction.Position, junction.Elev, offset);
|
return p;
|
|
}
|
private List<PointF> WorldPointToMapPoint(LinkViewModel pipe, PointF3D offset = null)
|
{
|
List<PointF> list = new List<PointF>();
|
|
PointF p;
|
p = WorldPointToMapPoint(pipe.StartNode, offset);
|
list.Add(p);
|
p = WorldPointToMapPoint(pipe.EndNode, offset);
|
list.Add(p);
|
return list;
|
|
}
|
/// <summary>
|
/// 获取正交投影坐标,返回的是世界坐标
|
/// </summary>
|
/// <param name="position3D">世界坐标</param>
|
/// <param name="mousePosition">地图坐标</param>
|
/// <param name="vector3">投影向量</param>
|
/// <returns></returns>
|
/// <exception cref="NotImplementedException"></exception>
|
private PointF3D GetZZWorldPoint(PointF3D position3D, PointF mousePosition, Vector3 vector3)
|
{
|
//做一条通过position3D的平行于vector3的直线,
|
if (vector3 == new Vector3(0, 0, 1))
|
{
|
return GetLGWorldPoint(position3D, mousePosition);
|
}
|
else
|
{
|
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);
|
}
|
}
|
}
|
}
|
|
/// <summary>
|
/// 获取正交投影坐标,返回的是世界坐标
|
/// </summary>
|
/// <param name="position3D">世界坐标</param>
|
/// <param name="mousePosition">地图坐标</param>
|
/// <param name="vector3">投影向量</param>
|
/// <returns></returns>
|
/// <exception cref="NotImplementedException"></exception>
|
private PointF3D GetLGWorldPoint(PointF3D position3D, PointF p2)
|
{
|
double radian_fushi = 俯视弧度;
|
float sin = (float)Math.Sin(radian_fushi);
|
float cos = (float)Math.Cos(radian_fushi);
|
var p1 = WorldPointToMapPoint(position3D);
|
var dy = p2.Y - p1.Y;
|
float dz = dy / cos;
|
return new PointF3D(position3D.X, position3D.Y, position3D.Z + dz);
|
|
}
|
|
private PointF MapPointToWorldPoint(PointF3D point)
|
{
|
return MapPointToWorldPoint(new PointF(point.X, point.Y), point.Z);
|
}
|
/// <summary>
|
/// 获取地图投影坐标
|
/// </summary>
|
/// <param name="point"></param>
|
/// <param name="z"></param>
|
/// <returns></returns>
|
public PointF MapPointToWorldPoint(PointF point, float z = 0)
|
{
|
var pointT = Get俯视角还原Point(point, z);
|
pointT = Get平面还原Point(pointT);
|
|
//var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y));
|
return pointT;
|
}
|
private PointF GetMapPoint_还原(NodeViewModel junction)
|
{
|
PointF p;
|
|
p = MapPointToWorldPoint(junction.Position, junction.Elev);
|
return p;
|
|
}
|
|
|
|
#endregion
|
|
|
#region 判断可见性
|
private float Get_dist(PointF A, PointF B)
|
{
|
float dx = A.X - B.X;
|
float dy = A.Y - B.Y;
|
float dist = (float)Math.Sqrt(dx * dx + dy * dy);
|
return dist;
|
}
|
//判断A距离线段B和C的距离,如果超出了线段的范围,则返回到最近的端点的距离;距离线段中心点越远,返回的距离越大;
|
private float Get_dist(PointF A, PointF B, PointF C, float MaxOff)
|
{
|
//PointF A, PointF B,PointF C,求点A到B、C构成线段的中心点的距离
|
|
float dist_off = GetDistanceFromPointAToMidpointOfLineSegmentBC(A, B, C);
|
//使用dist_off 跟 线段A、B的长度比较,如果大于1/2,则返回MaxOff,否则按照比例返回
|
float dist_len = Get_dist(B, C);
|
if (dist_len < 5) dist_len = 5;
|
float dist_add = (dist_off / dist_len > 0.5 ? MaxOff : dist_off / dist_len * 2 * MaxOff);
|
|
float dx = C.X - B.X;
|
float dy = C.Y - B.Y;
|
float dist = (float)Math.Sqrt(dx * dx + dy * dy);
|
if (dist == 0) return Get_dist(A, B) + dist_add;
|
float t = ((A.X - B.X) * dx + (A.Y - B.Y) * dy) / (dist * dist);
|
if (t < 0) return Get_dist(A, B) + dist_add;
|
if (t > 1) return Get_dist(A, C) + dist_add;
|
float x = B.X + t * dx;
|
float y = B.Y + t * dy;
|
return Get_dist(A, new PointF(x, y)) + dist_add;
|
|
}
|
private float GetDistanceFromPointAToMidpointOfLineSegmentBC(PointF A, PointF B, PointF C)
|
{
|
// Calculate the midpoint of the line segment BC
|
PointF midpoint = new PointF((B.X + C.X) / 2, (B.Y + C.Y) / 2);
|
|
// Calculate the distance from point A to the midpoint
|
float dx = midpoint.X - A.X;
|
float dy = midpoint.Y - A.Y;
|
float distance = (float)Math.Sqrt(dx * dx + dy * dy);
|
|
return distance;
|
}
|
|
PointF PMin_Show, PMax_Show;
|
|
/// <summary>
|
/// 判断是否在屏幕坐标内
|
/// </summary>
|
/// <param name="screenPos"></param>
|
/// <returns></returns>
|
public bool isVisible(PointF MapPos)
|
{
|
if (MapPos.X < PMin_Show.X || MapPos.X > PMax_Show.X || MapPos.Y < PMin_Show.Y || MapPos.Y > PMax_Show.Y)
|
return false;
|
else
|
return true;
|
}
|
|
/// <summary>
|
/// 判断是否在屏幕坐标内
|
/// </summary>
|
/// <param name="screenPos"></param>
|
/// <returns></returns>
|
public bool isVisible(List<PointF> list_MapPos)
|
{
|
bool visible = false;
|
foreach (var MapPos in list_MapPos)
|
{
|
if (MapPos.X < PMin_Show.X || MapPos.X > PMax_Show.X || MapPos.Y < PMin_Show.Y || MapPos.Y > PMax_Show.Y)
|
{
|
|
}
|
else
|
{
|
visible = true;
|
return true;
|
}
|
|
}
|
|
return visible;
|
}
|
#endregion
|
|
}
|
}
|