2D planar coordinate system conversion

Posted on Tue, Mar 26, 2024 Rust

The 2D planar coordinate system conversion I use at work, the demo code is implemented in Rust, and other code should be implemented in roughly the same way. πŸ€”

If you are using the standard right-handed Cartesian coordinate system you may need to transform the y-axis appropriately.

Rotation

clockwise

A=[cos(ΞΈ)sin(ΞΈ)0sin(ΞΈ)cos(ΞΈ)0001]A= \begin{gathered} \begin{bmatrix} cos(\theta) & sin(\theta) & 0 \\ sin(\theta) & cos(\theta) & 0 \\ 0 & 0 & 1 \end{bmatrix} \end{gathered}

counterclockwise

A=[cos(ΞΈ)sin(βˆ’ΞΈ)0sin(ΞΈ)cos(ΞΈ)0001]A= \begin{gathered} \begin{bmatrix} cos(\theta) & sin(-\theta) & 0 \\ sin(\theta) & cos(\theta) & 0 \\ 0 & 0 & 1 \end{bmatrix} \end{gathered}

matrix equation

[x1y11]=Aβ‹…[xy1]\begin{gathered} \begin{bmatrix} x_1 \\ y_1 \\ 1 \end{bmatrix} \end{gathered} = A \cdot \begin{gathered} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} \end{gathered}

Rust demo code

use std::f64::consts::PI;
use ndarray::arr2;

fn rotation() {
    // 2D point rotation 45 degrees
    let theta = 45.0 * (PI / 180.0);

    // Convert Ordinary Coordinate (x, y) to Homogeneous Coordinate (x, y, 1)
    let point = arr2(&[[0.0], [10.0], [1.0]]);

    // 2D rotated matrices
    let a = arr2(&[
        [f64::cos(theta), f64::sin(theta), 0.0],
        [f64::sin(theta), f64::cos(theta), 0.0],
        [0.0, 0.0, 1.0],
    ]);

    let new_point = a.dot(&point);

    println!("{}", &new_point);
}
    Finished dev [unoptimized + debuginfo] target(s) in 0.11s
     Running `target/debug/two_d_cover`
[[7.071067811865475],
 [7.0710678118654755],
 [1]]

Rotate a point around another point

  1. Translate the specified point to the origin to obtain the translation matrix T1T_1
  2. Perform a rotation to obtain the rotation matrix RR
  3. Translate to the specified point to get the translation matrix T2T_2.

the point (x0,y0)(x_0, y_0) is rotated around the point (xs,ys)(x_s, y_s)

T1=[100010βˆ’xsβˆ’ys1]T_1= \begin{gathered} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ -x_s & -y_s & 1 \end{bmatrix} \end{gathered}

R=[cos(ΞΈ)βˆ’sin(ΞΈ)0sin(ΞΈ)cos(ΞΈ)0001]R= \begin{gathered} \begin{bmatrix} cos(\theta) & -sin(\theta) & 0 \\ sin(\theta) & cos(\theta) & 0 \\ 0 & 0 & 1 \end{bmatrix} \end{gathered}

T2=[100010xsys1]T_2= \begin{gathered} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ x_s & y_s & 1 \end{bmatrix} \end{gathered}

[x1y11]=[x0y01]β‹…T1β‹…Rβ‹…T2\begin{gathered} \begin{bmatrix} x_1 \\ y_1 \\ 1 \end{bmatrix} \end{gathered} = \begin{gathered} \begin{bmatrix} x_0 \\ y_0 \\ 1 \end{bmatrix} \end{gathered} \cdot T_1 \cdot R \cdot T_2

Translation

[x1y11]=[100010dxdy1]β‹…[x0y01]\begin{gathered} \begin{bmatrix} x_1 \\ y_1 \\ 1 \end{bmatrix} \end{gathered} = \begin{gathered} \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ dx & dy & 1 \end{bmatrix} \end{gathered} \cdot \begin{gathered} \begin{bmatrix} x_0 \\ y_0 \\ 1 \end{bmatrix} \end{gathered}

Zoom

[x1y11]=[sx000sy0001]β‹…[x0y01]\begin{gathered} \begin{bmatrix} x_1 \\ y_1 \\ 1 \end{bmatrix} \end{gathered} = \begin{gathered} \begin{bmatrix} s_x & 0 & 0 \\ 0 & s_y & 0 \\ 0 & 0 & 1 \end{bmatrix} \end{gathered} \cdot \begin{gathered} \begin{bmatrix} x_0 \\ y_0 \\ 1 \end{bmatrix} \end{gathered}

Rust demo code

use ndarray::arr2;

fn main() {
    zoom(10.0, 10.0, 1.2, 1.2);
}

fn zoom(x_0: f64, y_0: f64, s_x: f64, s_y: f64) {
    let point = arr2(&[[x_0], [y_0], [1.0]]);

    let s = arr2(&[
        [s_x, 0.0, 0.0],
        [0.0, s_y, 0.0],
        [0.0, 0.0, 1.0],
    ]);

    let new_point = s.dot(&point);
    println!("{}", &new_point);
}
    Finished dev [unoptimized + debuginfo] target(s) in 0.34s
     Running `target/debug/two_d_cover`
[[12],
 [12],
 [1]]