Reverse a Generic Trimetric Projection [closed]
Trimetric Projected Tile
I am creating a grid using Trimetric Projection tiles, and have a way to go from a standard 2D grid's coordinates to a generic Trimetric tile coordinate using the following equations:
HeightRatio = 0.5; // Tiles are 128Hx256W, so height ratio is 1/2
HRI = 1/(2 * HeightRatio); // I don't really know why this works, but it's a modified Inverse of HeightRatio
Skew = 0.565f; // Offset of top point to the left of center (For isometric this is 0)
MSkew = 1-Skew
TrimetricToFlat(TX, TY): //This converts trimetric grid coordinates (starting at origin) to flat grid
x = ((TX* MSkew) - ((1+Skew) * TY)) * HRI;
y = (((1+Skew) * TX) + (TY* MSkew)) * 0.5f;
This all works as I want it, and given (0,0) to (N,N) trimetric grid positions I can generate a nice looking grid on a screen using the output x and y values. However, I want to be able to do the inverse and can't figure out how to do the system of equations for it.
The goal is to have a function similar like:
FlatToTrimetric(x, y):
TX = ??
TY = ??
Any help of guidance would be appriciated!
Let's make this look a bit more mathematical by using
-
$x$, $y$ for the projected (screen) coordinates
-
$X$, $Y$ (instead of
TX
,TY
) for the trimetric coordinates -
$S$ =
Skew
, $A$ =HeightRatio
, and $V$ =0.5
for vertical scaling. -
The horizontal scaling factor $H$ =
HRI
is actually $H = V / A$, i.e. vertical scaling factor divided by the height ratio. (It makes geometric sense, if you think about it.)
This way, we can write the formula you use as $$\left\lbrace ~ \begin{aligned} x &= \biggl( (1 - S) H \biggr) X + \biggl( - (1 + S) H \biggr) Y \\ y &= \biggl( (1 + S) V \biggr ) X + \biggl( (1 - S) V \biggr) Y \\ \end{aligned} \right. \tag{1}\label{BtV1}$$
In linear algebra terms, if we use vectors $\vec{P} = (X, Y)$ and $\vec{p} = (x, y)$, we can express the above using a simple matrix $\mathbf{M}$: $$\vec{p} = \mathbf{M} \vec{P}$$ where $$\mathbf{M} = \left[ \begin{matrix} H (1 - S) & - H (1 + S) \\ V (1 + S) & V (1 - S) \end{matrix} \right]$$
This means that The inverse is $$\vec{P} = \mathbf{M}^{-1} \vec{p}$$ where the inverse of matrix $\mathbf{M}$ is $$\mathbf{M}^{-1} = \left[ \begin{matrix} \frac{1 - S}{2 H (S^2 + 1)} & \frac{1 + S}{2 V (S^2 + 1)} \\ -\frac{1 + S}{2 H (S^2 + 1)} & \frac{1 - S}{2 V (S^2 + 1)} \\ \end{matrix} \right]$$
In Cartesian coordinates, that is equivalent to $$\left\lbrace ~ \begin{aligned} X &= \biggl(\frac{1 - S}{2 H (S^2 + 1)} \biggr) x + \biggl(\frac{1 + S}{2 V (S^2 + 1)}\biggr) y \\ Y &= \biggl(-\frac{1 + S}{2 H (S^2 + 1)} \biggr) x + \biggl(\frac{1 - S}{2 V (S^2 + 1)}\biggr) y \\ \end{aligned} \right. \tag{2}\label{BtV2}$$
Note how I grouped the terms in (larger) parentheses in $\eqref{BtV1}$ and $\eqref{BtV2}$, above. This is because you can do both mappings using the same code, say in pseudocode:
Function Map(x, y, Cxx, Cxy, Cyx, Cyy):
Let newX = x * Cxx + y * Cxy
Let newY = x * Cyx + y * Cyy
Return newX, newY
End Function
In the original mapping, the four constants are obviously
Cxx = (1 - S) * H
Cxy = -(1 + S) * H
Cyx = (1 + S) * V
Cyy = (1 - S) * V
and in the reverse mapping,
Cxx = (1 - S) / (2 * H * (S * S + 1))
Cxy = (1 + S) / (2 * V * (S * S + 1))
Cyx = -(1 + S) / (2 * H * (S * S + 1))
Cyy = (1 - S) / (2 * V * (S * S + 1))
These four (eight, if you count both ways) only change if H
, V
, or S
changes, so you can simply precalculate them into global variables, and use the pseudocode to very efficiently calculate either way, using just four multiplications and two additions per point.
The reason for how and why this works, exactly, is the matrix $\mathbf{M}$. In it, the left column is the new $x$ axis vector, and right column is the new $y$ axis vector. (The same applies to the inverse matrix, and all such matrices in both 2D and 3D, too.)
Trimetric projection is one of oblique projections, where the third coordinate ($z$ axis) is always directly up, and $x$ and $y$ axes are at different angles with respect to vertical. (I happen to use -1:2 and 2:1 quite often, i.e. Cxx = -0.5, Cxy = 2, Cyx = 2, Cyy = 0.5
, which you get with S=0.6, A=-1, V=5/17≃0.2941
.)