# 2D transform matrix to map 4 source points to 4 destination points

**URL:** <https://discourse.threejs.org/t/2d-transform-matrix-to-map-4-source-points-to-4-destination-points/68539>\
**Category:** Questions\
**Tags:** transform-matrix, transform, math\
**Created:** [July 24, 2024, 7:11pm UTC](https://discourse.threejs.org/t/2d-transform-matrix-to-map-4-source-points-to-4-destination-points/68539 "2024-07-24T19:11:33Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![myro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/myro/32/44083_2.png) [@myro](https://discourse.threejs.org/u/myro)\
**Post date:** [July 24, 2024, 7:11pm UTC](https://discourse.threejs.org/t/2d-transform-matrix-to-map-4-source-points-to-4-destination-points/68539/1 "2024-07-24T19:11:34Z")

</div>

Hi all,  
I’m trying to make a 2D perspective transform matrix that maps 4 source points to 4 destination points.

I think I’m doing something backward but I can’t pinpoint my error.  
I’m using mathjs for solving the system. here is my situation: I have followed this topic to set up the equations [math - Perspective projection, 4 points - Stack Overflow](https://stackoverflow.com/questions/8925569/perspective-projection-4-points)  
and have come up with the following function.

```javascript
export function getTransformMatrix(
  s1: THREE.Vector2, s2: THREE.Vector2, s3: THREE.Vector2, s4: THREE.Vector2,
  d1: THREE.Vector2, d2: THREE.Vector2, d3: THREE.Vector2, d4: THREE.Vector2,
) {

  const A = [
    [s1.x, s1.y, 1, 0, 0, 0, -d1.x * s1.x, -d1.x * s1.y],
    [0, 0, 0, s1.x, s1.y, 1, -d1.y * s1.x, -d1.y * s1.y],
    [s2.x, s2.y, 1, 0, 0, 0, -d2.x * s2.x, -d2.x * s2.y],
    [0, 0, 0, s2.x, s2.y, 1, -d2.y * s2.x, -d2.y * s2.y],
    [s3.x, s3.y, 1, 0, 0, 0, -d3.x * s3.x, -d3.x * s3.y],
    [0, 0, 0, s3.x, s3.y, 1, -d3.y * s3.x, -d3.y * s3.y],
    [s4.x, s4.y, 1, 0, 0, 0, -d4.x * s4.x, -d4.x * s4.y],
    [0, 0, 0, s4.x, s4.y, 1, -d4.y * s4.x, -d4.y * s4.y],
  ];

  const B = [
    d1.x, d1.y,
    d2.x, d2.y,
    d3.x, d3.y,
    d4.x, d4.y
  ];

  const A_matrix = mathjs.matrix(A);
  const B_matrix = mathjs.matrix(B);

  // A = H * B
  // H = A^-1 * B
  const A_inv = (mathjs.inv(A_matrix));
  const H_matrix = (mathjs.multiply(A_inv, B_matrix));
  const H = H_matrix.valueOf().flat();

  // Re-order the 3x3 matrix for Three.js
  const res = new THREE.Matrix3();
  res.set(
    H[0], H[3], H[6],
    H[1], H[4], H[7],
    H[2], H[5], 0
  );
  return res;
}

```

the problem is that when I apply the transform, it is wrong.

```javascript
function applyTransform1(matrix: THREE.Matrix3, vertices :THREE.Vector2[]) {
    vertices.forEach(vertice => {
      vertice.applyMatrix3(matrix);
    })
  }

```

So I tried to make my own version applyTransform2 to try and understand what is hapenning inside. Here it is :

```javascript
  function applyTransform2(matrix: THREE.Matrix3, vertices: THREE.Vector2) {    
    vertices.forEach(vertex => {
      const x = vertex.x;
      const y = vertex.y;
      const w = matrix.elements[6] * x + matrix.elements[7] * y + 1; // Homogeneous coordinate
      const newX = (matrix.elements[0] * x + matrix.elements[1] * y + matrix.elements[2]) / w;
      const newY = (matrix.elements[3] * x + matrix.elements[4] * y + matrix.elements[5]) / w;

      vertex.setX(newX)
      vertex.setY(newY)
    });
  }

```

applyTransform2 makes the correct transform with the matrices out of getTransformMatrix but if I use it with some standard THREE js transform matrix such as `new THREE.Matrix3().translate(...).matrix.scale(...)` it makes a wrong transform.

So in the end my functions work well together but obviously there is something wrong since vertice.applyMatrix3(M) doesn’t give the expected result.

Here is an example of result:

```javascript
const s1 = new THREE.Vector2(0, 0);
const s2 = new THREE.Vector2(80, 0);
const s3 = new THREE.Vector2(0, 80);
const s4 = new THREE.Vector2(80, 80);
let d1 = new THREE.Vector2(-200, 100)
let d2 = new THREE.Vector2(0, 200)
let d3 = new THREE.Vector2(0, 0)
let d4 = new THREE.Vector2(30, 100)

```

expected result (made using applyTransform2): red source, blue destination  
 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/d/3/d3bf73741754f40362d85dc5280f89d592ad2e77.png)

wrong result (using applyTransform1): red source, blue destination  
 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/6/9/6954d5197e561ac1057f7eae569e472b038524eb.png)

I guess I am solving for a right hand multiplication instead of left hand multiplication or I am missing a transpose somewhere… I’ve been at it for a few days but I feel like I’m running in circles now.  
Help and pointers welcome 🙂

---

<div class="post-metadata">

**Author:** ![myro](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/myro/32/44083_2.png) [@myro](https://discourse.threejs.org/u/myro)\
**Post date:** [July 25, 2024, 2:55am UTC](https://discourse.threejs.org/t/2d-transform-matrix-to-map-4-source-points-to-4-destination-points/68539/2 "2024-07-25T02:55:10Z")

</div>

So it seems I was missing some transpose but more importantly, I went to check the source code for Vector2.applyMatrix and there is no handling of the homogenous coordinate!  
which is why the transformation is stuck in a paralellogram and not a correct perspective transform…

> <https://github.com/mrdoob/three.js/blob/e241101b5f88102ce31ce87ed5f3d8ea2fbad057/src/math/Vector2.js#L209>
