Beispiel #1
0
        public Matrix3D GetStrain(Symmetry symmetry, Matrix3D rotation, Matrix3D stress)
        {
            Matrix3D m1 = rotation.Transpose() * stress * rotation;
            Matrix3D m2 = GetStrain(symmetry, m1);
            Matrix3D m  = rotation * m2 * rotation.Transpose();

            return(m);
        }
Beispiel #2
0
        /// <summary>
        /// 楕円の中心群とそれらの半径から、真の中心のオフセット位置(offset)と傾き(tau, phi)を返す
        /// </summary>
        /// <param name="CenterPt"></param>
        /// <param name="Peaks"></param>
        /// <param name="PixelSize"></param>
        /// <param name="CameraLength"></param>
        /// <param name="offset"></param>
        /// <param name="tau"></param>
        /// <param name="phi"></param>
        public static void GetTiltAndOffset(PointD[] EllipseCenter, double[] Radius, double CameraLength, ref PointD offset,
                                            ref double tau, ref double phi)
        {
            //まずCenterPtの回帰直線を求める
            double phi1, A;

            phi1 = A = 0;
            Statistics.LineFitting(EllipseCenter, ref phi1, ref A);
            double CosPhi1 = Math.Cos(phi1);
            double SinPhi1 = Math.Sin(phi1);
            bool   xMode   = Math.Abs(CosPhi1) > 1 / Math.Sqrt(2);

            //この直線上の点B(x,y)と、各CenterPtの距離Riとしたとき
            //δ^2= ( Ri - Cameralength * Tan(2θ)^2 *Sin(ψ) / pixelSize )^2 
            //が最小になるような点Bとψをさがす

            double[] TheoriticalRperSinPsi = new double[EllipseCenter.Length];
            double   startTau1             = -Math.PI / 180;
            double   stepTau1 = Math.PI / 9000;
            double   endTau1 = Math.PI / 180;
            double   tau1, bestTau1;

            tau1 = 0;

            double startCenter = -5;
            double stepCenter = 0.1;
            double endCenter = 5;
            double Center, BestCenter;
            double BestY, BestX, X, Y;

            double residual, bestResidual;

            bestResidual = double.PositiveInfinity;
            BestX        = BestY = bestTau1 = BestCenter = 0;
            //double temp;
            for (int n = 0; n < 40; n++)
            {
                for (Center = startCenter; Center <= endCenter; Center += stepCenter)
                {
                    if (xMode)
                    {
                        X = Center;
                        Y = (X * SinPhi1 - A) / CosPhi1;
                    }
                    else
                    {
                        Y = Center;
                        X = (Y * CosPhi1 + A) / SinPhi1;
                    }
                    for (tau1 = startTau1; tau1 <= endTau1; tau1 += stepTau1)
                    {
                        residual = 0;
                        for (int i = 0; i < EllipseCenter.Length; i++)
                        {
                            //現在のTau,X,Yから予想される半径Rの円の中心位置は
                            double IdealX, IdealY;
                            double TwoTheta = Math.Atan2(Radius[i], CameraLength);
                            //Rはtauが正のとき正、負のとき負
                            //double R = CameraLength * 2 * Math.Sin(TwoTheta) * Math.Sin(TwoTheta) * Math.Sin(tau1) / (Math.Cos(2 * TwoTheta) + Math.Cos(2 * tau1));
                            //1/2 CL tan2q { sinj [tan(2q+j) -tan(2q-j)] }
                            double R = 0.5 * CameraLength * Math.Sin(TwoTheta) * (1 / Math.Cos(TwoTheta + tau1) - 1 / Math.Cos(TwoTheta - tau1));
                            if (tau1 > 0)
                            {
                                R = Math.Abs(R);
                            }
                            else
                            {
                                R = -Math.Abs(R);
                            }

                            IdealX = R * CosPhi1;
                            IdealY = R * SinPhi1;

                            if (xMode && tau1 * IdealX <= 0)//横方向に広がっていて tau1 > 0 かつ idealX <0  あるいは tau1 < 0 かつ idealX > 0 のときは
                            {
                                IdealX = -IdealX;
                                IdealY = -IdealY;
                            }
                            if (!xMode && tau1 * IdealY <= 0)//縦方向に広がっていて tau1 > 0 かつ idealY <0  あるいは tau1 < 0 かつ idealY > 0 のときは
                            {
                                IdealX = -IdealX;
                                IdealY = -IdealY;
                            }
                            //ここまでで、Tau すなわち Rが正のときは楕円の中心もX,Yのいずれかの方向に正に振れる事になる
                            residual += (X + IdealX - EllipseCenter[i].X) * (X + IdealX - EllipseCenter[i].X) * 1000
                                        + (Y + IdealY - EllipseCenter[i].Y) * (Y + IdealY - EllipseCenter[i].Y) * 1000;
                        }
                        if (residual < bestResidual)
                        {
                            bestResidual = residual;
                            BestX        = X;
                            BestY        = Y;
                            BestCenter   = Center;
                            bestTau1     = tau1;
                        }
                    }
                }
                startCenter = BestCenter - 2.4 * stepCenter;
                endCenter   = BestCenter + (2.4 * stepCenter);
                stepCenter *= 0.8;

                startTau1 = bestTau1 - 2.4 * stepTau1;
                endTau1   = bestTau1 + 2.4 * stepTau1;
                stepTau1 *= 0.8;
            }//最適化終了

            offset = new PointD(BestX, BestY);

            //無条件に270°引いて
            phi1 -= 9 * Math.PI / 2;

            //xModeが真かつtauが正のとき. このとき回転軸は-135°〜-45°になるべき
            if (xMode && bestTau1 >= 0)
            {
                while (phi1 < -Math.PI * 3 / 4 - 0.01)//-135°〜-45°の範囲じゃないときは
                {
                    phi1 += Math.PI;
                }
            }
            //xModeが真かつtauが負のとき. このとき回転軸は45°〜135°になるべき
            if (xMode && bestTau1 < 0)
            {
                while (phi1 < Math.PI / 4 - 0.01)//45°以下のときは
                {
                    phi1 += Math.PI;
                }
            }
            //xModeが偽かつtauが正のとき. このとき回転軸は-45°〜45°になるべき
            if (!xMode && bestTau1 >= 0)
            {
                while (phi1 < -Math.PI / 4 - 0.01)//-45°〜45°の範囲じゃないときは
                {
                    phi1 += Math.PI;
                }
            }
            //xModeが偽かつtauが負のとき.このとき回転軸は135°〜215°になるべき
            if (!xMode && bestTau1 < 0)
            {
                while (phi1 < Math.PI * 3 / 4 - 0.01)//135°〜215°の範囲じゃないときは
                {
                    phi1 += Math.PI;
                }
            }

            bestTau1 = Math.Abs(bestTau1);

            double CosPhi = Math.Cos(phi);
            double SinPhi = Math.Sin(phi);
            double CosTau = Math.Cos(tau);
            double SinTau = Math.Sin(tau);

            CosPhi1 = Math.Cos(phi1);
            SinPhi1 = Math.Sin(phi1);
            double CosTau1 = Math.Cos(bestTau1);
            double SinTau1 = Math.Sin(bestTau1);

            var M = new Matrix3D(CosPhi, SinPhi, 0, -SinPhi, CosPhi, 0, 0, 0, 1);
            var P = new Matrix3D(1, 0, 0, 0, CosTau, SinTau, 0, -SinTau, CosTau);

            var M1 = new Matrix3D(CosPhi1, SinPhi1, 0, -SinPhi1, CosPhi1, 0, 0, 0, 1);
            var P1 = new Matrix3D(1, 0, 0, 0, CosTau1, SinTau1, 0, -SinTau1, CosTau1);

            var Q = M1 * P1 * M1.Transpose() * M * P * M.Transpose();

            tau = Math.Acos(Q.E33);
            if (Math.Sin(tau) == 0)
            {
                phi = 0;
            }
            else
            {
                phi = Math.Atan2(-Q.E31, Q.E32);
            }

            bestResidual = double.PositiveInfinity;
            double startPhi = phi - 0.1;
            double endPhi   = phi + 0.1;
            double stepPhi  = 0.01;
            double startTau = tau - 0.01;
            double endTau   = tau + 0.01;
            double stepTau  = 0.001;
            double bestPhi  = phi;
            double bestTau  = tau;
            double temp;

            for (int n = 0; n < 30; n++)
            {
                for (phi = startPhi; phi <= endPhi; phi += stepPhi)
                {
                    for (tau = startTau; tau <= endTau; tau += stepTau)
                    {
                        CosPhi = Math.Cos(phi);
                        SinPhi = Math.Sin(phi);
                        CosTau = Math.Cos(tau);
                        SinTau = Math.Sin(tau);

                        residual = 0;

                        temp      = Q.E11 - (CosPhi * CosPhi + CosTau * SinPhi * SinPhi);
                        residual += temp * temp;
                        temp      = Q.E12 - (CosPhi * SinPhi - CosTau * CosPhi * SinPhi);
                        residual += temp * temp;
                        temp      = Q.E13 - (SinPhi * SinTau);
                        residual += temp * temp;
                        temp      = Q.E21 - (CosPhi * SinPhi - CosPhi * CosTau * SinPhi);
                        residual += temp * temp;
                        temp      = Q.E22 - (CosPhi * CosPhi * CosTau + SinPhi * SinPhi);
                        residual += temp * temp;
                        temp      = Q.E23 - (-CosPhi * SinTau);
                        residual += temp * temp;
                        temp      = Q.E31 - (-SinPhi * SinTau);
                        residual += temp * temp;
                        temp      = Q.E32 - (CosPhi * SinTau);
                        residual += temp * temp;
                        temp      = Q.E33 - (CosTau);
                        residual += temp * temp;
                        if (bestResidual > residual)
                        {
                            bestPhi      = phi;
                            bestTau      = tau;
                            bestResidual = residual;
                        }
                    }
                }
                startPhi = bestPhi - stepPhi;
                endPhi   = bestPhi + stepPhi;
                stepPhi *= 0.4;
                startTau = bestTau - stepTau;
                endTau   = bestTau + stepTau;
                stepTau *= 0.4;
            }

            phi = bestPhi;
            tau = bestTau;
        }