平移两个二维坐标系之间的坐标

时间:2016-03-30 21:28:37

标签: c# wpf matrix

我正在编写一个小图表编写程序作为个人项目。

每个点都应该在wpf画布上绘制,但是我无法将图形坐标系中的点转换为例如:x = -8 to 4 y=-4 to 4到画布的坐标系示例: x = 600 to 0 y = 400 to 0

我正在使用概述here的方法来预先计算变换方程式。

但是我遇到乘法v=M^-1*u的结果有问题。 我的预期结果是:

[0.2 ]
[0.0 ]
[-8.0]
[4.0 ]

但我得到的结果是:

[4.0   ]
[-4.0  ]
[0.01  ]
[-0.006]

我已经确认我的转换矩阵是正确的,当我手动计算时,我得到了预期的结果。

计算变换方程的方法:

 private void CalculateTransformationFunctions()
    {
        // Define the transformation matrix
        var transformationMatrix = new Matrix4x4
        {
            M11 = _destArea.XMin,
            M12 = _destArea.YMin,
            M13 = 1,
            M14 = 0,

            M21 = -_destArea.YMin,
            M22 = _destArea.XMin,
            M23 = 0,
            M24 = 1,

            M31 = _destArea.XMax,
            M32 = _destArea.YMax,
            M33 = 1,
            M34 = 0,

            M41 = -_destArea.YMax,
            M42 = _destArea.XMax,
            M43 = 0,
            M44 = 1
        };
        // Define the source vector 
        var srcVector = new Vector4
        {

            X = _srcArea.XMin,
            Y = _srcArea.YMax,
            Z = _srcArea.XMax,
            W = _srcArea.YMin
        };

        // Invert the transformationmatrix before the multiplication
        Matrix4x4 invertedTransformationMatrix;

        if(!Matrix4x4.Invert(transformationMatrix,out invertedTransformationMatrix))
            throw new Exception();

        // Returns the wrong value
        var transformResult = Vector4.Transform(srcVector, invertedTransformationMatrix); 


        float a = transformResult.X,
            b = transformResult.Y,
            c = transformResult.Z,
            d = transformResult.W;


        _xTransformationFunction = (x, y) => (a*x + b*y - b*d - a*c)/(a*a + b*b);
        _yTransformationFunction = (x, y) => (b*x - a*y - b*c + a*d)/(a*a + b*b);

    }

在其父类的构造函数中调用它。

我的问题:

我误解了Vector4.Transform()在这里的作用吗?还是我完全失明并且遗失了一些非常明显的东西?

全班同学:

using System;
using System.Numerics;
using System.Windows;
using System.Windows.Media;
using Grapher.Control.Grapher;

namespace Grapher.GraphingMath
{
    public class Translator
    {
        private GraphingArea _srcArea;
        private GraphingArea _destArea;

        public GraphingArea SourceArea
        {
            get
            {
                return _srcArea;
            }
            set
            {
                _srcArea = value;
               CalculateTransformationFunctions();
            }
        }

        public GraphingArea DestinationArea
        {
            get { return _destArea; }
            set
            {
                _destArea = value;
                CalculateTransformationFunctions();

            }
        }

        private Func<double, double, double> _xTransformationFunction;
        private Func<double, double, double> _yTransformationFunction;

        public Translator(GraphingArea sourceArea, GraphingArea destArea)
        {
            _destArea = destArea;
            _srcArea = sourceArea;
            CalculateTransformationFunctions();

        }

        public Point TranslatePoint(Point point)
        {
            var x = point.X;
            var y = point.Y;

            return new Point
            {
                X = _xTransformationFunction(x, y),
                Y = _yTransformationFunction(x, y)
            };

        }

        /*

               x1 y1 1 0
              -y1 x1 0 1
            M= x2 y2 1 0
              -y2 x2 0 1

            x1,y1 = dest_min
            x2,y2 = dest_max


        */

