Exemple #1
0
 public void Dispose()
 {
     Br.Dispose();
     Bw.Dispose();
     Close();
     GC.SuppressFinalize(this);
 }
Exemple #2
0
        private static readonly PointD3D _NormalVectorPZX = new PointD3D(0, 1, 0);  // 正方体表面的 +ZX 法向量。

        //

        /// <summary>
        /// 绘制一个长方体,并返回表示是否已经实际完成绘图的布尔值。
        /// </summary>
        /// <param name="bmp">用于绘制的位图。</param>
        /// <param name="center">长方体的中心坐标。</param>
        /// <param name="size">长方体的大小。</param>
        /// <param name="color">长方体的颜色。</param>
        /// <param name="edgeWidth">长方体的棱的宽度。</param>
        /// <param name="affineMatrices">仿射矩阵(左矩阵)列表。</param>
        /// <param name="focalLength">焦距。</param>
        /// <param name="illuminationDirection">光照方向。</param>
        /// <param name="illuminationDirectionIsAfterAffineTransform">光照方向是否基于仿射变换之后的坐标系。</param>
        /// <param name="exposure">曝光,取值范围为 [-100, 100]。</param>
        /// <param name="antiAlias">是否使用抗锯齿模式绘图。</param>
        /// <returns>布尔值,表示是否已经实际完成绘图。</returns>
        public static bool PaintCuboid(Bitmap bmp, PointD3D center, PointD3D size, Color color, float edgeWidth, List <Matrix> affineMatrices, double focalLength, PointD3D illuminationDirection, bool illuminationDirectionIsAfterAffineTransform, double exposure, bool antiAlias)
        {
            try
            {
                if (bmp is null || center.IsNaNOrInfinity || (size.IsNaNOrInfinity || size.IsZero) || (color.IsEmpty || color.A == 0) || InternalMethod.IsNaNOrInfinity(edgeWidth) || InternalMethod.IsNullOrEmpty(affineMatrices) || (InternalMethod.IsNaNOrInfinity(focalLength) || focalLength < 0) || illuminationDirection.IsNaNOrInfinity || InternalMethod.IsNaNOrInfinity(exposure))
                {
                    return(false);
                }
                else
                {
                    PointD3D P3D_000 = _Vertex000;
                    PointD3D P3D_100 = _Vertex100;
                    PointD3D P3D_010 = _Vertex010;
                    PointD3D P3D_110 = _Vertex110;
                    PointD3D P3D_001 = _Vertex001;
                    PointD3D P3D_101 = _Vertex101;
                    PointD3D P3D_011 = _Vertex011;
                    PointD3D P3D_111 = _Vertex111;

                    P3D_000.Scale(size);
                    P3D_100.Scale(size);
                    P3D_010.Scale(size);
                    P3D_110.Scale(size);
                    P3D_001.Scale(size);
                    P3D_101.Scale(size);
                    P3D_011.Scale(size);
                    P3D_111.Scale(size);

                    P3D_000.Offset(center);
                    P3D_100.Offset(center);
                    P3D_010.Offset(center);
                    P3D_110.Offset(center);
                    P3D_001.Offset(center);
                    P3D_101.Offset(center);
                    P3D_011.Offset(center);
                    P3D_111.Offset(center);

                    P3D_000.AffineTransform(affineMatrices);
                    P3D_100.AffineTransform(affineMatrices);
                    P3D_010.AffineTransform(affineMatrices);
                    P3D_110.AffineTransform(affineMatrices);
                    P3D_001.AffineTransform(affineMatrices);
                    P3D_101.AffineTransform(affineMatrices);
                    P3D_011.AffineTransform(affineMatrices);
                    P3D_111.AffineTransform(affineMatrices);

                    PointD3D PrjCenter = new PointD3D(bmp.Width / 2, bmp.Height / 2, 0);

                    PointD P2D_000 = P3D_000.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_100 = P3D_100.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_010 = P3D_010.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_110 = P3D_110.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_001 = P3D_001.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_101 = P3D_101.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_011 = P3D_011.ProjectToXY(PrjCenter, focalLength);
                    PointD P2D_111 = P3D_111.ProjectToXY(PrjCenter, focalLength);

                    PointF P_000 = P2D_000.ToPointF();
                    PointF P_100 = P2D_100.ToPointF();
                    PointF P_010 = P2D_010.ToPointF();
                    PointF P_110 = P2D_110.ToPointF();
                    PointF P_001 = P2D_001.ToPointF();
                    PointF P_101 = P2D_101.ToPointF();
                    PointF P_011 = P2D_011.ToPointF();
                    PointF P_111 = P2D_111.ToPointF();

                    PointD3D[][] Element3D = new PointD3D[][]
                    {
                        // XY 面
                        new PointD3D[] { P3D_000, P3D_010, P3D_110, P3D_100 },
                        new PointD3D[] { P3D_001, P3D_011, P3D_111, P3D_101 },

                        // YZ 面
                        new PointD3D[] { P3D_000, P3D_001, P3D_011, P3D_010 },
                        new PointD3D[] { P3D_100, P3D_101, P3D_111, P3D_110 },

                        // ZX 面
                        new PointD3D[] { P3D_000, P3D_001, P3D_101, P3D_100 },
                        new PointD3D[] { P3D_010, P3D_011, P3D_111, P3D_110 },

                        // X 棱
                        new PointD3D[] { P3D_000, P3D_100 },
                        new PointD3D[] { P3D_010, P3D_110 },
                        new PointD3D[] { P3D_001, P3D_101 },
                        new PointD3D[] { P3D_011, P3D_111 },

                        // Y 棱
                        new PointD3D[] { P3D_000, P3D_010 },
                        new PointD3D[] { P3D_100, P3D_110 },
                        new PointD3D[] { P3D_001, P3D_011 },
                        new PointD3D[] { P3D_101, P3D_111 },

                        // Z 棱
                        new PointD3D[] { P3D_000, P3D_001 },
                        new PointD3D[] { P3D_100, P3D_101 },
                        new PointD3D[] { P3D_010, P3D_011 },
                        new PointD3D[] { P3D_110, P3D_111 }
                    };

                    PointF[][] Element2D = new PointF[][]
                    {
                        // XY 面
                        new PointF[] { P_000, P_010, P_110, P_100 },
                        new PointF[] { P_001, P_011, P_111, P_101 },

                        // YZ 面
                        new PointF[] { P_000, P_001, P_011, P_010 },
                        new PointF[] { P_100, P_101, P_111, P_110 },

                        // ZX 面
                        new PointF[] { P_000, P_001, P_101, P_100 },
                        new PointF[] { P_010, P_011, P_111, P_110 },

                        // X 棱
                        new PointF[] { P_000, P_100 },
                        new PointF[] { P_010, P_110 },
                        new PointF[] { P_001, P_101 },
                        new PointF[] { P_011, P_111 },

                        // Y 棱
                        new PointF[] { P_000, P_010 },
                        new PointF[] { P_100, P_110 },
                        new PointF[] { P_001, P_011 },
                        new PointF[] { P_101, P_111 },

                        // Z 棱
                        new PointF[] { P_000, P_001 },
                        new PointF[] { P_100, P_101 },
                        new PointF[] { P_010, P_011 },
                        new PointF[] { P_110, P_111 }
                    };

                    //

                    bool CuboidIsVisible = false;

                    bool[] ElementVisible = new bool[Element2D.Length];

                    for (int i = 0; i < Element2D.Length; i++)
                    {
                        bool EVisible = false;

                        foreach (PointF P in Element2D[i])
                        {
                            PointD P2D = P;

                            if (P2D.IsNaNOrInfinity)
                            {
                                EVisible = false;

                                break;
                            }
                            else
                            {
                                if (Geometry.PointIsVisibleInRectangle(P2D, new RectangleF(new Point(0, 0), bmp.Size)))
                                {
                                    EVisible = true;
                                }
                            }
                        }

                        ElementVisible[i] = EVisible;

                        if (!CuboidIsVisible && EVisible)
                        {
                            CuboidIsVisible = true;
                        }
                    }

                    if (!CuboidIsVisible)
                    {
                        return(false);
                    }
                    else
                    {
                        double[] IlluminationIntensity = new double[Element3D.Length];

                        double Exposure = Math.Max(-2, Math.Min(exposure / 50, 2));

                        if (illuminationDirection.IsZero)
                        {
                            for (int i = 0; i < 6; i++)
                            {
                                IlluminationIntensity[i] = Exposure;
                            }

                            for (int i = 6; i < Element3D.Length; i++)
                            {
                                IlluminationIntensity[i] = Constant.HalfSqrt2 * (Exposure + 1) + (Exposure - 1);
                            }
                        }
                        else
                        {
                            PointD3D[] NormalVector = new PointD3D[]
                            {
                                // XY 面
                                _NormalVectorNXY,
                                _NormalVectorPXY,

                                // YZ 面
                                _NormalVectorNYZ,
                                _NormalVectorPYZ,

                                // ZX 面
                                _NormalVectorNZX,
                                _NormalVectorPZX
                            };

                            if (illuminationDirectionIsAfterAffineTransform)
                            {
                                PointD3D NewOriginOpposite = PointD3D.Zero.AffineTransformCopy(affineMatrices).Opposite;

                                for (int i = 0; i < NormalVector.Length; i++)
                                {
                                    NormalVector[i].AffineTransform(affineMatrices);
                                    NormalVector[i].Offset(NewOriginOpposite);
                                }
                            }

                            double[] Angle = new double[NormalVector.Length];

                            for (int i = 0; i < NormalVector.Length; i++)
                            {
                                Angle[i] = illuminationDirection.AngleFrom(NormalVector[i]);
                            }

                            for (int i = 0; i < Angle.Length; i++)
                            {
                                double A       = Angle[i];
                                double CosA    = Math.Cos(A);
                                double CosSqrA = CosA * CosA;

                                double _IlluminationIntensity = (A < Constant.HalfPi ? -CosSqrA : (A > Constant.HalfPi ? CosSqrA : 0));

                                if (color.A < 255 && A != Constant.HalfPi)
                                {
                                    double Transmittance = 1 - (double)color.A / 255;

                                    if (A < Constant.HalfPi)
                                    {
                                        _IlluminationIntensity += (Transmittance * Math.Abs(CosA) * CosSqrA);
                                    }
                                    else
                                    {
                                        _IlluminationIntensity -= ((1 - Transmittance) * (1 - Math.Abs(CosA)) * CosSqrA);
                                    }
                                }

                                _IlluminationIntensity += Exposure;

                                IlluminationIntensity[i] = _IlluminationIntensity;
                            }

                            for (int i = 6; i < Element3D.Length; i++)
                            {
                                double _IlluminationIntensity = 0;

                                int Num = 0;

                                for (int j = 0; j < 6; j++)
                                {
                                    bool Flag = true;

                                    foreach (PointD3D P in Element3D[i])
                                    {
                                        if (!Element3D[j].Contains(P))
                                        {
                                            Flag = false;

                                            break;
                                        }
                                    }

                                    if (Flag)
                                    {
                                        _IlluminationIntensity += IlluminationIntensity[j];

                                        Num++;
                                    }
                                }

                                _IlluminationIntensity = Constant.HalfSqrt2 * (_IlluminationIntensity / Num + 1) + (Exposure - 1);

                                IlluminationIntensity[i] = _IlluminationIntensity;
                            }
                        }

                        for (int i = 0; i < IlluminationIntensity.Length; i++)
                        {
                            IlluminationIntensity[i] = Math.Max(-1, Math.Min(IlluminationIntensity[i], 1));
                        }

                        //

                        Color[] ElementColor = new Color[IlluminationIntensity.Length];

                        for (int i = 0; i < IlluminationIntensity.Length; i++)
                        {
                            double _IlluminationIntensity = IlluminationIntensity[i];

                            if (_IlluminationIntensity == 0)
                            {
                                ElementColor[i] = color;
                            }
                            else
                            {
                                ColorX EColor = color;

                                if (_IlluminationIntensity < 0)
                                {
                                    EColor.Lightness_HSL += EColor.Lightness_HSL * _IlluminationIntensity;
                                }
                                else
                                {
                                    EColor.Lightness_HSL += (100 - EColor.Lightness_HSL) * _IlluminationIntensity;
                                }

                                ElementColor[i] = EColor.ToColor();
                            }
                        }

                        //

                        double[] ElementZAvg = new double[Element3D.Length];

                        for (int i = 0; i < Element3D.Length; i++)
                        {
                            PointD3D[] Element = Element3D[i];

                            double ZAvg = 0;

                            foreach (PointD3D P in Element)
                            {
                                ZAvg += P.Z;
                            }

                            ZAvg /= Element.Length;

                            ElementZAvg[i] = ZAvg;
                        }

                        int[] ElementIndex = new int[ElementZAvg.Length];

                        for (int i = 0; i < ElementZAvg.Length; i++)
                        {
                            ElementIndex[i] = i;
                        }

                        for (int i = 0; i < ElementZAvg.Length; i++)
                        {
                            for (int j = i + 1; j < ElementZAvg.Length; j++)
                            {
                                if (ElementZAvg[ElementIndex[i]] < ElementZAvg[ElementIndex[j]] || (ElementZAvg[ElementIndex[i]] <= ElementZAvg[ElementIndex[j]] + edgeWidth && Element2D[ElementIndex[i]].Length < Element2D[ElementIndex[j]].Length))
                                {
                                    int Temp = ElementIndex[i];
                                    ElementIndex[i] = ElementIndex[j];
                                    ElementIndex[j] = Temp;
                                }
                            }
                        }

                        //

                        using (Graphics Grph = Graphics.FromImage(bmp))
                        {
                            if (antiAlias)
                            {
                                Grph.SmoothingMode = SmoothingMode.AntiAlias;
                            }

                            //

                            for (int i = 0; i < ElementIndex.Length; i++)
                            {
                                int EIndex = ElementIndex[i];

                                if (ElementVisible[EIndex])
                                {
                                    Color EColor = ElementColor[EIndex];

                                    if (!EColor.IsEmpty && EColor.A > 0)
                                    {
                                        PointF[] Element = Element2D[EIndex];

                                        if (Element.Length >= 3)
                                        {
                                            try
                                            {
                                                using (SolidBrush Br = new SolidBrush(EColor))
                                                {
                                                    Grph.FillPolygon(Br, Element);
                                                }
                                            }
                                            catch { }
                                        }
                                        else if (Element.Length == 2)
                                        {
                                            if (edgeWidth > 0)
                                            {
                                                float EdgeWidth = (focalLength == 0 ? edgeWidth : (float)(focalLength / (ElementZAvg[EIndex] - PrjCenter.Z) * edgeWidth));

                                                try
                                                {
                                                    Brush Br;

                                                    Func <Color, double, int> GetAlpha = (Cr, Z) =>
                                                    {
                                                        int Alpha;

                                                        if (focalLength == 0)
                                                        {
                                                            Alpha = Cr.A;
                                                        }
                                                        else
                                                        {
                                                            if (Z - PrjCenter.Z <= focalLength)
                                                            {
                                                                Alpha = Cr.A;
                                                            }
                                                            else
                                                            {
                                                                Alpha = (int)Math.Max(0, Math.Min(focalLength / (Z - PrjCenter.Z) * Cr.A, 255));
                                                            }
                                                        }

                                                        if (EdgeWidth < 1)
                                                        {
                                                            Alpha = (int)(Alpha * EdgeWidth);
                                                        }

                                                        return(Alpha);
                                                    };

                                                    if (((PointD)Element[0]).DistanceFrom(Element[1]) > 1)
                                                    {
                                                        int Alpha0 = GetAlpha(EColor, Element3D[EIndex][0].Z), Alpha1 = GetAlpha(EColor, Element3D[EIndex][1].Z);

                                                        Br = new LinearGradientBrush(Element[0], Element[1], Color.FromArgb(Alpha0, EColor), Color.FromArgb(Alpha1, EColor));
                                                    }
                                                    else
                                                    {
                                                        int Alpha = GetAlpha(EColor, ElementZAvg[EIndex]);

                                                        Br = new SolidBrush(Color.FromArgb(Alpha, EColor));
                                                    }

                                                    using (Pen Pn = new Pen(Br, EdgeWidth))
                                                    {
                                                        Grph.DrawLines(Pn, Element);
                                                    }

                                                    if (!(Br is null))
                                                    {
                                                        Br.Dispose();
                                                    }
                                                }
                                                catch { }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        //

                        return(true);
                    }
                }
            }
        private Bitmap GetProjectionOfCube(Com.PointD3D CubeSize, Color CubeColor, Com.Matrix AffineMatrix, Com.PointD3D IlluminationDirection, double Exposure, Views View, SizeF ImageSize)
        {
            //
            // 获取立方体的投影。
            //

            double CubeDiag = Math.Min(ImageSize.Width, ImageSize.Height);

            CubeSize = CubeSize.Normalize * CubeDiag;

            Bitmap PrjBmp = new Bitmap(Math.Max(1, (int)ImageSize.Width), Math.Max(1, (int)ImageSize.Height));

            //

            Com.PointD3D CubeCenter = new Com.PointD3D(0, 0, 0);

            Com.PointD3D P3D_000 = new Com.PointD3D(0, 0, 0);
            Com.PointD3D P3D_100 = new Com.PointD3D(1, 0, 0);
            Com.PointD3D P3D_010 = new Com.PointD3D(0, 1, 0);
            Com.PointD3D P3D_110 = new Com.PointD3D(1, 1, 0);
            Com.PointD3D P3D_001 = new Com.PointD3D(0, 0, 1);
            Com.PointD3D P3D_101 = new Com.PointD3D(1, 0, 1);
            Com.PointD3D P3D_011 = new Com.PointD3D(0, 1, 1);
            Com.PointD3D P3D_111 = new Com.PointD3D(1, 1, 1);

            P3D_000 = (P3D_000 - 0.5) * CubeSize + CubeCenter;
            P3D_100 = (P3D_100 - 0.5) * CubeSize + CubeCenter;
            P3D_010 = (P3D_010 - 0.5) * CubeSize + CubeCenter;
            P3D_110 = (P3D_110 - 0.5) * CubeSize + CubeCenter;
            P3D_001 = (P3D_001 - 0.5) * CubeSize + CubeCenter;
            P3D_101 = (P3D_101 - 0.5) * CubeSize + CubeCenter;
            P3D_011 = (P3D_011 - 0.5) * CubeSize + CubeCenter;
            P3D_111 = (P3D_111 - 0.5) * CubeSize + CubeCenter;

            Com.PointD3D RotateCenter3D = CubeCenter;

            AffineTransform(ref P3D_000, RotateCenter3D, AffineMatrix);
            AffineTransform(ref P3D_100, RotateCenter3D, AffineMatrix);
            AffineTransform(ref P3D_010, RotateCenter3D, AffineMatrix);
            AffineTransform(ref P3D_110, RotateCenter3D, AffineMatrix);
            AffineTransform(ref P3D_001, RotateCenter3D, AffineMatrix);
            AffineTransform(ref P3D_101, RotateCenter3D, AffineMatrix);
            AffineTransform(ref P3D_011, RotateCenter3D, AffineMatrix);
            AffineTransform(ref P3D_111, RotateCenter3D, AffineMatrix);

            //

            double TrueLenDist3D = new Com.PointD(Screen.PrimaryScreen.Bounds.Size).Module;

            Com.PointD3D PrjCenter3D = CubeCenter;

            switch (View)
            {
            case Views.XY: PrjCenter3D.Z -= (TrueLenDist3D + CubeDiag / 2); break;

            case Views.YZ: PrjCenter3D.X -= (TrueLenDist3D + CubeDiag / 2); break;

            case Views.ZX: PrjCenter3D.Y -= (TrueLenDist3D + CubeDiag / 2); break;
            }

            Func <Com.PointD3D, Com.PointD3D, double, Com.PointD> GetProject3D = (Pt, PrjCenter, TrueLenDist) =>
            {
                switch (View)
                {
                case Views.XY: return(Pt.ProjectToXY(PrjCenter, TrueLenDist));

                case Views.YZ: return(Pt.ProjectToYZ(PrjCenter, TrueLenDist));

                case Views.ZX: return(Pt.ProjectToZX(PrjCenter, TrueLenDist));

                default: return(Com.PointD.NaN);
                }
            };

            Com.PointD P2D_000 = GetProject3D(P3D_000, PrjCenter3D, TrueLenDist3D);
            Com.PointD P2D_100 = GetProject3D(P3D_100, PrjCenter3D, TrueLenDist3D);
            Com.PointD P2D_010 = GetProject3D(P3D_010, PrjCenter3D, TrueLenDist3D);
            Com.PointD P2D_110 = GetProject3D(P3D_110, PrjCenter3D, TrueLenDist3D);
            Com.PointD P2D_001 = GetProject3D(P3D_001, PrjCenter3D, TrueLenDist3D);
            Com.PointD P2D_101 = GetProject3D(P3D_101, PrjCenter3D, TrueLenDist3D);
            Com.PointD P2D_011 = GetProject3D(P3D_011, PrjCenter3D, TrueLenDist3D);
            Com.PointD P2D_111 = GetProject3D(P3D_111, PrjCenter3D, TrueLenDist3D);

            Com.PointD BitmapCenter = new Com.PointD(PrjBmp.Size) / 2;

            PointF P_000 = (P2D_000 + BitmapCenter).ToPointF();
            PointF P_100 = (P2D_100 + BitmapCenter).ToPointF();
            PointF P_010 = (P2D_010 + BitmapCenter).ToPointF();
            PointF P_110 = (P2D_110 + BitmapCenter).ToPointF();
            PointF P_001 = (P2D_001 + BitmapCenter).ToPointF();
            PointF P_101 = (P2D_101 + BitmapCenter).ToPointF();
            PointF P_011 = (P2D_011 + BitmapCenter).ToPointF();
            PointF P_111 = (P2D_111 + BitmapCenter).ToPointF();

            //

            List <Com.PointD3D[]> Element3D = new List <Com.PointD3D[]>(18)
            {
                // XY 面
                new Com.PointD3D[] { P3D_000, P3D_010, P3D_110, P3D_100 },
                new Com.PointD3D[] { P3D_001, P3D_011, P3D_111, P3D_101 },

                // YZ 面
                new Com.PointD3D[] { P3D_000, P3D_001, P3D_011, P3D_010 },
                new Com.PointD3D[] { P3D_100, P3D_101, P3D_111, P3D_110 },

                // ZX 面
                new Com.PointD3D[] { P3D_000, P3D_001, P3D_101, P3D_100 },
                new Com.PointD3D[] { P3D_010, P3D_011, P3D_111, P3D_110 },

                // X 棱
                new Com.PointD3D[] { P3D_000, P3D_100 },
                new Com.PointD3D[] { P3D_010, P3D_110 },
                new Com.PointD3D[] { P3D_001, P3D_101 },
                new Com.PointD3D[] { P3D_011, P3D_111 },

                // Y 棱
                new Com.PointD3D[] { P3D_000, P3D_010 },
                new Com.PointD3D[] { P3D_100, P3D_110 },
                new Com.PointD3D[] { P3D_001, P3D_011 },
                new Com.PointD3D[] { P3D_101, P3D_111 },

                // Z 棱
                new Com.PointD3D[] { P3D_000, P3D_001 },
                new Com.PointD3D[] { P3D_100, P3D_101 },
                new Com.PointD3D[] { P3D_010, P3D_011 },
                new Com.PointD3D[] { P3D_110, P3D_111 }
            };

            List <PointF[]> Element2D = new List <PointF[]>(18)
            {
                // XY 面
                new PointF[] { P_000, P_010, P_110, P_100 },
                new PointF[] { P_001, P_011, P_111, P_101 },

                // YZ 面
                new PointF[] { P_000, P_001, P_011, P_010 },
                new PointF[] { P_100, P_101, P_111, P_110 },

                // ZX 面
                new PointF[] { P_000, P_001, P_101, P_100 },
                new PointF[] { P_010, P_011, P_111, P_110 },

                // X 棱
                new PointF[] { P_000, P_100 },
                new PointF[] { P_010, P_110 },
                new PointF[] { P_001, P_101 },
                new PointF[] { P_011, P_111 },

                // Y 棱
                new PointF[] { P_000, P_010 },
                new PointF[] { P_100, P_110 },
                new PointF[] { P_001, P_011 },
                new PointF[] { P_101, P_111 },

                // Z 棱
                new PointF[] { P_000, P_001 },
                new PointF[] { P_100, P_101 },
                new PointF[] { P_010, P_011 },
                new PointF[] { P_110, P_111 }
            };

            //

            List <double> IlluminationIntensity = new List <double>(Element3D.Count);

            double Exp = Math.Max(-2, Math.Min(Exposure / 50, 2));

            if (IlluminationDirection.IsZero)
            {
                for (int i = 0; i < 6; i++)
                {
                    IlluminationIntensity.Add(Exp);
                }

                for (int i = 6; i < Element3D.Count; i++)
                {
                    IlluminationIntensity.Add((Math.Sqrt(2) / 2) * (Exp + 1) + (Exp - 1));
                }
            }
            else
            {
                List <Com.PointD3D> NormalVector = new List <Com.PointD3D>(6)
                {
                    // XY 面
                    new Com.PointD3D(0, 0, -1),
                    new Com.PointD3D(0, 0, 1),

                    // YZ 面
                    new Com.PointD3D(-1, 0, 0),
                    new Com.PointD3D(1, 0, 0),

                    // ZX 面
                    new Com.PointD3D(0, -1, 0),
                    new Com.PointD3D(0, 1, 0),
                };

                Com.PointD3D NewOrigin = new Com.PointD3D(0, 0, 0).AffineTransformCopy(AffineMatrix);

                for (int i = 0; i < NormalVector.Count; i++)
                {
                    NormalVector[i] = NormalVector[i].AffineTransformCopy(AffineMatrix) - NewOrigin;
                }

                List <double> Angle = new List <double>(NormalVector.Count);

                for (int i = 0; i < NormalVector.Count; i++)
                {
                    Angle.Add(IlluminationDirection.AngleFrom(NormalVector[i]));
                }

                for (int i = 0; i < Angle.Count; i++)
                {
                    double A       = Angle[i];
                    double CosA    = Math.Cos(A);
                    double CosSqrA = CosA * CosA;

                    double _IlluminationIntensity = (A < Math.PI / 2 ? -CosSqrA : (A > Math.PI / 2 ? CosSqrA : 0));

                    if (CubeColor.A < 255 && A != Math.PI / 2)
                    {
                        double Transmittance = 1 - (double)CubeColor.A / 255;

                        if (A < Math.PI / 2)
                        {
                            _IlluminationIntensity += (Transmittance * Math.Abs(CosA) * CosSqrA);
                        }
                        else
                        {
                            _IlluminationIntensity -= ((1 - Transmittance) * (1 - Math.Abs(CosA)) * CosSqrA);
                        }
                    }

                    _IlluminationIntensity += Exp;

                    IlluminationIntensity.Add(_IlluminationIntensity);
                }

                for (int i = 6; i < Element3D.Count; i++)
                {
                    double _IlluminationIntensity = 0;

                    int Num = 0;

                    for (int j = 0; j < 6; j++)
                    {
                        bool Flag = true;

                        foreach (Com.PointD3D P in Element3D[i])
                        {
                            if (!Element3D[j].Contains(P))
                            {
                                Flag = false;

                                break;
                            }
                        }

                        if (Flag)
                        {
                            _IlluminationIntensity += IlluminationIntensity[j];

                            Num++;
                        }
                    }

                    _IlluminationIntensity = (Math.Sqrt(2) / 2) * (_IlluminationIntensity / Num + 1) + (Exp - 1);

                    IlluminationIntensity.Add(_IlluminationIntensity);
                }
            }

            for (int i = 0; i < IlluminationIntensity.Count; i++)
            {
                IlluminationIntensity[i] = Math.Max(-1, Math.Min(IlluminationIntensity[i], 1));
            }

            //

            List <Color> ElementColor = new List <Color>(IlluminationIntensity.Count);

            for (int i = 0; i < IlluminationIntensity.Count; i++)
            {
                switch (i)
                {
                case 6:
                    ElementColor.Add(Colors.X);
                    break;

                case 10:
                    ElementColor.Add(Colors.Y);
                    break;

                case 14:
                    ElementColor.Add(Colors.Z);
                    break;

                default:
                {
                    double _IlluminationIntensity = IlluminationIntensity[i];

                    if (_IlluminationIntensity == 0)
                    {
                        ElementColor.Add(CubeColor);
                    }
                    else
                    {
                        Com.ColorX EColor = new Com.ColorX(CubeColor);

                        if (_IlluminationIntensity < 0)
                        {
                            EColor.Lightness_HSL += EColor.Lightness_HSL * _IlluminationIntensity;
                        }
                        else
                        {
                            EColor.Lightness_HSL += (100 - EColor.Lightness_HSL) * _IlluminationIntensity;
                        }

                        ElementColor.Add(EColor.ToColor());
                    }
                }
                break;
                }
            }

            //

            List <double> ElementZAvg = new List <double>(Element3D.Count);

            for (int i = 0; i < Element3D.Count; i++)
            {
                Com.PointD3D[] Element = Element3D[i];

                double ZAvg = 0;

                foreach (Com.PointD3D P in Element)
                {
                    switch (View)
                    {
                    case Views.XY: ZAvg += P.Z; break;

                    case Views.YZ: ZAvg += P.X; break;

                    case Views.ZX: ZAvg += P.Y; break;
                    }
                }

                ZAvg /= Element.Length;

                ElementZAvg.Add(ZAvg);
            }

            List <int> ElementIndex = new List <int>(ElementZAvg.Count);

            for (int i = 0; i < ElementZAvg.Count; i++)
            {
                ElementIndex.Add(i);
            }

            for (int i = 0; i < ElementZAvg.Count; i++)
            {
                for (int j = i + 1; j < ElementZAvg.Count; j++)
                {
                    if (ElementZAvg[ElementIndex[i]] < ElementZAvg[ElementIndex[j]] || (ElementZAvg[ElementIndex[i]] <= ElementZAvg[ElementIndex[j]] + 2F && Element2D[ElementIndex[i]].Length < Element2D[ElementIndex[j]].Length))
                    {
                        int Temp = ElementIndex[i];
                        ElementIndex[i] = ElementIndex[j];
                        ElementIndex[j] = Temp;
                    }
                }
            }

            //

            using (Graphics Grph = Graphics.FromImage(PrjBmp))
            {
                Grph.SmoothingMode = SmoothingMode.AntiAlias;

                //

                for (int i = 0; i < ElementIndex.Count; i++)
                {
                    int EIndex = ElementIndex[i];

                    Color EColor = ElementColor[EIndex];

                    if (!EColor.IsEmpty && EColor.A > 0)
                    {
                        PointF[] Element = Element2D[EIndex];

                        if (Element.Length >= 3)
                        {
                            try
                            {
                                using (SolidBrush Br = new SolidBrush(EColor))
                                {
                                    Grph.FillPolygon(Br, Element);
                                }
                            }
                            catch { }
                        }
                        else if (Element.Length == 2)
                        {
                            double PrjZ = 0;

                            switch (View)
                            {
                            case Views.XY: PrjZ = PrjCenter3D.Z; break;

                            case Views.YZ: PrjZ = PrjCenter3D.X; break;

                            case Views.ZX: PrjZ = PrjCenter3D.Y; break;
                            }

                            float EdgeWidth = (TrueLenDist3D == 0 ? 2F : (float)(TrueLenDist3D / (ElementZAvg[EIndex] - PrjZ) * 2F));

                            try
                            {
                                Brush Br;

                                Func <Color, double, int> GetAlpha = (Cr, Z) =>
                                {
                                    int Alpha;

                                    if (TrueLenDist3D == 0)
                                    {
                                        Alpha = Cr.A;
                                    }
                                    else
                                    {
                                        if (Z - PrjZ <= TrueLenDist3D)
                                        {
                                            Alpha = Cr.A;
                                        }
                                        else
                                        {
                                            Alpha = (int)Math.Max(0, Math.Min(TrueLenDist3D / (Z - PrjZ) * Cr.A, 255));
                                        }
                                    }

                                    if (EdgeWidth < 1)
                                    {
                                        Alpha = (int)(Alpha * EdgeWidth);
                                    }

                                    return(Alpha);
                                };

                                if (Com.PointD.DistanceBetween(new Com.PointD(Element[0]), new Com.PointD(Element[1])) > 1)
                                {
                                    int Alpha0 = 0, Alpha1 = 0;

                                    switch (View)
                                    {
                                    case Views.XY:
                                    {
                                        Alpha0 = GetAlpha(EColor, Element3D[EIndex][0].Z);
                                        Alpha1 = GetAlpha(EColor, Element3D[EIndex][1].Z);
                                    }
                                    break;

                                    case Views.YZ:
                                    {
                                        Alpha0 = GetAlpha(EColor, Element3D[EIndex][0].X);
                                        Alpha1 = GetAlpha(EColor, Element3D[EIndex][1].X);
                                    }
                                    break;

                                    case Views.ZX:
                                    {
                                        Alpha0 = GetAlpha(EColor, Element3D[EIndex][0].Y);
                                        Alpha1 = GetAlpha(EColor, Element3D[EIndex][1].Y);
                                    }
                                    break;
                                    }

                                    Br = new LinearGradientBrush(Element[0], Element[1], Color.FromArgb(Alpha0, EColor), Color.FromArgb(Alpha1, EColor));
                                }
                                else
                                {
                                    int Alpha = GetAlpha(EColor, ElementZAvg[EIndex]);

                                    Br = new SolidBrush(Color.FromArgb(Alpha, EColor));
                                }

                                using (Pen Pn = new Pen(Br, EdgeWidth))
                                {
                                    Grph.DrawLines(Pn, Element);
                                }

                                if (Br != null)
                                {
                                    Br.Dispose();
                                }
                            }
                            catch { }
                        }
                    }
                }

                //

                Func <Com.PointD3D, int, int, int> GetAlphaOfPoint = (Pt, MinAlpha, MaxAlpha) =>
                {
                    switch (View)
                    {
                    case Views.XY: return((int)Math.Max(0, Math.Min(((Pt.Z - CubeCenter.Z) / CubeDiag + 0.5) * (MinAlpha - MaxAlpha) + MaxAlpha, 255)));

                    case Views.YZ: return((int)Math.Max(0, Math.Min(((Pt.X - CubeCenter.X) / CubeDiag + 0.5) * (MinAlpha - MaxAlpha) + MaxAlpha, 255)));

                    case Views.ZX: return((int)Math.Max(0, Math.Min(((Pt.Y - CubeCenter.Y) / CubeDiag + 0.5) * (MinAlpha - MaxAlpha) + MaxAlpha, 255)));

                    default: return(0);
                    }
                };

                Grph.DrawString("X", new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, 134), new SolidBrush(Color.FromArgb(GetAlphaOfPoint(P3D_100, 64, 192), Colors.X)), P_100);
                Grph.DrawString("Y", new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, 134), new SolidBrush(Color.FromArgb(GetAlphaOfPoint(P3D_010, 64, 192), Colors.Y)), P_010);
                Grph.DrawString("Z", new Font("微软雅黑", 9F, FontStyle.Regular, GraphicsUnit.Point, 134), new SolidBrush(Color.FromArgb(GetAlphaOfPoint(P3D_001, 64, 192), Colors.Z)), P_001);

                //

                string ViewName = string.Empty;

                switch (View)
                {
                case Views.XY: ViewName = "XY 视图 (主视图)"; break;

                case Views.YZ: ViewName = "YZ 视图"; break;

                case Views.ZX: ViewName = "ZX 视图"; break;
                }

                Grph.DrawString(ViewName, new Font("微软雅黑", 10F, FontStyle.Regular, GraphicsUnit.Point, 134), new SolidBrush(Colors.Text), new PointF(Math.Max(0, (PrjBmp.Width - PrjBmp.Height) / 4), Math.Max(0, (PrjBmp.Height - PrjBmp.Width) / 4)));

                //

                Grph.DrawRectangle(new Pen(Color.FromArgb(64, Colors.Border), 1F), new Rectangle(new Point(-1, -1), PrjBmp.Size));
            }

            return(PrjBmp);
        }