2017-01-07 38 views
0

给定任意反射线如何用矩阵反射一组点?我曾尝试以下,但我不能得到它的工作:在反射线上用矩阵反射2d点

  1. 翻译系统,以使reflectionline的P1是在 起源

  2. 旋转系统,以便reflectionline平行于ÿ

  3. 执行Y轴反射

  4. 撤消旋转

  5. 撤消转换

荫试图写在C#中要做到这一点,我的方法基本上我给它2点的直线和我得到的矩阵回来。

+0

似乎我写下的步骤很好,但是我在代码中犯了一些错误。我解决了这个问题,现在它的工作正常 – Barsonax

回答

1

there is a formula for reflecting about any line through the origin以来不需要旋转。让(a,b)(c,d)任意反射线上的两点。假设您想要反映的是(x,y)

  1. 转换坐标以便(a,b)成为原点。然后(x,y)变成(x-a,y-b)。这一步只是矢量减法。
  2. 反映。这是你需要矩阵的地方。您将通过步骤1中的转换矢量乘以矩阵。您的结果将是另一个矢量(2×1矩阵)。
  3. 将坐标转换回原始系统。这是第一步,即倒数,这是向量加法,仅仅撤销步骤1中的向量减法在这一步中你只是将(a,b)到你的结果从第2步

的步骤矩阵2是:

H(θ) = [cos(2θ) sin(2θ)] 
     [sin(2θ) -cos(2θ)] 

在矩阵中,θ是(平移的)反射线与正x轴所成的角度。只要ac不相等,则可以通过评估发现θ:

θ = arctangent((d-b)/(c-a)) 

您将得到严格-π/2π/2之间的值。如果a = c,也就是说,如果反射线是垂直的,那么就拿θ = π/2。虽然如果反射线是垂直的(或水平的,在这种情况下θ = 0),那么您可以使用众所周知的反射矩阵来反射y轴或x轴。

这几乎奠定了查找和使用矩阵的整个过程。这听起来像你所要求的是找到反射矩阵。我不知道C#以及足够用了它的答案,但这里是伪代码:

// (a,b) and (c,d) are any two distinct points on the reflection line 
getMatrix(double a, double b, double c, double d) 
    double x11, x12, x21, x22; // Elements of the reflection matrix 

    if a == c // If the reflection line is vertical 
     x11 = -1; x12 = 0; x21 = 0; x22 = 1; 
    else if b == d // If the reflection line is horizontal 
     x11 = 1; x12 = 0; x21 = 0; x22 = -1; 
    else 
     double θ = arctangent((d-b)/(c-a)); 

     x11 = cos(2 * θ); 
     x12 = sin(2 * θ); 
     x21 = x12; // sin(2 * θ) again 
     x22 = -x11; // -cos(2 * θ) 
    end if 

    return Matrix(x11, x12, x21, x22); 
    /* The above line returns a matrix with the following entries: 
      [ x11 x12 ] 
      [ x21 x22 ] 
    */ 

而这里的例子伪代码使用上述伪代码:

// Reflect (x,y) over the line given by the points (a,b) and (c,d) 
reflectPoint(double x, double y, double a, double b, double c, double d) 
    Matrix reflector = getMatrix(a, b, c, d); 
    Vector v1 = new Vector(x-a, x-b); // This is Step 1 
    Vector v2 = new Vector(a, b);  // This is so we can do Step 3 later 

    return reflector * v1 + v2; // v1 already has Step 1 done 
           // reflector * v1 is Step 2 
           // + v2 is Step 3 

有这样做的更有效的方法上面(例如检查给定点(a,b)(c,d)之一是否已经是原点),但上述内容仍然有效。

+0

这也是我的想法。不同的是,在你的情况下,事先预先计算更多的东西,所以这将会执行更多。事实上,您可以事先预先计算所有步骤,而不是将矩阵相乘,因此您只需填写变量。如果遇到性能问题,我会牢记这一想法。 – Barsonax

+0

@Barsonax如果你担心表现,可能会更好地做到这一点没有矩阵,只是使用垂直度和距离公式。我还没有制定出所有的细节,但我认为哪种方式更好可能取决于您需要反映的点数。 – tilper

+0

使用矩阵只是一些增加和乘法。如果我真的想掐掉它的每一点性能,我会事先预先计算并消除任何多余的变量。关于矩阵的好处是,一旦它使您可以重复使用它的点数,你喜欢。 – Barsonax

