/// <summary>
        /// Return the composition T2 o T1 of two transformations, T1 and T2.
        /// <remarks>Note the order: In the composition, T1 is performed first, then T2 afterwards!</remarks>
        /// <returns>The composite transform. </returns>
        /// </summary>
        public static AffineTransform2 operator *(AffineTransform2 T1, AffineTransform2 T2)
        {
            AffineTransform2 S = new AffineTransform2();

            S.mat = MatrixProduct(T1.mat, T2.mat);
            return(S);
        }
        /// <summary>
        /// Given a point p1 and linearly independent vectors v1 and v2, build the unique transformation taking p1 to q1, v1 to w1, and v2 to w2.
        /// <param name="p1">The point to be moved</param>
        /// <param name="v1">The first vector</param>
        /// <param name="v2">The second vector</param>
        /// <param name="q1">The point to which p1 will be moved</param>
        /// <param name="w1">The vector to which v1 will be moved</param>
        /// <param name="w2">The vector to which v2 will be moved</param>
        /// <returns>The affine transform. </returns>
        /// </summary>
        public static AffineTransform2 PointAndVectorsToPointAndVectors(
            Point p1, Vector v1, Vector v2,
            Point q1, Vector w1, Vector w2)
        {
            AffineTransform2 Trans1 = AffineTransform2.Translate(p1, new Point(0, 0));
            LinearTransform2 T      = LinearTransform2.VectorsToVectors(v1, v2, w1, w2);
            AffineTransform2 Trans2 = AffineTransform2.Translate(new Point(0, 0), q1);
            AffineTransform2 S      = new AffineTransform2();

            S.mat = T.Matrix();

            return(Trans2 * S * Trans1);

            /*
             * double[,] linmat = T.Matrix();
             * for (int i = 0; i < 2; i++)
             * {
             *  for (int j = 0; j < 2; j++)
             *  {
             *      W.mat[i, j] = linmat[i, j];
             *  }
             * }
             * return W;
             */
        }
        /// <summary>
        /// Construct a translation that displaces any point by the amount specified by the vector "v"
        /// <param name="v">The displacement vector</param>
        /// <returns>The translation transform. </returns>
        /// </summary>
        public static AffineTransform2 Translate(Vector v)
        {
            AffineTransform2 T = new AffineTransform2();

            T.mat[0, 2] = v.X;
            T.mat[1, 2] = v.Y;
            return(T);
        }
        /// <summary>
        /// Return the inverse of this transformation, if it's invertible.
        /// <returns>The inverse transform. </returns>
        /// </summary>
        public AffineTransform2 InverseTransform()
        {
            double[,] m = MatrixInverse(mat);
            AffineTransform2 T = new AffineTransform2();

            T.mat = m;
            return(T);
        }
        /// <summary>
        /// Construct a rotation by amount "angle" around the point "p". The resulting transformation leaves "p" unmoved.
        /// <param name="p">The center point for the rotation.</param>
        /// <param name="angle">The rotation angle, in radians.</param>
        /// <returns>The rotation transform. </returns>
        /// </summary>
        public static AffineTransform2 RotateAboutPoint(Point p, double angle)
        {
            Point            origin = new Point();
            AffineTransform2 T1     = Translate(origin - p);
            AffineTransform2 T2     = RotateXY(angle);
            AffineTransform2 T3     = Translate(p - origin);

            return(T3 * T2 * T1);
        }
        /// <summary>
        /// Construct a scaling transformation of the form (x, y) -> (ax, by)
        /// <param name="xamount">The multiplier for x-coordinates.</param>
        /// <param name="yamount">The multiplier for y-coordinates.</param>
        /// <returns>The scaling transform. </returns>
        /// </summary>
        public static AffineTransform2 AxisScale(double xamount, double yamount)
        {
            AffineTransform2 T = new AffineTransform2();

            T.mat[0, 0] = xamount;
            T.mat[1, 1] = yamount;
            T.mat[2, 2] = 1.0d;
            return(T);
        }
        /// <summary>
        /// Given a point p and linearly independent vectors v1 and v2, build the unique transformation taking p to q, v1 to w1, and v2 to w2.
        /// <param name="p1">The point to be moved</param>
        /// <param name="v1">The first vector</param>
        /// <param name="v2">The second vector</param>
        /// <param name="q1">The point to which p1 will be moved</param>
        /// <param name="w1">The vector to which v1 will be moved</param>
        /// <param name="w2">The vector to which v2 will be moved</param>
        /// <returns>The affine transform. </returns>
        /// </summary>
        public static AffineTransform2 PointsAndVectorToPointsAndVector(
            Point p1, Point p2, Vector v1,
            Point q1, Point q2, Vector w1)
        {
            Vector v2 = p2 - p1;
            Vector w2 = q2 - q1;

            return(AffineTransform2.PointAndVectorsToPointAndVectors(p1, v1, v2, q1, w1, w2));
        }
        /// <summary>
        /// Construct a scaling transformation of the form (x, y) -> (ax, by)
        /// <param name="xamount">The multiplier for x-coordinates.</param>
        /// <param name="yamount">The multiplier for y-coordinates.</param>
        /// <returns>The scaling transform. </returns>
        /// <remarks>Note that if the two scale amounts are equal, the transformation has no effect, when regarded in homogeneous coordinates. </remarks>
        /// </summary>
        public static ProjectiveTransform2 AxisScale(double xamount, double yamount)
        {
            AffineTransform2     T  = AffineTransform2.AxisScale(xamount, yamount);
            ProjectiveTransform2 T2 = new ProjectiveTransform2();

            T2.mat = T.mat;
            T.mat  = null;
            return(T2);
        }
        /// <summary>
        /// Construct a translation that displaces the Point p to the Point q
        /// <param name="P">A point that will be translated.</param>
        /// <param name="Q">The point where P will end up after translation.</param>
        /// <returns>The translation transform. </returns>
        /// </summary>
        public static ProjectiveTransform2 Translate(Point p, Point q)
        {
            AffineTransform2     T  = AffineTransform2.Translate(p, q);
            ProjectiveTransform2 T2 = new ProjectiveTransform2();

            T2.mat = T.mat;
            T.mat  = null;
            return(T2);
        }
        /// <summary>
        /// Construct a translation that displaces any point by the amount specified by the vector "v"
        /// <param name="v">The displacement vector</param>
        /// <returns>The translation transform. </returns>
        /// </summary>
        public static ProjectiveTransform2 Translate(Vector v)
        {
            AffineTransform2     T  = AffineTransform2.Translate(v);
            ProjectiveTransform2 T2 = new ProjectiveTransform2();

            T2.mat = T.mat;
            T.mat  = null;
            return(T2);
        }
        /// <summary>
        /// Construct a rotation that moves the positive X-axis towards the postive Y-axis by an amount "angle".
        /// <param name="angle">The rotation amount, in radians</param>
        /// </summary>
        public static ProjectiveTransform2 RotateXY(double angle)
        {
            AffineTransform2     T  = AffineTransform2.RotateXY(angle);
            ProjectiveTransform2 T2 = new ProjectiveTransform2();

            T2.mat = T.mat;
            T.mat  = null;
            return(T2);
        }
        /// <summary>
        /// Construct a rotation that moves the positive X-axis towards the postive Y-axis by an amount "angle".
        /// <param name="angle">The rotation amount, in radians</param>
        /// </summary>
        public static AffineTransform2 RotateXY(double angle)
        {
            AffineTransform2 T = new AffineTransform2();

            T.mat[0, 0] = Math.Cos(angle);
            T.mat[1, 1] = T.mat[0, 0];
            T.mat[1, 0] = Math.Sin(angle);
            T.mat[0, 1] = -T.mat[1, 0];
            return(T);
        }
        /// <summary>
        /// Build the unique transformation taking three independent points to any three other points.
        /// <param name="p1">The 1st point to be moved</param>
        /// <param name="p2">The 2nd point to be moved</param>
        /// <param name="p3">The 3rd point to be moved</param>
        /// <param name="q1">The point to which p1 will be moved</param>
        /// <param name="q2">The point to which p2 will be moved</param>
        /// <param name="q3">The point to which p3 will be moved</param>
        /// <returns>The affine transform. </returns>
        /// </summary>
        public static AffineTransform2 PointsToPoints(
            Point p1, Point p2, Point p3,
            Point q1, Point q2, Point q3)
        {
            Vector v1 = p2 - p1;
            Vector v2 = p3 - p1;
            Vector w1 = q2 - q1;
            Vector w2 = q3 - q1;

            return(AffineTransform2.PointAndVectorsToPointAndVectors(p1, v1, v2, q1, w1, w2));
        }
