| | |
| | | using Hydro.MapView; |
| | | using DevExpress.XtraPrinting.Native; |
| | | using Hydro.MapView; |
| | | using Hydro.MapView.Base; |
| | | using Hydro.MapView.Common; |
| | | using System; |
| | | using System.Collections.Generic; |
| | |
| | | |
| | | partial class MapViewer |
| | | { |
| | | void Draw(Graphics bufferG, Template template) |
| | | void DrawBackGroud(Graphics bufferG,Template template) |
| | | { |
| | | if (template == null) return; |
| | | var _Nodes = template.network.Nodes.ViewNodes; |
| | |
| | | |
| | | 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)) |
| | | |
| | |
| | | |
| | | |
| | | }; |
| | | template.BackGroundPoint1 = p4; |
| | | template.BackGroundPoint2 = new PointF(p3.X, p1.Y); |
| | | |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | //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<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.Elev < minElve || area.Elev >= 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); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | 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) |
| | | { |
| | | |
| | |
| | | |
| | | |
| | | // 根据旋转角度计算旋转后的坐标 |
| | | private PointF Get平面旋转Point(PointF p) |
| | | private PointF Get平面旋转Point(PointF p, PointF MapC) |
| | | { |
| | | PointF center = MapCenter; |
| | | |
| | | 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) |
| | | private PointF Get平面还原Point(PointF p, PointF MapC) |
| | | { |
| | | PointF center = MapCenter; |
| | | 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); |
| | |
| | | |
| | | |
| | | |
| | | private PointF Get俯视角旋转Point(PointF p, float z) |
| | | private PointF Get俯视角旋转Point(PointF p, float z, PointF MapC) |
| | | { |
| | | PointF center = MapCenter; |
| | | PointF center = MapC; |
| | | double radian_fushi = 俯视弧度; |
| | | float sin = (float)Math.Sin(radian_fushi); |
| | | float cos = (float)Math.Cos(radian_fushi); |
| | |
| | | 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) |
| | | private PointF Get俯视角还原Point(PointF p, float z, PointF MapC) |
| | | { |
| | | PointF center = MapCenter; |
| | | PointF center = MapC; |
| | | double radian_fushi = 俯视弧度; |
| | | float sin = (float)Math.Sin(radian_fushi); |
| | | float cos = (float)Math.Cos(radian_fushi); |
| | |
| | | return new PointF(x, y); |
| | | } |
| | | /// <summary> |
| | | /// 获取地图投影坐标 |
| | | /// 获取世界投影坐标 |
| | | /// </summary> |
| | | /// <param name="point"></param> |
| | | /// <param name="z"></param> |
| | |
| | | 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 pointR = Get平面旋转Point(point, MapCenter); |
| | | |
| | | var pointT = Get俯视角旋转Point(pointR, z + offset.Z); |
| | | 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; |
| | |
| | | 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<PointF> WorldPointToMapPoint(LinkViewModel pipe, PointF3D offset = null) |
| | | { |
| | |
| | | /// <returns></returns> |
| | | public PointF MapPointToWorldPoint(PointF point, float z = 0) |
| | | { |
| | | var pointT = Get俯视角还原Point(point, z); |
| | | pointT = Get平面还原Point(pointT); |
| | | 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; |
| | |
| | | |
| | | |
| | | #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) |