예제 #1
0
 public Frame3d(Vector3d origin, Quaterniond orientation)
 {
     rotation    = orientation;
     this.origin = origin;
 }
예제 #2
0
 public double Dot(Quaterniond q2)
 {
     return(x * q2.x + y * q2.y + z * q2.z + w * q2.w);
 }
예제 #3
0
        /// <summary>
        /// Solve for Translate/Rotate update, based on current From and To
        /// Note: From and To are invalidated, will need to be re-computed after calling this
        /// </summary>
        void update_transformation()
        {
            int N = From.Length;

            // normalize weights
            double wSum = 0;

            for (int i = 0; i < N; ++i)
            {
                wSum += Weights[i];
            }

            double wSumInv = 1.0 / wSum;

            // compute means
            Vector3d MeanX = Vector3d.Zero;
            Vector3d MeanY = Vector3d.Zero;

            for (int i = 0; i < N; ++i)
            {
                MeanX += (Weights[i] * wSumInv) * From[i];
                MeanY += (Weights[i] * wSumInv) * To[i];
            }


            // subtract means
            for (int i = 0; i < N; ++i)
            {
                From[i] -= MeanX;
                To[i]   -= MeanY;
            }

            // construct matrix 3x3 Matrix  From*Transpose(To)
            // (vectors are columns)
            double[] M = new double[9];
            for (int k = 0; k < 3; ++k)
            {
                int r = 3 * k;
                for (int i = 0; i < N; ++i)
                {
                    double lhs = (Weights[i] * wSumInv) * From[i][k];
                    M[r + 0] += lhs * To[i].x;
                    M[r + 1] += lhs * To[i].y;
                    M[r + 2] += lhs * To[i].z;
                }
            }

            // compute SVD of M
            SingularValueDecomposition svd = new SingularValueDecomposition(3, 3, 100);
            uint ok = svd.Solve(M, -1);     // sort in decreasing order, like Eigen

            Debug.Assert(ok < 9999999);
            double[] U = new double[9], V = new double[9], Tmp = new double[9];;
            svd.GetU(U);
            svd.GetV(V);

            // this is our rotation update
            double[] RotUpdate = new double[9];

            // U*V gives us desired rotation
            double detU = MatrixUtil.Determinant3x3(U);
            double detV = MatrixUtil.Determinant3x3(V);

            if (detU * detV < 0)
            {
                double[] S = MatrixUtil.MakeDiagonal3x3(1, 1, -1);
                MatrixUtil.Multiply3x3(V, S, Tmp);
                MatrixUtil.Transpose3x3(U);
                MatrixUtil.Multiply3x3(Tmp, U, RotUpdate);
            }
            else
            {
                MatrixUtil.Transpose3x3(U);
                MatrixUtil.Multiply3x3(V, U, RotUpdate);
            }

            // convert matrix to quaternion
            Matrix3d    RotUpdateM = new Matrix3d(RotUpdate);
            Quaterniond RotUpdateQ = new Quaterniond(RotUpdateM);

            // [TODO] is this right? We are solving for a translation and
            //  rotation of the current From points, but when we fold these
            //  into Translation & Rotation variables, we have essentially
            //  changed the order of operations...

            // figure out translation update
            Vector3d TransUpdate = MeanY - RotUpdateQ * MeanX;

            Translation += TransUpdate;

            // and rotation
            Rotation = RotUpdateQ * Rotation;


            // above was ported from this code...still not supporting weights though.
            // need to figure out exactly what this code does (like, what does
            // transpose() do to a vector??)

            //            /// Normalize weight vector
            //Eigen::VectorXd w_normalized = w/w.sum();
            ///// De-mean
            //Eigen::Vector3d X_mean, Y_mean;
            //for(int i=0; i<3; ++i) {
            //    X_mean(i) = (X.row(i).array()*w_normalized.transpose().array()).sum();
            //    Y_mean(i) = (Y.row(i).array()*w_normalized.transpose().array()).sum();

            //Eigen::Matrix3d sigma = X * w_normalized.asDiagonal() * Y.transpose();
        }
