Some months ago I was trying to figure out a way to find the symmetry of a given point using a line as a mirror. I got busy doing other things and all my notes were lost like tears in the rain. I finally got time to complete the research.

I found three simple ways to do so. All three need an **origin** position and a **direction** (a unit vector that represents the **line** itself); it’s needless to say that the **origin** must be over the **line**.

### Vector Projection

Let’s label the *original* point as **A** and the symmetric partner as **P**.

Assuming we already have **A**, we want to find **B **using vector projections. In the figure below, **a** is **A**, **b** is the **direction** and the point opposite to the arrow’s tip is the **origin**. **P** will be analogous to **A**, but below **b**.

Using basic linear algebra:

Here’s the code that applies this principle:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public Vector2 FindMirror(Vector2 origin, Vector2 direction, Vector2 pointA) { float s = 0f; //Scalar projection float angle = Mathf.Atan2(pointA.y, pointA.x) - Mathf.Atan2(direction.y, direction.x); float lengthA = pointA.magnitude; s = lengthA * Mathf.Cos(angle); //We use the vector projection formula //An alternate way is by using the dot product, in which case // the following code of line substitutes the last three. //s = Vector3.Dot(pointA, direction); //The projection of point A over direction Vector2 projA = origin + direction * s; //The rejection of point A from direction Vector2 rejA = pointA - projA; //We want the opposite, as it's the rejection of point B from "direction" rejA *= -1; //We return the symmetric point of point A over direction return projA + rejA; } |

### Perpendicular Vectors

I wanted alternate ways to have the desired points with. For this approach, the initial point **A** is not needed as input, as both **A** and **B** will be generated at the same time.

In this case, the first step will be to create the projection vector of the future points. After that, the rejection vectors will be nothing more than the perpendicular vectors of such projection. The results are three vectors that will be used to create the desired points.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public Vector2[] GenerateMirrorPair(Vector2 origin, Vector2 direction) { Vector2[] points = new Vector2[2]; //This sets the max distance along the line where both points can be generated float maxDistance = 100f; //[This is just an example] //Length of the projection vector float distanceInLine = Random.Range(0f, maxDistance); //Length of the rejection vector float distanceFromLine = Random.Range(0f, maxDistance); Vector2 projection = direction; //The projection can go with or against the direction if (Random.Range(0f, 1f) <= 0.5f) { projection *= -1; } //Given the projection vector, we calculate the future rejection vector Vector2 rejection = Perpendicular(projection); rejection *= distanceFromLine; projection *= distanceInLine; projection += origin; points[0] = projection + rejection; points[1] = projection - rejection; return points; } public Vector2 Perpendicular(Vector2 p) { return new Vector2(p.y, -p.x); } |

This method provides control over the generation of points, via three variables (randomly set in the code above for the sake of the example). Those variables can be passed as arguments but are used as they are for explanatory purposes.

### Radial construction

There’s also a third solution. Given an origin point along the line, it’s possible to either create a pair of mirrored points by thinking of them as points over a circle. The hemispheres of the circle are dictated by the mirror line and the points reside in each of them.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
Vector2[] GenerateMirrorPairRadially(Vector2 origin, Vector2 direction) { Vector2[] points = new Vector2[2]; float x, y; //Distance away from the origin (i.e. the radius of the circle) float distance = Random.Range(0f, float.MaxValue); //Angle of the line used as a mirror float lineAngle = Mathf.Atan2(direction.y, direction.x); //Variation to be applied to the line angle // Max value is 180 degrees because the point over the // other hemisphere will be calculated using this one float deltaAngle = Random.Range(0f, 180f); //The deltaAngle in radians float deltaAngleR; //We generate the first point deltaAngleR = lineAngle + (deltaAngle * Mathf.Deg2Rad); //Basic position over a circle formula x = origin.x + Mathf.Cos(deltaAngleR) * distance; y = origin.y + Mathf.Sin(deltaAngleR) * distance; points[0] = new Vector2(x, y); //The mirror point's angular distance from the 360 degrees //is equal to the distance between the original point and 0 degrees deltaAngleR = lineAngle + ((360f - deltaAngle) * Mathf.Deg2Rad); x = origin.x + Mathf.Cos(deltaAngleR) * distance; y = origin.y + Mathf.Sin(deltaAngleR) * distance; points[1] = new Vector2(x, y); return points; } |

Although the code provided will generate both points, it’s possible to modify it and calculate the mirror of an existing point.

This solution also provides customizability via two variables: distance from the origin and angle.

I’m pretty sure there are more ways to get the symmetry of a point over a line, but I these 3 methods will perform the task.