Inverting an isometric projection?

198 Views Asked by At

I'm trying to invert a function that takes points on a 2-d plane to an isometric projection of that plane. This function is encoded as follows (as part of the Isomer library):

Isomer.prototype._translatePoint = function(point) {
  /**
   * X rides along the angle extended from the origin
   * Y rides perpendicular to this angle (in isometric view: PI - angle)
   * Z affects the y coordinate of the drawn point
   */
  var xMap = new Point(point.x * this.transformation[0][0],
                       point.x * this.transformation[0][1]);

  var yMap = new Point(point.y * this.transformation[1][0],
                       point.y * this.transformation[1][1]);

  var x = this.originX + xMap.x + yMap.x;
  var y = this.originY - xMap.y - yMap.y - (point.z * this.scale);
  return new Point(x, y);
};

On my reading, this is basically a set of simultaneous equations (ignoring point.z since I would like to map to the projected plane z=0):

x = origin.x + xmap.x + ymap.x
y = origin.y - xmap.y - ymap.y

Substituting in the values for xmap and ymap we have

x = o.x + (point.x * tx[0][0]) + (point.y * tx[1][0])
y = o.y - (point.x * tx[0][1]) - (point.y * tx[1][1])

(where o is the origin and tx is the transformation matrix.)

We can encode this in single-letter variables as follows

x = c + ae + bg
y = d - af - bh

where

  a = point.x
  b = point.y
  c = origin.x
  d = origin.y
  e = tx[0][0]
  f = tx[0][1]
  g = tx[1][0]
  h = tx[1][1]

To invert the function, I would think we want to solve this set of equations for a and b. Wolfram Alpha gives me the following solution:

a = ch + dg - gy - hx / fg - eh
b = -cf - de + ey + fx / fg - eh

And this actually looks reasonable. The common divisor term looks to be the determinant of the transformation matrix. For what it's worth here is the code relating to the construction of this matrix:

this.transformation = [
    [
      this.scale * Math.cos(this.angle),
      this.scale * Math.sin(this.angle)
    ],
    [
      this.scale * Math.cos(Math.PI - this.angle),
      this.scale * Math.sin(Math.PI - this.angle)
    ]
  ];

The transformation matrix is precalculated and always seems to take on the values

[[60.62177826491071,34.99999999999999],
 [-60.62177826491071,34.99999999999999]].