예제 #4
0
 /// <summary>
 /// Interpolate between two frames - Lerp for origin, Slerp for rotation
 /// </summary>
 public static Frame3d Interpolate(Frame3d f1, Frame3d f2, double t)
 {
     return(new Frame3d(
                Vector3d.Lerp(f1.origin, f2.origin, t),
                Quaterniond.Slerp(f1.rotation, f2.rotation, t)));
 }
예제 #5
0
 public Quaterniond(Quaterniond p, Quaterniond q, double t)
 {
     x = y = z = 0; w = 1;
     SetToSlerp(p, q, t);
 }
예제 #6
0
 public static Vector3d Rotate(Vector3d pos, Vector3d origin, Quaterniond rotation)
 {
     return(rotation * (pos - origin) + origin);
 }
예제 #7
0
        public void AlignAxis(int nAxis, Vector3d vTo)
        {
            Quaterniond rot = Quaterniond.FromTo(GetAxis(nAxis), vTo);

            Rotate(rot);
        }
예제 #8
0
        public static Quaterniond FromToConstrained(Vector3d vFrom, Vector3d vTo, Vector3d vAround)
        {
            double fAngle = MathUtil.PlaneAngleSignedD(vFrom, vTo, vAround);

            return(Quaterniond.AxisAngleD(vAround, fAngle));
        }
예제 #9
0
 /// <summary>
 /// this rotates the frame around its own axes, rather than around the world axes,
 /// which is what Rotate() does. So, RotateAroundAxis(AxisAngleD(Z,180)) is equivalent
 /// to Rotate(AxisAngleD(My_AxisZ,180)).
 /// </summary>
 public void RotateAroundAxes(Quaterniond q)
 {
     rotation = rotation * q;
 }
예제 #10
0
        public Frame3d RotatedAround(Vector3d point, Quaterniond q)
        {
            Vector3d dv = q * (this.origin - point);

            return(new Frame3d(point + dv, q * this.rotation));
        }
예제 #11
0
 public Frame3d Rotated(Quaterniond q)
 {
     return(new Frame3d(this.origin, q * this.rotation));
 }
예제 #12
0
 public Frame3d(Frame3d copy)
 {
     this.rotation = copy.rotation;
     this.origin   = copy.origin;
 }
예제 #13
0
 public void Rotate(Quaterniond q)
 {
     rotation = q * rotation;
 }
예제 #14
0
 public static Quaterniond Inverse(Quaterniond q)
 {
     return(q.Inverse());
 }
예제 #15
0
 public Frame3d(Vector3d origin)
 {
     rotation    = Quaterniond.Identity;
     this.origin = origin;
 }
예제 #16
0
 public Quaterniond(Quaterniond q2)
 {
     x = q2.x; y = q2.y; z = q2.z; w = q2.w;
 }
예제 #17
0
 public Frame3d(Vector3d origin, Vector3d setZ)
 {
     rotation    = Quaterniond.FromTo(Vector3d.AxisZ, setZ);
     this.origin = origin;
 }
예제 #18
0
 public static Quaterniond Slerp(Quaterniond p, Quaterniond q, double t)
 {
     return(new Quaterniond(p, q, t));
 }
예제 #19
0
 ///<summary> Map quaternion *into* local coordinates of Frame </summary>
 public Quaterniond ToFrame(ref Quaterniond q)
 {
     return(Quaterniond.Inverse(this.rotation) * q);
 }
예제 #20
0
 public static Frame3f Rotate(Frame3f f, Vector3d origin, Quaterniond rotation)
 {
     f.Rotate((Quaternionf)rotation);
     f.Origin = (Vector3f)Rotate(f.Origin, origin, rotation);
     return(f);
 }
예제 #21
0
 /// <summary> Map quaternion *from* local frame coordinates into "world" coordinates </summary>
 public Quaterniond FromFrame(ref Quaterniond q)
 {
     return(this.rotation * q);
 }
