1
cloudflight
2024-07-20 fab5d6e30b9a42a1f94524fca74ef227d2c963e4
Hydraulic/Hydro.MapUI/Map/MapViewer.Draw.cs
@@ -1,4 +1,6 @@
using Hydro.MapView;
using DevExpress.XtraPrinting.Native;
using Hydro.MapView;
using Hydro.MapView.Base;
using Hydro.MapView.Common;
using System;
using System.Collections.Generic;
@@ -21,12 +23,116 @@
    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;
            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<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 Cps = new List<PointF>
                    //{
                    //    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<PointF>
                {
                    //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<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);
            }
        }
        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;
@@ -56,67 +162,52 @@
            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))
            //绘制面
            using (Pen pen0 = new Pen(Color.FromArgb(0, 0, 255), 2 * r))
            {
                //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,
                //};
                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));
                var Cps = new List<PointF>
                foreach (var area in _Areas)
                {
                    //template.BackGroundPoint1,
                    //new PointF(template.BackGroundImgX,template.BackGroundImgY),
                    p1,
                    p3,p4
                    //template.BackGroundPoint2,
                };
                    if (!area.Visible) continue;
                    if (!IsFaceVisibleToCamera(area, GetCameraPosition())) continue;
                    if (area.Elev < minElve || area.Elev >= maxElve) continue;
                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)
                    var p = new List<PointF>();
                    foreach (var node in area.InnerNodes)
                    {
                        bufferG.FillPolygon(penN.Brush, p.ToArray());
                        bufferG.DrawImage(img, p.ToArray());
                        p.Add(CubeWorldPointToMapPoint(node, template.OffSet));
                    }
                }
                catch
                {
                    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);
                }
                //bufferG.Restore(gs);
                    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);
                }
            }
@@ -703,6 +794,12 @@
            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)
        {
@@ -719,17 +816,18 @@
        // 根据旋转角度计算旋转后的坐标
        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);
@@ -738,9 +836,9 @@
        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);
@@ -748,9 +846,9 @@
            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);
@@ -769,7 +867,7 @@
            return new PointF(x, y);
        }
        /// <summary>
        /// 获取地图投影坐标
        /// 获取世界投影坐标
        /// </summary>
        /// <param name="point"></param>
        /// <param name="z"></param>
@@ -779,9 +877,9 @@
            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;
@@ -797,7 +895,19 @@
            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)
        {
@@ -896,8 +1006,8 @@
        /// <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;
@@ -914,7 +1024,84 @@
        #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)