        private void CalculateTransformationFunctions()
        {
            // Define the transformation matrix
            var transformationMatrix = new Matrix4x4
            {
                M11 = _destArea.XMin,
                M12 = _destArea.YMin,
                M13 = 1,
                M14 = 0,

                M21 = -_destArea.YMin,
                M22 = _destArea.XMin,
                M23 = 0,
                M24 = 1,

                M31 = _destArea.XMax,
                M32 = _destArea.YMax,
                M33 = 1,
                M34 = 0,

                M41 = -_destArea.YMax,
                M42 = _destArea.XMax,
                M43 = 0,
                M44 = 1
            };
            // Define the source vector 
            var srcVector = new Vector4
            {

                X = _srcArea.XMin,
                Y = _srcArea.YMax,
                Z = _srcArea.XMax,
                W = _srcArea.YMin
            };

            // Invert the transformationmatrix before the multiplication
            Matrix4x4 invertedTransformationMatrix;

            if(!Matrix4x4.Invert(transformationMatrix,out invertedTransformationMatrix))
                throw new Exception();

            // Returns the wrong value
            var transformResult = Vector4.Transform(srcVector, invertedTransformationMatrix); 


            float a = transformResult.X,
                b = transformResult.Y,
                c = transformResult.Z,
                d = transformResult.W;


            _xTransformationFunction = (x, y) => (a*x + b*y - b*d - a*c)/(a*a + b*b);
            _yTransformationFunction = (x, y) => (b*x - a*y - b*c + a*d)/(a*a + b*b);

        }
    }
}

对于图形区域struct:

using System;

namespace Grapher.Control.Grapher
{
    public struct GraphingArea
    {
        public float XMin { get; set; }

        public float YMin { get; set; }

        public float XMax { get; set; }

        public float YMax { get; set; }

        public float Width => Math.Abs(XMax - XMin);
        public float Height => Math.Abs(YMax - YMin);
    }
}

在我的main方法中,我像这样调用Translator类:

        Point testPoint = new Point {X = 0, Y = 0};


        var srcArea = new GraphingArea
        {
            XMax = 4,
            XMin = -8,
            YMax = 4,
            YMin = -4
        };

        var destArea = new GraphingArea
        {
            XMax = 600,
            XMin = 0,
            YMax = 400,
            YMin = 0
        };

        var translator = new Translator(srcArea, destArea);
        var translatedPoint = translator.TranslatePoint(testPoint);

修改

结束了我自己的矩阵乘法方法。我必须误解Vector4.Transform()做什么......

代码在这里,对任何感兴趣的人:

using System.Numerics;

namespace Grapher.GraphingMath.MatrixAndVectorMath
{
    public static class Matrix4x4Multiply
    {
        public static Vector4 Vector4Multiply(Matrix4x4 matrix, Vector4 vector)
        {
            var mat = new float[4, 4]
            {
                {matrix.M11, matrix.M12, matrix.M13, matrix.M14},
                {matrix.M21, matrix.M22, matrix.M23, matrix.M24},
                {matrix.M31, matrix.M32, matrix.M33, matrix.M34},
                {matrix.M41, matrix.M42, matrix.M43, matrix.M44}
            }; // We'll just wrap the matrix in a float so we can index it.

            var vec = new float[4] {vector.X, vector.Y, vector.Z, vector.W}; // And the same with the vector

            var result = new float[4] {0, 0, 0, 0};

            for (var row = 0; row < mat.GetLength(0); row++)
            {
                for (var col = 0; col < mat.GetLength(1); col++)
                {
                    result[row] += mat[row, col]*vec[col];
                }
            }

            return new Vector4
            {
                X = result[0],
                Y = result[1],
                Z = result[2],
                W = result[3]
            };
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我不知道这是否会有所帮助,但我在其中一个项目中按照这些方针做了一些事情。我不会使用矩阵,所以它可能不是你想要的。我只是存储图形的坐标范围和容器(画布)的宽度和高度。然后我提供了两个扩展函数:

public static System.Windows.Point ConvertToScreen(this System.Windows.Point point, CartesianExtents2D extents, double containerWidth, double containerHeight)
{
    var x = (point.X - extents.XMinimum) * containerWidth / (extents.XMaximum - extents.XMinimum);
    var y = (extents.YMaximum - point.Y) * containerHeight / (extents.YMaximum - extents.YMinimum);
    return new System.Windows.Point(x, y);

}

public static System.Windows.Point ConvertToReal(this System.Windows.Point point, CartesianExtents2D extents, double containerWidth, double containerHeight, )
{
    var x = extents.XMinimum + (point.X * (extents.XMaximum - extents.XMinimum)) / containerWidth;
    var y = extents.YMaximum - (point.Y * (extents.YMaximum - extents.YMinimum)) / containerHeight;
    return new System.Windows.Point(x, y);
}

致电:

Point p = new Point();
p.ConvertToReal(...);

我希望CartesianExtents2D的内容很明显 - 只需要x和y的最小值和最大值