Example #14
0
        private static void testAT()
        {
            // Results: inverse is broken for LinearTransform; otherwise OK.
            Debug.Print("T0:" + new AffineTransform2() + "\nshould be identity\n");
            Vector v1 = new Vector(2, 3); Vector v2 = new Vector(-1, 4);
            Vector w1 = new Vector(0, 1); Vector w2 = new Vector(1, 1);
            Point  p1 = new Point(1, 5);
            Point  p2 = new Point(1, 1);
            Point  p3 = new Point(4, 4);
            Point  p4 = new Point(2, 5);
            Point  q1 = new Point(1, 1);
            Point  q2 = new Point(0, 0);
            Point  q3 = new Point(1, 2);
            Point  q4 = new Point(-1, 0);
            Point  pt = p1 + 0.5 * (p2 - p1);
            Point  qt = q1 + 0.5 * (q2 - q1);

            AffineTransform2 T1 = AffineTransform2.Translate(p1, q1);

            Debug.Print("T1:" + T1 * p1 + "\n should be " + q1 + "\n");
            AffineTransform2 T2 = AffineTransform2.PointAndVectorsToPointAndVectors(p1, v1, v2, q1, w1, w2);

            Debug.Print("T2:" + T2 * (v1 + v2) + "\n should be " + (w1 + w2) + "\n"); /// Broken
            Debug.Print("T2:" + T2 * p1 + "\n should be " + q1 + "\n");
            AffineTransform2 T3 = AffineTransform2.RotateXY(30 * Math.PI / 180);
            LinearTransform2 T4 = LinearTransform2.RotateXY(30 * Math.PI / 180);

            Debug.Print("T3,4:" + T3 + "\n should equal " + T4 + "\n");
            AffineTransform2 T5 = AffineTransform2.AxisScale(2, -3);

            Debug.Print("T5:" + T5 + "\n should be [2 0 ; 0 -3]\n");
            AffineTransform2 T6 = AffineTransform2.RotateAboutPoint(p1, 30 * Math.PI / 180);

            Debug.Print("T6:" + T6 * p1 + "\n should be " + p1 + "\n");
            Debug.Print("T6:" + T6 * new Vector(1, 0) + "\n should be [.866, .5]\n");

            AffineTransform2 TPV = AffineTransform2.PointAndVectorsToPointAndVectors(p1, v1, v2, q1, w1, w2); // Broken

            Debug.Print("TPV:" + TPV * p1 + "\n should be " + q1 + "\n");
            Debug.Print("TPV:" + TPV * (p1 + 0.3 * v2) + "\n should be " + (q1 + 0.3 * w2) + "\n");

            AffineTransform2 T7 = AffineTransform2.PointsToPoints(p1, p2, p3, q1, q2, q3);

            Debug.Print("T7:" + T7 * pt + "\n should be " + qt + "\n");
            Debug.Print("T7:" + T7 * p1 + "\n should be " + q1 + "\n");
            Debug.Print("T7:" + T7 * p2 + "\n should be " + q2 + "\n");
            Debug.Print("T7:" + T7 * p3 + "\n should be " + q3 + "\n");
            Debug.Print("Inverse:" + T7 * (T7.InverseTransform()) + "\n should be identity\n"); //BROKEN
            AffineTransform2 T7i = T7.InverseTransform();

            Debug.Print("T7i:" + T7i * q1 + "\n should be " + p1 + "\n");
            Debug.Print("T7i:" + T7i * q2 + "\n should be " + p2 + "\n");
            Debug.Print("T7i:" + T7i * q3 + "\n should be " + p3 + "\n");

            AffineTransform2 T8 = AffineTransform2.PointsAndVectorToPointsAndVector(p1, p2, p3 - p1, q1, q2, q3 - q1);

            Debug.Print("T8:" + T7 * (T8.InverseTransform()) + "\n should be identity\n"); //BROKEN
            Debug.Print("T8:" + T8 * p1 + "\n should be " + q1 + "\n");
            Debug.Print("T8:" + T8 * p2 + "\n should be " + q2 + "\n");
            Debug.Print("T8:" + T8 * p3 + "\n should be " + q3 + "\n");
        }