예제 #22
0
        // ported from WildMagic5 Wm5ContBox3.cpp::MergeBoxes
        public static Box3d Merge(ref Box3d box0, ref Box3d box1)
        {
            // Construct a box that contains the input boxes.
            var box = new Box3d();

            // The first guess at the box center.  This value will be updated later
            // after the input box vertices are projected onto axes determined by an
            // average of box axes.
            box.Center = 0.5 * (box0.Center + box1.Center);

            // A box's axes, when viewed as the columns of a matrix, form a rotation
            // matrix.  The input box axes are converted to quaternions.  The average
            // quaternion is computed, then normalized to unit length.  The result is
            // the slerp of the two input quaternions with t-value of 1/2.  The result
            // is converted back to a rotation matrix and its columns are selected as
            // the merged box axes.
            Quaterniond q0 = new Quaterniond(), q1 = new Quaterniond();
            var         rot0 = new Matrix3d(ref box0.AxisX, ref box0.AxisY, ref box0.AxisZ, false);

            q0.SetFromRotationMatrix(ref rot0);
            var rot1 = new Matrix3d(ref box1.AxisX, ref box1.AxisY, ref box1.AxisZ, false);

            q1.SetFromRotationMatrix(ref rot1);
            if (q0.Dot(q1) < 0)
            {
                q1 = -q1;
            }

            Quaterniond q         = q0 + q1;
            double      invLength = 1.0 / Math.Sqrt(q.Dot(q));

            q = q * invLength;
            Matrix3d q_mat = q.ToRotationMatrix();

            box.AxisX = q_mat.Column(0); box.AxisY = q_mat.Column(1); box.AxisZ = q_mat.Column(2);              //q.ToRotationMatrix(box.Axis);

            // Project the input box vertices onto the merged-box axes.  Each axis
            // D[i] containing the current center C has a minimum projected value
            // min[i] and a maximum projected value max[i].  The corresponding end
            // points on the axes are C+min[i]*D[i] and C+max[i]*D[i].  The point C
            // is not necessarily the midpoint for any of the intervals.  The actual
            // box center will be adjusted from C to a point C' that is the midpoint
            // of each interval,
            //   C' = C + sum_{i=0}^2 0.5*(min[i]+max[i])*D[i]
            // The box extents are
            //   e[i] = 0.5*(max[i]-min[i])

            int      i, j;
            double   dot;
            var      vertex = new Vector3d[8];
            Vector3d pmin   = Vector3d.Zero;
            Vector3d pmax   = Vector3d.Zero;

            box0.ComputeVertices(vertex);
            for (i = 0; i < 8; ++i)
            {
                Vector3d diff = vertex[i] - box.Center;
                for (j = 0; j < 3; ++j)
                {
                    dot = box.Axis(j).Dot(ref diff);
                    if (dot > pmax[j])
                    {
                        pmax[j] = dot;
                    }
                    else if (dot < pmin[j])
                    {
                        pmin[j] = dot;
                    }
                }
            }

            box1.ComputeVertices(vertex);
            for (i = 0; i < 8; ++i)
            {
                Vector3d diff = vertex[i] - box.Center;
                for (j = 0; j < 3; ++j)
                {
                    dot = box.Axis(j).Dot(ref diff);
                    if (dot > pmax[j])
                    {
                        pmax[j] = dot;
                    }
                    else if (dot < pmin[j])
                    {
                        pmin[j] = dot;
                    }
                }
            }

            // [min,max] is the axis-aligned box in the coordinate system of the
            // merged box axes.  Update the current box center to be the center of
            // the new box.  Compute the extents based on the new center.
            for (j = 0; j < 3; ++j)
            {
                box.Center   += (0.5 * (pmax[j] + pmin[j])) * box.Axis(j);
                box.Extent[j] = 0.5 * (pmax[j] - pmin[j]);
            }

            return(box);
        }
예제 #23
0
 /// <summary>
 /// Create new Vector3d representing an Euler angles for a Quaternionf rotation.
 /// </summary>
 /// <param name="quat">Quaternion</param>
 /// <returns>Vector3 representing Euler angles rotation</returns>
 public static Vector3d ToEuler(Quaterniond quat)
 {
     return(quat.ToEuler());
 }