Exemplo n.º 1
0
        private void AffineTransform(ref Com.PointD3D Pt, Com.PointD3D Origin, Com.Matrix AffineMatrix)
        {
            //
            // 将一个 3D 坐标以指定点为新的原点进行仿射变换。
            //

            Pt -= Origin;
            Pt.AffineTransform(AffineMatrix);
            Pt += Origin;
        }
Exemplo n.º 2
0
        private void Label_Control_MouseDown(object sender, MouseEventArgs e)
        {
            //
            // 鼠标按下 Label_Control。
            //

            if (e.Button == MouseButtons.Left)
            {
                ((Label)sender).BackColor = Me.RecommendColors.Button_INC.ToColor();
                ((Label)sender).Cursor    = Cursors.SizeWE;

                CubeSizeCopy              = CubeSize;
                AffineMatrix3DCopy        = AffineMatrix3D.Copy();
                IlluminationDirectionCopy = IlluminationDirection;
                ExposureCopy              = Exposure;

                CursorX   = e.X;
                AdjustNow = true;
            }
        }
Exemplo n.º 3
0
        private void Label_Rz_MouseMove(object sender, MouseEventArgs e)
        {
            //
            // 鼠标经过 Label_Rz。
            //

            if (AdjustNow && !BackgroundWorker_RepaintBmpDelay.IsBusy)
            {
                double angle = (e.X - CursorX) * RadPerPixel;

                ((Label)sender).Text = (angle >= 0 ? "+ " : "- ") + (Math.Abs(angle) / Math.PI * 180).ToString("F0") + "°";

                Com.Matrix matrixLeft = Com.PointD3D.RotateZMatrix(angle);

                AffineMatrix3D = Com.Matrix.Multiply(matrixLeft, AffineMatrix3DCopy);

                if (!Com.Matrix.IsNullOrEmpty(AffineMatrix3D))
                {
                    BackgroundWorker_RepaintBmpDelay.RunWorkerAsync();
                }
            }
        }
Exemplo n.º 4
0
        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);
        }