Пример #1
0
        /// <summary>
        /// 平面上に分布する点集合が与えられたとき、その点集合が作る多角形の情報を返す
        /// 1. 頂点index (originから見て反時計回り)
        /// 2. 法線ベクトル
        /// 3. 中心座標
        /// </summary>
        /// <param name="points"></param>
        /// <returns></returns>
        public static (int[] Indices, V3d Center, V3d Norm) PolygonInfo(IEnumerable <V3d> points, V3d origin)
        {
            var center = new V3d(points.Average(p => p.X), points.Average(p => p.Y), points.Average(p => p.Z));
            var prm    = Geometriy.GetPlaneEquationFromPoints(points.Select(p => p.ToVector3DBase()));
            var norm   = new V3d(prm[0], prm[1], prm[2]);

            if (V3d.Dot(norm, (center - origin)) < 0)
            {
                norm = -norm;
            }

            //座標変換 (XY平面に投影)
            var rot = CreateRotationToZ(norm);

            var vXY = points.Select(p => p - center).Select(p => new V2d(rot.M11 * p.X + rot.M12 * p.Y + rot.M13 * p.Z, rot.M21 * p.X + rot.M22 * p.Y + rot.M23 * p.Z)).ToList();

            int i = vXY.FindIndex(p => p.LengthSquared == vXY.Max(q => q.LengthSquared));//原点から最も距離の遠い点を選ぶ

            //もう一つ点を選び、直線の方程式を産出
            List <int> iList = new List <int>(new[] { i });

            do
            {
                for (int j = 0; j < vXY.Count; j++)
                {
                    if (j != i)
                    {
                        var V = new V2d(vXY[j].Y - vXY[i].Y, vXY[i].X - vXY[j].X);
                        var c = vXY[j].X * vXY[i].Y - vXY[i].X * vXY[j].Y;

                        if (vXY.All(p => V2d.Dot(p, V) + c <= Th))
                        {
                            iList.Add(j);
                            i = j;
                            break;
                        }
                    }
                }
            } while (i != iList[0]);

            return(iList.ToArray(), center, norm);
        }
        private double[] getSrcImage()
        {
            if (Crystal.Bethe.Disks == null || trackBarOutputThickness.Value >= Crystal.Bethe.Disks.Length)
            {
                return(null);
            }

            var image  = new double[ImageWidth * ImageHeight];
            var disks  = Crystal.Bethe.Disks[trackBarOutputThickness.Value];
            var center = new PointD(ImageWidth / 2.0, ImageHeight / 2.0);

            //中心付近の1ピクセル当たりの角度

            foreach (var disk in disks.Where(disk => disk.Intensity.Max() > 1E-20))
            {
                var v     = new { x = disk.G.X, y = -disk.G.Y, z = -disk.G.Z };//ここでベクトルのY,Zの符号を反転
                var point = Geometriy.GetCrossPoint(0, 0, 1, FormDiffractionSimulator.CameraLength2, new Vector3D(0, 0, 0), new Vector3D(v.x, v.y, v.z + FormDiffractionSimulator.EwaldRadius));
                var pt    = new PointD(point.X, point.Y);
                //ptをピクセル座標に変換する
                var diskCenter = new Point((int)(pt.X / ImagePixelSize + center.X + 0.5), (int)(pt.Y / ImagePixelSize + center.Y + 0.5));
                if (diskCenter.X > -ImageWidth * 0.5 && diskCenter.Y > -ImageHeight * 0.5 && diskCenter.X < ImageWidth * 1.5 && diskCenter.Y < ImageHeight * 1.5)
                {
                    var side = (int)Math.Sqrt(disk.Intensity.Length);
                    for (int y = diskCenter.Y + side / 2, n = 0; y >= diskCenter.Y - side / 2; y--)
                    {
                        for (int x = diskCenter.X + side / 2; x >= diskCenter.X - side / 2; x--)
                        {
                            if (x > -1 && x < ImageWidth && y > -1 && y < ImageHeight && (diskCenter.X - x) * (diskCenter.X - x) + (diskCenter.Y - y) * (diskCenter.Y - y) < (side * side / 4))
                            {
                                image[y * ImageWidth + x] += disk.Intensity[n];
                            }
                            n++;
                        }
                    }
                }
            }
            return(image);
        }
        /// <summary>
        /// 回折スポットおよび指数ラベルの描画
        /// </summary>
        /// <param name="graphics">描画対象のグラフィックオブジェクト</param>
        /// <param name="drawLabel">ラベルを描画するかどうか</param>
        /// <param name="outputOnlySpotInformation">このフラグがTrueの場合は、画面描画は行わずにspotの情報だけを返す</param>
        public List <SpotInformation> GetDiffractionSpots(Matrix3D rotation, IEnumerable <Vector3D> gVector, double coeff)
        {
            var    spotInformation = new List <SpotInformation>();
            double sigma           = spotRadiusOnDetector;

            //描画するスポットを決める
            foreach (Vector3D g in gVector)
            {
                Vector3DBase vec = rotation * g;
                if (vec.Z > -3 * excitationError)
                {
                    vec.Y = -vec.Y; vec.Z = -vec.Z;//ここでベクトルのY,Zの符号を反転
                    double L2 = vec.X * vec.X + vec.Y * vec.Y;
                    double dev = ewaldRadius - Math.Sqrt(L2 + (vec.Z + ewaldRadius) * (vec.Z + ewaldRadius)), dev2 = dev * dev;
                    if (dev2 < 9 * error2)
                    {
                        if (-sinTau * vec.Y + cosTau * (vec.Z + ewaldRadius) > 0)//(vec.X, vec.Y, vec.Z + EwaldRadius) と(0, -sinTau, cosTau) の内積が0より大きい)
                        {
                            //2020/02/03の変更対処済み
                            var    point = Geometriy.GetCrossPoint(0, sinTau, -cosTau, cameraLength2, new Vector3D(0, 0, 0), new Vector3D(vec.X, vec.Y, vec.Z + ewaldRadius));
                            PointD pt    = new PointD(point.X, point.Y * cosTau + point.Z * sinTau);

                            //if (IsDetectorArea(pt))
                            {
                                double intensity = g.RelativeIntensity / (sigma * sqrt2PI) * Math.Exp(-dev2 / error2 / 2);
                                if (intensity > 1E-3)
                                {
                                    spotInformation.Add(new SpotInformation(pt.X, pt.Y, intensity * coeff, sigma));
                                }
                            }
                        }
                    }
                }
            }
            return(spotInformation);
        }
        private void execute(string filename = "")
        {
            var n            = 0;
            var initialRot   = new Matrix3D(FormDiffractionSimulator.formMain.Crystal.RotationMatrix);
            var originalAxes = new Matrix3D(OriginalCrystal.A_Axis * 10, OriginalCrystal.B_Axis * 10, OriginalCrystal.C_Axis * 10);

            //データ数を減らす
            var numMax = 4;
            var ptTemp = graphControl.Profile.Pt;
            var pt     = new List <PointD>();

            for (int i = 0; i < ptTemp.Count; i += numMax)
            {
                var num = Math.Min(numMax, ptTemp.Count - i);
                var p   = new PointD();
                for (int j = i; j < i + num; j++)
                {
                    p += ptTemp[j];
                }
                pt.Add(p / num);
            }

            //var pt = graphControl.Profile.Pt;

            var states = new List <(double depth, double pressure, double thickness)>();

            for (int i = 0; i < pt.Count - 1; i++)
            {
                states.Add(((pt[i].X + pt[i + 1].X) / 2, (pt[i].Y + pt[i + 1].Y) / 2, pt[i + 1].X - pt[i].X));
            }

            int count = checkBoxOmegaStep.Checked ? numericBoxOmegaTimes.ValueInteger : 1;

            toolStripProgressBar.Maximum = states.Count * count;
            toolStripProgressBar.Value   = 0;


            //無回転の時の圧縮面の法線ベクトル
            int cH = numericBoxShockedPlaneH.ValueInteger, cK = numericBoxShockedPlaneK.ValueInteger, cL = numericBoxShockedPlaneL.ValueInteger;
            var compressedPlane = (cH * OriginalCrystal.A_Star + cK * OriginalCrystal.B_Star + cL * OriginalCrystal.C_Star).Normarize();
            //無回転の時の圧縮面の法線ベクトルを(1,0,0)方向に向ける回転ベクトル
            var m1 = Matrix3D.Rot(Vector3DBase.VectorProduct(compressedPlane, new Vector3DBase(1, 0, 0)), Math.Acos(compressedPlane.X));

            //無回転時の圧縮面と平行なベクトル
            (int h, int k, int l, Vector3DBase vec)v1 = (-cK, cH, 0, (-cK * OriginalCrystal.A_Axis + cH * OriginalCrystal.B_Axis).Normarize());
            (int h, int k, int l, Vector3DBase vec)v2 = (0, -cL, cK, (-cL * OriginalCrystal.B_Axis + cK * OriginalCrystal.C_Axis).Normarize());
            if (v1.vec.Length2 < 0.1)
            {
                v1 = (-cL, 0, cH, (-cL * OriginalCrystal.A_Axis + cH * OriginalCrystal.C_Axis).Normarize());
            }
            if (v2.vec.Length2 < 0.1)
            {
                v2 = (-cL, 0, cH, (-cL * OriginalCrystal.A_Axis + cH * OriginalCrystal.C_Axis).Normarize());
            }

            //回転状態の圧縮面の法線ベクトル
            var shockDirection = initialRot * compressedPlane;

            //無回転の時のスリップ面の法線ベクトル
            var slipPlane = (numericBoxSlipPlaneH.Value * OriginalCrystal.A_Star + numericBoxSlipPlaneK.Value * OriginalCrystal.B_Star + numericBoxSlipPlaneL.Value * OriginalCrystal.C_Star).Normarize();
            //回転時のスリップ面と圧縮面の外積ベクトル
            var rotationAxis2019 = Vector3DBase.AngleBetVectors(slipPlane, compressedPlane) < Math.PI / 2 ?
                                   initialRot * Vector3DBase.VectorProduct(slipPlane, compressedPlane) :
                                   initialRot *Vector3DBase.VectorProduct(compressedPlane, slipPlane);

            //(0,0,1)方向をrotationAxis2019に向ける回転ベクトル
            var m2 = Matrix3D.Rot(Vector3DBase.VectorProduct(new Vector3DBase(0, 0, 1), rotationAxis2019), Math.Acos(rotationAxis2019.Z));

            //2018モデル。結晶は圧縮軸に垂直な方向を回転軸として回転すると仮定。その回転軸のリストを設定
            List <Vector3DBase> rotationAxes2018 = new List <Vector3DBase>();
            var div1 = numericBoxDivisionOfRotationAxis.ValueInteger;//回転軸を分割する数
            var initialNormalDirection = Math.Abs(shockDirection.Z) < 0.5 ? new Vector3DBase(shockDirection.Y, -shockDirection.X, 0) : new Vector3DBase(0, -shockDirection.Z, shockDirection.Y);

            for (int rot = 0; rot < div1; rot++)
            {
                rotationAxes2018.Add(Matrix3D.Rot(shockDirection, 2 * Math.PI * rot / div1) * initialNormalDirection);
            }

            var div2 = numericBoxDivisionOfRotationAngle.ValueInteger;//回転量を分割する数

            double front = graphControl.LineList[0].X, back = graphControl.LineList[1].X;
            double omegaC = numericBoxCompressedOmega.RadianValue, sigmaOmegaC = numericBoxCompressedOmegaSigma.RadianValue;
            double omegaR = numericBoxReleasedOmega.RadianValue, sigmaOmegaR = numericBoxReleasedOmegaSigma.RadianValue;
            double thetaC_A = numericBoxCompressedThetaA.RadianValue, thetaC_B = numericBoxCompressedThetaB.RadianValue;
            double thetaR_A = numericBoxReleasedThetaA.RadianValue, thetaR_B = numericBoxReleasedThetaB.RadianValue;
            var    absorption    = 1.0;
            var    compiledImage = new double[FormDiffractionSimulator.FormDiffractionSimulatorGeometry.DetectorWidth * FormDiffractionSimulator.FormDiffractionSimulatorGeometry.DetectorHeight];
            var    spots         = new List <SpotInformation>();
            long   beforeSec     = 0;

            //メインループ開始
            for (int i = 0; i < states.Count; i++)
            {
                FormDiffractionSimulator.SkipDrawing = FormDiffractionSimulator.formMain.SkipDrawing = checkBoxSkipDrawing.Checked;
                var rotationList = new List <(Matrix3D rot, double weight)>();

                if (states[i].depth < front)//Uncompressedの時
                {
                    rotationList.Add((Matrix3D.IdentityMatrix, 1));
                }
                else
                {
                    var time1 = states[i].depth < back ? (states[i].depth - front) / numericBoxUp.Value : (back - front) / numericBoxUp.Value;
                    var time2 = states[i].depth < back ? 0.0 : (states[i].depth - back) / numericBoxUr.Value;
                    var omega = omegaC * time1 + omegaR * time2;
                    var range = 2.0;

                    if (radioButton2018Model.Checked)//2018モデルの時
                    {
                        var sigmaOmega = Math.Sqrt(time1 * sigmaOmegaC * time1 * sigmaOmegaC + time2 * sigmaOmegaR * time2 * sigmaOmegaR);

                        double start = Math.Max(0, omega - range * sigmaOmega), end = omega + range * sigmaOmega, step = (end - start) / div2;
                        var    rotationAngles = new List <PointD>();
                        for (var speed = start; speed <= end + step / 2; speed += step)
                        {
                            rotationAngles.Add(new PointD(speed, Math.Exp(-(speed - omega) * (speed - omega) / 2 / sigmaOmega / sigmaOmega)));
                        }
                        foreach (var axis in rotationAxes2018)
                        {
                            foreach (var angle in rotationAngles)
                            {
                                rotationList.Add((Matrix3D.Rot(axis, angle.X), angle.Y));
                            }
                        }
                    }
                    else//2019モデルの時
                    {
                        double sigmaTheta = states[i].depth < back ? thetaC_A + thetaC_B * time1 : thetaC_A * time1 + thetaR_A + thetaR_B * time2, sigmaTheta2 = sigmaTheta * sigmaTheta;
                        double sigmaOmega = sigmaOmegaC * time1 + sigmaOmegaR * time2, sigmaOmega2 = sigmaOmega * sigmaOmega;

                        double stepTheta = (range * sigmaTheta) / ((int)Math.Sqrt(div1) + 1);
                        double startR = Math.Max(0, omega - range * sigmaOmega), endR = omega + range * sigmaOmega, stepR = (endR - startR) / div2;
                        double stepPhi = (2 * Math.PI) / ((int)Math.Sqrt(div1) + 1);
                        if (stepTheta == 0)
                        {
                            stepTheta = double.PositiveInfinity;
                        }
                        if (stepR == 0)
                        {
                            stepR = double.PositiveInfinity;
                        }

                        for (var theta = stepTheta / 2; theta <= range * sigmaTheta; theta += stepTheta)
                        {
                            for (var phi = 0.0; phi < 2 * Math.PI; phi += stepPhi)
                            {
                                for (var r = startR; r <= endR; r += stepR)
                                {
                                    var v = new Vector3DBase(Math.Sin(theta) * Math.Cos(phi), Math.Sin(theta) * Math.Sin(phi), Math.Cos(theta));
                                    rotationList.Add((Matrix3D.Rot(m2 * v, r), Math.Exp(-(r - omega) * (r - omega) / 2 / sigmaOmega2 - theta * theta / 2 / sigmaTheta2) * r * r * Math.Sin(theta)));
                                }
                            }
                        }
                    }
                }
                var sum = rotationList.Sum(r => r.weight);
                rotationList = rotationList.Select(r => (r.rot, r.weight / sum)).ToList();

                //ここから、圧縮による格子定数の変化
                Matrix3D newAxes = originalAxes;
                if (states[i].depth >= front)
                {
                    var volume = EOS.InverseThirdBirchMurnaghan(numericBoxEOS_K0.Value, numericBoxEOS_Kprime.Value, states[i].pressure * 100);
                    if ((states[i].depth < back && radioButtonCompressedUniaxial.Checked) || (states[i].depth >= back && radioButtonReleasedUniaxial.Checked))
                    {
                        newAxes = m1.Inverse() * new Matrix3D(1 / volume, 0, 0, 0, 1, 0, 0, 0, 1) * m1 * originalAxes;
                    }
                    else
                    {
                        newAxes = new Matrix3D(Math.Pow(1 / volume, 1.0 / 3.0), 0, 0, 0, Math.Pow(1 / volume, 1.0 / 3.0), 0, 0, 0, Math.Pow(1 / volume, 1.0 / 3.0)) * originalAxes;
                    }
                }
                var a = new Vector3DBase(newAxes.E11, newAxes.E21, newAxes.E31);
                var b = new Vector3DBase(newAxes.E12, newAxes.E22, newAxes.E32);
                var c = new Vector3DBase(newAxes.E13, newAxes.E23, newAxes.E33);
                FormDiffractionSimulator.SkipDrawing = FormDiffractionSimulator.formMain.SkipDrawing = true;
                CrystalControl.CellConstants         = (a.Length, b.Length, c.Length, Vector3DBase.AngleBetVectors(b, c), Vector3DBase.AngleBetVectors(c, a), Vector3DBase.AngleBetVectors(a, b));

                var corrRot = newAxes * new Matrix3D(CrystalControl.Crystal.A_Axis * 10, CrystalControl.Crystal.B_Axis * 10, CrystalControl.Crystal.C_Axis * 10).Inverse();

                // ここまで

                //候補となるgの絞り込み
                FormDiffractionSimulator.SetVector(true);
                List <Vector3D> gVector = new List <Vector3D>();
                foreach (var g in FormDiffractionSimulator.formMain.Crystal.VectorOfG.Where(g => g.Flag && g.RelativeIntensity > 1E-6))
                {
                    var vec = initialRot * corrRot * g;
                    vec.Y = -vec.Y; vec.Z = -vec.Z;                           //ここでベクトルのY,Zの符号を反転
                    if (-sinTau * vec.Y + cosTau * (vec.Z + ewaldRadius) > 0) //(vec.X, vec.Y, vec.Z + EwaldRadius) と(0, -sinTau, cosTau) の内積が0より大きい)
                    {
                        //2020/02/03の変更対処済み
                        var point = Geometriy.GetCrossPoint(0, -sinTau, cosTau, cameraLength2, new Vector3D(0, 0, 0), new Vector3D(vec.X, vec.Y, vec.Z + ewaldRadius));
                        if (IsDetectorArea(new PointD(point.X, point.Y * cosTau + point.Z * sinTau)))
                        {
                            gVector.Add(g);
                        }
                    }
                }//ここまで

                //ここから揺動のループ
                var effectiveThickness = states[i].thickness / (shockDirection * new Vector3DBase(0, 0, 1));
                absorption *= Math.Exp(-numericBoxMassAbsorption.Value * FormDiffractionSimulator.formMain.Crystal.Density * effectiveThickness / 10000);
                foreach (var(rot, weight) in rotationList)
                {
                    var temp = GetDiffractionSpots(rot * initialRot * corrRot, gVector, states[i].thickness * absorption * absorption * weight);//入射と出射で二回absorptionをかける
                    spots.AddRange(temp);
                    if (n++ % 100 == 0 && !checkBoxSkipDrawing.Checked)
                    {
                        FormDiffractionSimulator.formMain.SetRotation(rot * initialRot * corrRot);
                    }
                }

                // if (spots.Count > 100 || i == states.Count - 1)
                {
                    var image = getImageData(spots);
                    for (int j = 0; j < compiledImage.Length; j++)
                    {
                        compiledImage[j] += image[j];
                    }
                    spots.Clear();
                }

                toolStripProgressBar.Value++;
                toolStripStatusLabel1.Text =
                    "Time elapsed: " + (sw.ElapsedMilliseconds / 1000.0).ToString("f1") + " sec., per slice: " + (sw.ElapsedMilliseconds - beforeSec).ToString() + " msec., wait for more " +
                    (sw.ElapsedMilliseconds / 1000.0 / toolStripProgressBar.Value * (toolStripProgressBar.Maximum - toolStripProgressBar.Value)).ToString("f1") + " sec.";
                beforeSec = sw.ElapsedMilliseconds;
                Application.DoEvents();
            }//メインループここまで

            compiledImage = compiledImage.Select(intensity => intensity * 1E6).ToArray();
            PseudoBitmap pseud = new PseudoBitmap(compiledImage, FormDiffractionSimulator.FormDiffractionSimulatorGeometry.DetectorWidth);

            Tiff.Writer("temp.tif", compiledImage, 2, FormDiffractionSimulator.FormDiffractionSimulatorGeometry.DetectorWidth);
            FormDiffractionSimulator.FormDiffractionSimulatorGeometry.ReadImage("temp.tif");

            if (filename != "")
            {
                File.Copy("temp.tif", filename, true);
            }

            FormDiffractionSimulator.SkipDrawing = FormDiffractionSimulator.formMain.SkipDrawing = false;
        }