0

固定我在这里所作的错字后是我的代码是什么样子:

public class TranslateTransformation2D : MatrixTransformation2DBase 
{ 
    public TranslateTransformation2D(Vector2D translation) 
    { 
     TransformationMatrix = Matrix3x3.CreateTranslationMatrix(translation.X, translation.Y); 
    } 

    public TranslateTransformation2D(float x, float y) 
    { 
     TransformationMatrix = Matrix3x3.CreateTranslationMatrix(x, y); 
    } 
} 

这是MATRIX3X3类的样子:只使用抽象矩阵

private Transformer2D Reflect(Vector2D p1, Vector2D p2) 
{ 
     var translationMatrix = new TranslateTransformation2D(new Vector2D(0, 0) - p1); 
     var inverseTranslationMatrix = new TranslateTransformation2D(p1); 
     var translatedP2 = translationMatrix.Transform(p2); //What p2 would be if p1 of the line was translated to the origin. 
     var angleWithYaxis = new Vector2D(0, 1).AngleBetweenTwoVectors(translatedP2); 
     var rotationMatrix = new RotationTransformation2D(-angleWithYaxis * RhinoMath.Deg2Rad); 
     var inverseRotationMatrix = new RotationTransformation2D(angleWithYaxis * RhinoMath.Deg2Rad); 
     var reflectionMatrix = new ScaleTransformation2D(-1, 1); 
     return new Transformer2D(translationMatrix, rotationMatrix, reflectionMatrix, inverseRotationMatrix, inverseTranslationMatrix); 
} 

的类的IAM:

public class Matrix3x3 : Matrix 
{ 
    public Matrix3x3(double m11, double m12, double m13, 
        double m21, double m22, double m23, 
        double m31, double m32, double m33) 
    { 
     Rows = 3; 
     Cols = 3; 
     Mat = new double[Rows * Cols]; 
     Mat[0] = m11; 
     Mat[1] = m12; 
     Mat[2] = m13; 

     Mat[3] = m21; 
     Mat[4] = m22; 
     Mat[5] = m23; 

     Mat[6] = m31; 
     Mat[7] = m32; 
     Mat[8] = m33; 
    } 

    public static Matrix3x3 CreateTranslationMatrix(double x, double y) 
    { 
     return new Matrix3x3(1, 0, x, 
          0, 1, y, 
          0, 0, 1); 
    } 

    public static Matrix3x3 CreateScaleMatrix(double x, double y) 
    { 
     return new Matrix3x3(x, 0, 0, 
          0, y, 0, 
          0, 0, 1); 
    } 

    public static Matrix3x3 CreateIdentityMatrix() 
    { 
     return new Matrix3x3(1, 0, 0, 
          0, 1, 0, 
          0, 0, 1); 
    } 

    public static Matrix3x3 CreateRotationMatrix(double radians) 
    { 
     var cos = Math.Cos(radians); 
     var sin = Math.Sin(radians); 

     return new Matrix3x3(cos, -sin, 0, 
          sin, cos, 0, 
          0, 0, 1); 

    } 

Transformer2D类在这里是特殊的,因为它只是简单地组合ES全部转换成一个矩阵,所以我们只需要将此矩阵,让我们的所有转换:

public class Transformer2D : MatrixTransformation2DBase 
{ 
    public Transformer2D(params IMatrixTransformation2D[] transformations) 
    { 
     for (int i = transformations.Length - 1; i >= 0; i--) 
     { 
      var matrixTransformation2D = transformations[i]; 
      if (TransformationMatrix != null) 
      { 
       TransformationMatrix = TransformationMatrix * matrixTransformation2D.TransformationMatrix; 
      } 
      else 
      { 
       TransformationMatrix = matrixTransformation2D.TransformationMatrix; 
      } 
     } 
    } 
} 

的MatrixTransformation2DBase类

public abstract class MatrixTransformation2DBase : IMatrixTransformation2D 
{ 
    public Matrix3x3 TransformationMatrix { get; protected set; } 

    public Vector2D Transform(Vector2D vector2Din) 
    { 
     return vector2Din*TransformationMatrix; 
    } 
} 

我大概可以让它更快一点在一些地方,但想法是我不必再担心矩阵本身,除非我想要一些新的转换类型。

对于那些想知道我在内部它这一个使用什么矩阵类:https://github.com/darkdragon-001/LightweightMatrixCSharp

我所做的就是写一些解决这个conveinence。