Reputation: 310
Given a arbitrary reflection line how can you reflect a set of points with matrices? I have tried the following but i cannot get it to work:
Translate the system so that P1 of the reflectionline is in the origin
Rotate the system so that the reflectionline is parallel to the Y
axis
Perform a Y axis reflection
Undo the rotation
Iam trying to write a method to do this for me in C# basically i give it the 2 points of the line and i get the matrix back.
Upvotes: 0
Views: 1705
Reputation: 310
After fixing the typo i made here is what my code looks like:
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);
}
The classes iam using just abstract the matrices:
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);
}
}
This is how the Matrix3x3 class looks like:
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);
}
The Transformer2D class is special here since it simply combines all the transformations into one matrix so we only have to apply this matrix to get all our transformations:
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;
}
}
}
}
The MatrixTransformation2DBase class
public abstract class MatrixTransformation2DBase : IMatrixTransformation2D
{
public Matrix3x3 TransformationMatrix { get; protected set; }
public Vector2D Transform(Vector2D vector2Din)
{
return vector2Din*TransformationMatrix;
}
}
I could probably make it faster in a few places but the idea is that i dont have to worry anymore about the matrices themselves unless i want some new type of transformation.
For those wondering what matrix class i use internally its this one: https://github.com/darkdragon-001/LightweightMatrixCSharp
All i did was write some conveinence around this.
Upvotes: 0
Reputation:
No rotations are needed since there is a formula for reflecting about any line through the origin. Let (a,b)
and (c,d)
be any two points on the reflection line. Let's say the point you want to reflect is (x,y)
.
(a,b)
becomes the origin. Then (x,y)
becomes (x-a,y-b)
. This step is just vector subtraction.(a,b)
to your result from step 2.The matrix for step 2 is:
H(θ) = [cos(2θ) sin(2θ)]
[sin(2θ) -cos(2θ)]
In the matrix, θ is the angle that the (translated) reflection line makes with the positive x-axis. As long as a
and c
are not equal, you can find θ by evaluating:
θ = arctangent( (d-b) / (c-a) )
You will get a value strictly between -π/2
and π/2
. If a = c
, that is, if the reflection line is vertical, then just take θ = π/2
. Although if the reflection line is vertical (or horizontal, in which case θ = 0
) then you can just use well-known reflection matrices for reflecting over the y- or x-axis.
This pretty much lays out the whole process of finding and using the matrix. It sounds like all you're asking for is finding the reflection matrix. I don't know C# well enough to use it in an answer, but here's pseudocode:
// (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 ]
*/
And here's example pseudocode for using the above pseudocode:
// 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
There are more efficient ways of doing the above (like checking if one of the given points (a,b)
and (c,d)
is already the origin, for example) but the above should still work.
Upvotes: 2