|
|
|
|
using System;
|
using System.Collections.Generic;
|
using System.ComponentModel;
|
using System.Drawing;
|
using System.IO;
|
using System.Linq;
|
using System.Numerics;
|
using System.Text;
|
using System.Threading.Tasks;
|
using System.Windows.Forms;
|
|
namespace Yw.WinFrmUI.Q3d
|
{
|
partial class empty { }
|
|
//定义一个委托,用来存储void Draw(Graphics bufferG, Template template)
|
public delegate void DrawDelegate(Graphics bufferG, Settings template);
|
|
public delegate void MouseDelegate(MouseEventArgs e);
|
|
partial class Drawer
|
{
|
|
#region 定义事件
|
//定义一个event,将label_center.Text传出
|
public event EventHandler<string> CenterChanged;
|
public event EventHandler<string> ZoomChanged;
|
public event EventHandler<string> RotationChanged;
|
public event EventHandler<string> RotationFChanged;
|
public event EventHandler<string> MousePositionChanged;
|
|
|
|
//定义一个event,将选中的对象集传出
|
public event EventHandler<List<IBaseViewModel>> SelectedObjectsChanged;
|
#endregion
|
|
#region 绘制的相关属性,不允许外部访问
|
private DrawDelegate DrawNet = null;
|
private DrawDelegate DrawNetNew = null;
|
|
private DrawDelegate DrawBackGroundPic = null;
|
|
//绘制辅助线
|
private DrawDelegate DrawAuxiliary = null;
|
|
private MouseDelegate onMouseDown = null;
|
private MouseDelegate onMouseMove = null;
|
private MouseDelegate onMouseUp = null;
|
private MouseDelegate onMouseWheel = null;
|
private DrawingMode drawingMode = DrawingMode.All;
|
|
private bool Inited = false;
|
|
private DrawingStatus Status = DrawingStatus.Ready;
|
#endregion
|
|
#region 重写控件绘制事件
|
protected override void OnPaint(PaintEventArgs e)
|
{
|
this.Status = DrawingStatus.drawingBase;
|
base.OnPaint(e);
|
if (!Inited) { this.Status = DrawingStatus.Ready; return; }
|
if (float.IsInfinity(mapOption.zoom)) { this.Status = DrawingStatus.Ready; return; }
|
|
_needPaintAll = false;
|
if (buffer == null || buffer.Width != Width || buffer.Height != Height)
|
{
|
buffer?.Dispose();
|
buffer = new Bitmap(Width, Height);
|
}
|
// 使用缓存绘制,避免在每次重绘时重新计算所有要绘制的元素
|
var bufferG = Graphics.FromImage(buffer);
|
// 先将控件的背景填充为白色
|
bufferG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
bufferG.Clear(Color.Transparent);
|
bufferG.TranslateTransform(Width / 2, Height / 2);
|
bufferG.ScaleTransform(mapOption.zoom, -mapOption.zoom);
|
bufferG.TranslateTransform(-mapOption.Center.X, -mapOption.Center.Y);
|
|
|
this.Status = DrawingStatus.drawingPic;
|
DrawBackGroundPic(bufferG, _Template);
|
this.Status = DrawingStatus.drawingNet;
|
//BookMark :绘制地图事件
|
DrawNet(bufferG, _Template);
|
|
this.Status = DrawingStatus.drawingNetNew;
|
//if (_newTemplate?.network != null) DrawNetNew(bufferG, _newTemplate);
|
|
this.Status = DrawingStatus.drawingOthers;
|
DrawAuxiliary(bufferG, null);
|
// 将生成的画布绘制到控件上
|
e.Graphics.DrawImage(buffer, 0, 0);
|
|
bufferG.Dispose();
|
this.Status = DrawingStatus.Ready;
|
|
}
|
|
protected override void OnMouseDown(MouseEventArgs e)
|
{
|
base.OnMouseDown(e);
|
if (Inited) onMouseDown(e);
|
}
|
protected override void OnMouseMove(MouseEventArgs e)
|
{
|
base.OnMouseMove(e);
|
if (Inited) onMouseMove(e);
|
}
|
protected override void OnMouseUp(MouseEventArgs e)
|
{
|
base.OnMouseUp(e);
|
if (Inited) onMouseUp(e);
|
}
|
protected override void OnMouseWheel(MouseEventArgs e)
|
{
|
base.OnMouseWheel(e);
|
if (Inited) onMouseWheel(e);
|
}
|
#endregion
|
|
#region 绘制的方法实现
|
void DrawBackGroud(Graphics bufferG, Settings template)
|
{
|
if (template == null) return;
|
|
var _Nodes = _network.Nodes.ViewNodes;
|
var _Links = _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<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);
|
|
|
//背景图绘制
|
if (this.mapOption.isShowPic && template != null && File.Exists(template.BackGroundImg_FullPath))
|
|
|
{
|
//var gs = bufferG.Save();
|
// 应用矩阵变换以抵消之前的翻转效果
|
//bufferG.ScaleTransform(1 / Zoom.X, 1 / Zoom.Y);
|
List<PointF> p = new List<PointF>();
|
|
if (!this.mapOption.isAutoBackgroundImage)
|
{
|
var Cps = new List<PointF>
|
{
|
template.BackGroundPoint1,
|
new PointF(template.BackGroundPoint2.X,template.BackGroundPoint1.Y),
|
new PointF(template.BackGroundPoint1.X,template.BackGroundPoint2.Y),
|
//template.BackGroundPoint2,
|
|
|
};
|
Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet)));
|
}
|
else
|
{
|
|
|
var p1 = new PointF(template.BackGroundImgX, template.BackGroundImgY);
|
var p2 = new PointF(template.BackGroundImgX + template.BackGroundImgWidth, template.BackGroundImgY + template.BackGroundImgHeight);
|
|
var f = template.BackGroundImgRotaAngle / 180 * Math.PI;
|
var djx = Math.Sqrt((Math.Pow(template.BackGroundImgWidth, 2) + Math.Pow(template.BackGroundImgHeight, 2)));
|
var p3 = new PointF(p1.X + (float)(Math.Cos(f) * template.BackGroundImgWidth), p1.Y + (float)(Math.Sin(f) * template.BackGroundImgWidth));
|
var p4 = new PointF(p1.X - (float)(Math.Sin(f) * template.BackGroundImgHeight), p1.Y + (float)(Math.Cos(f) * template.BackGroundImgHeight));
|
p3.Y = p4.Y;
|
//p4.Y = -p4.Y;
|
var Cps = new List<PointF>
|
{
|
|
p4,
|
p3,p1
|
|
|
};
|
template.BackGroundPoint1 = p4;
|
template.BackGroundPoint2 = new PointF(p3.X, p1.Y);
|
|
|
Cps.ForEach(cp => p.Add(WorldPointToMapPoint(cp, template.BackGroundElev, template.OffSet)));
|
}
|
|
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, Settings template)
|
{
|
if (template == null) return;
|
var _Nodes = _network.Nodes.ViewNodes;
|
var _Links = _network.Links.ViewLinks;
|
var _Areas = _network.Areas;
|
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<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);
|
|
|
//绘制面
|
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.Z < minElve || area.Z >= maxElve) continue;
|
|
var p = new List<PointF>();
|
foreach (var node in area.InnerNodes)
|
{
|
p.Add(CubeWorldPointToMapPoint(node, template.OffSet));
|
}
|
if (p.Count < 3) continue;
|
pen0.Color = penClosed.Color = area.color;
|
Pen pen = pen0;
|
if (area.Hovered) pen = penHovered;
|
bufferG.FillPolygon(pen.Brush, p.ToArray());
|
bufferG.DrawPolygon(pen, p.ToArray());
|
//显示area的名称
|
var c = new PointF(p.Average(p0 => p0.X), p.Average(p0 => p0.Y));
|
var brush = new SolidBrush(Color.White);
|
|
|
|
|
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<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.Z < minElve || link.Z >= 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 == Yw.WinFrmUI.Q3D.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 || IsShowValve)
|
{
|
|
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 || IsShowValve)
|
{
|
|
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 圆形拆分
|
|
List<PointF> p = new List<PointF>();
|
Cpoints.ForEach(cp => p.Add(GraphHelper.getRotatePoint(c.X + cp.X * radius - radius, c.Y + cp.Y * radius, c, p1, p2)));
|
|
#endregion
|
|
|
|
bufferG.FillPolygon(link.Selected ? pen_valveChoosed.Brush : pen.Brush, p.ToArray());
|
|
|
|
// 绘制连接线
|
|
|
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.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.Z < minElve || node.Z >= 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 == _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);
|
|
|
}
|
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 || IsShowJunction)
|
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 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, Settings template)
|
{
|
var r = 2f / zoom;
|
if (_isDragging && DragStartPos != new PointF(0, 0) && mousePosition != new PointF(0, 0))
|
{
|
//将$"{MapCenter.X.ToString("0.00")},{MapCenter.Y.ToString("0.00")}"通过CenterChanged传出
|
CenterChanged?.Invoke(this, $"{MapCenter.X.ToString("0.00")},{MapCenter.Y.ToString("0.00")}");
|
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());
|
}
|
}
|
}
|
#endregion
|
|
#region 基础坐标转换方法
|
/// <summary>
|
/// 将屏幕坐标转换为世界坐标。 (x,y),返回输入屏幕坐标世界坐标 (wx, wy)。
|
/// </summary>
|
/// <param name="screenPos"></param>
|
/// <returns></returns>
|
private PointF ScreenToVMap(PointF screenPos, float z = 0)
|
{
|
|
var centerX = this.Width / 2;
|
var centerY = this.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.Width / 2;
|
var centerY = this.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);
|
}
|
|
/// <summary>
|
/// 世界投影坐标转换为屏幕坐标
|
/// </summary>
|
/// <param name="mapPos"></param>
|
/// <param name="z"></param>
|
/// <returns></returns>
|
private PointF MapToScreen(PointF mapPos, float z = 0)
|
{
|
|
var centerX = this.Width / 2;
|
var centerY = this.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);
|
}
|
|
|
// 根据旋转角度计算旋转后的坐标
|
|
|
/// <summary>
|
/// 计算围绕竖直线Z轴旋转后的坐标
|
/// </summary>
|
/// <param name="p">世界坐标</param>
|
/// <param name="MapC"></param>
|
/// <returns></returns>
|
private PointF3D Get平面旋转Point(PointF3D p, PointF3D MapC)
|
{
|
PointF3D 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);
|
float z = p.Z;
|
return new PointF3D(x, y, z);
|
}
|
/// <summary>
|
/// 计算围绕竖直线Z轴旋转前的坐标
|
/// </summary>
|
/// <param name="p">p是世界坐标</param>
|
/// <param name="MapC"></param>
|
/// <returns></returns>
|
private PointF3D Get平面还原Point(PointF3D p, PointF3D MapC)
|
{
|
PointF3D 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);
|
float z = p.Z;
|
return new PointF3D(x, y, z);
|
}
|
|
|
|
/// <summary>
|
/// 将世界坐标投影到xy平面,建立投影坐标系,法向量为Z轴
|
/// </summary>
|
/// <param name="p"></param>
|
/// <param name="z"></param>
|
/// <param name="MapC"></param>
|
/// <returns></returns>
|
private PointF Get俯视角投影Point(PointF3D p, PointF3D MapC)
|
{
|
PointF3D 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 * p.Z - center.Z;
|
float z = p.Z;
|
return new PointF(x, y);
|
}
|
/// <summary>
|
/// 计算围绕X轴旋转前的坐标
|
/// </summary>
|
/// <param name="p"></param>
|
/// <param name="z"></param>
|
/// <param name="MapC"></param>
|
/// <returns></returns>
|
private PointF3D Get俯视角投影还原Point(PointF3D p, PointF3D MapC)
|
{
|
PointF3D center = MapC;
|
|
double radian_fushi = 俯视弧度;
|
float sin = (float)Math.Sin(radian_fushi);
|
float cos = (float)Math.Cos(radian_fushi);
|
float x = p.X;
|
float y = (p.Y - center.Y - cos * p.Z + center.Z) / sin + center.Y;
|
float z = p.Z;
|
return new PointF3D(x, y, z);
|
}
|
|
|
/// <summary>
|
/// 输入两个<屏幕坐标>的点,返回连接两点<世界坐标>的向量
|
/// 该方法用来计算鼠标拖动/双击定位/鼠标位置缩放时,视角中心点的移动
|
/// </summary>
|
/// <param name="p">屏幕坐标</param>
|
/// <param name="p0">屏幕坐标</param>
|
/// <returns></returns>
|
private PointF3D GetWorldVectorByScreenPoints(PointF p, PointF p0)
|
{
|
|
double radian = Rotation * Math.PI / 180; // 角度转弧度
|
double radian_fushi = 俯视弧度;
|
var wp0 = ScreenToMap(p0);
|
var wp = ScreenToMap(p);
|
//通过p0到p的点,构造一个二维向量
|
var vector = new Vector2(wp.X - wp0.X, wp.Y - wp0.Y);
|
//通过俯视角度,根据vector的Y分量,计算新的y和z分量
|
float y = (float)(vector.Y * Math.Sin(radian_fushi));
|
float z = (float)(vector.Y * Math.Cos(radian_fushi));
|
//构造一个新的向量
|
var vector3 = new Vector3(vector.X, y, z);
|
//通过平面旋转,将vector3,还原到世界坐标
|
var vector3_ = Get平面还原Point(new PointF3D(vector3.X, vector3.Y, vector3.Z), new PointF3D(0, 0, 0));
|
//对vector3_取反向量
|
//,得到最终的向量
|
return new PointF3D(vector3_.X, vector3_.Y, vector3_.Z);
|
|
|
//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));
|
//float z = (float)(Math.Sin(radian_fushi) * (p.Y - p0.Y)); // 添加俯视角度的影响
|
//return new PointF3D(x / Zoom.X, y / Zoom.Y, z/Zoom.Z);
|
}
|
|
/// <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);
|
PointF3D point3d = new PointF3D(point.X + offset.X, point.Y + offset.Y, z + offset.Z);
|
|
var pointR = Get平面旋转Point(point3d, MapCenter);
|
|
var pointT = Get俯视角投影Point(pointR, 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)
|
{
|
|
if (junction == null) return new PointF(0, 0);
|
var p = WorldPointToMapPoint(junction.Position, junction.Z, offset);
|
return p;
|
}
|
private PointF CubeWorldPointToMapPoint(NodeViewModel junction, PointF3D offset = null)
|
{
|
|
if (junction == null) return new PointF(0, 0);
|
var point = junction.Position3D;
|
var z = junction.Z;
|
if (offset == null) offset = new PointF3D(0, 0, 0);
|
point = new PointF3D(point.X + offset.X, point.Y + offset.Y, point.Z + offset.Z);
|
var pointR = Get平面旋转Point(point, new PointF3D(0, 0, 0));
|
var pointT = Get俯视角投影Point(pointR, new PointF3D(0, 0, 0));
|
//var n=new PointF((float)pointR.X - Z(z).X, (float)(pointR.Y - Z(z).Y));
|
return pointT;
|
}
|
private List<PointF> WorldPointToMapPoint(LinkViewModel pipe, PointF3D offset = null)
|
{
|
List<PointF> list = new List<PointF>();
|
|
PointF p;
|
p = WorldPointToMapPoint(pipe.StartNode, offset);
|
list.Add(p);
|
p = WorldPointToMapPoint(pipe.EndNode, offset);
|
list.Add(p);
|
return list;
|
|
}
|
/// <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);
|
|
}
|
|
|
/// <summary>
|
/// 获取地图投影坐标
|
/// </summary>
|
/// <param name="point"></param>
|
/// <param name="z"></param>
|
/// <returns></returns>
|
public PointF3D MapPointToWorldPoint(PointF point, float z = 0)
|
{
|
var pointT = Get俯视角投影还原Point(new PointF3D(point.X, point.Y, 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;
|
}
|
|
|
|
|
#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;
|
|
/// <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
|
|
}
|
}
|