Danie Clawson
Danie Clawson

Reputation: 183

How do I convert pixel coordinates to isometric grid coordinates?

I didn't have too much trouble figuring out where to place my tiles or finding the tile corners, but I can't figure out the math/formula for determining what grid unit the pixel I'm hovering over belongs to. My grid runs like this:

        y0,x0|y0,x1|y0,x2
     y1,x0|y1,x1|y1,x2
  y2,x0|y2,x1|y2,x2

With y0,x0 being the top/back and centered against the top edge of the canvas. Tiles are twice as wide as long as usual. I have gotten the offset code to work, so that my mouse pixel coordinate offsets are the same as my tiles, but I'm stumped.

Edit: Sorry for the confusing question. All-night code session fatigue.

I have this function (simplified here):

getTilePixelCoord(x,y)
{
    p.x = S-yH+xH;
    p.y = yM+xM;
    return p;
}

That I use to place my tiles. S is the origin point, where 0y,0x is always placed, H is tile pixel height, and M is H/2. What I need is the opposite of this, a getPixelTileCoord(pixelx,pixely); for getting which tile I'm hovering on.

Upvotes: 1

Views: 1793

Answers (1)

Steven Liao
Steven Liao

Reputation: 3787

Initial Observations

The isometric tile grid just a regular rectangular grid with the x-coordinate shifted, depending on how many rows there are.

Rectangular Grid (y,x)

             v length (L)
          +_____+xxxxx+xxxxx+
          x     x     x     x
No offset>+xxxxx+xxxxx+xxxxx+
          x     x     x     x
          +xx|xx+xxxxx+xxxxx+
          x  |  x     x     x
          +xx|xx+xxxxx+xxxxx+
             ^ height (H)

+: corners

Each tile's length edge is Lpx and height perpendicular to that edge is Hpx. The isometric pixel offset per row will be Opx.

Isometric Grid (y,x)

                  V length (L) is the same as above
height     ......+_____+xxxxx+xxxxx+
dependent >_____x 0,0 x     x     x
offset     ....+xxxxx+xxxxx+xxxxx+
(O)        ...x     x     x 1,2 x
           ..+x|xxx+xxxxx+xxxxx+
           .x  |  x     x     x
           +xxx|x+xxxxx+xxxxx+
               ^ height (H) is the same as above

+: corners

Notation

  • t(ty,tx) refers to the tile vertically located at ty and horizontally located at tx
  • p(i,j) refers to the pixel location (in pixels)
  • MAX_Y refers to the number of tile rows

(All locations are always listed with the vertical component first.)

Examples

Ex. 1

If you count, you'll notice that the corners of t(0,0) are located at the following pixel locations:

  • p(0, 3O): top left
  • p(H, 2O): bottom left
  • p(0, 3O+L): top right
  • p(H, 2O+L): bottom right

Each of these four points are corners of other tiles as well.

Ex. 2

We can see t(1,2) as another example. Their corners are at the following pixel locations:

  • p(H, 2O+2L): top left
  • p(2H, O+2L): bottom left
  • p(H, 2O+3L): top right
  • p(2H, O+3L): bottom right

General Case

For each unit increase in tx (from t(ty,tx) to t(ty,tx+1)), the horizontal pixel location of the corners changes by L px.

For each unit increase in ty (from t(ty,tx) to t(ty+1,tx)), the horizontal pixel location of the corners changes by -O px and the vertical pixel location of the corners changes by H px.

To generalize, the corners of tile t(ty,tx) (where the number of rows is Y_MAX, so for our example, Y_MAX = 3) are at the following pixel locations:

p(    ty*H,   (Y_MAX-ty)*O +     tx*L) - top left
p((ty+1)*H, (Y_MAX-ty-1)*O +     tx*L) - bottom left
p(    ty*H,   (Y_MAX-ty)*O + (tx+1)*L) - top right
p((ty+1)*H, (Y_MAX-ty-1)*O + (tx+1)*L) - bottom right

You can plug in the above examples to show that these are the correct locations.

Pixel To Tile

Vertical Location

For a tile t(ty,tx) and p(i,j), ty*H <= i < (ty+1)*H.

ty*H <= i   < (ty+1)*H
ty   <= i/H < ty+1
ty = floor(i/H)

Thus, ty = floor(i/H).

Horizontal Location

The horizontal location is a little more complex because the offset, and thus the horizontal location, depends on the vertical location of the pixel. We can see that the offset starts at O*Y_MAX px at the top and decreases linearly to 0px at the bottom.

At the top of tile t(ty,tx) and pixel p(i,j), (Y_MAX-ty)*O + tx*L <= j < (Y_MAX-ty)*O + (tx+1)*L.

At the bottom of tile t(ty,tx) and pixel p(i,j), (Y_MAX-ty-1)*O + tx*L <= j < (Y_MAX-ty-1)*O + (tx+1)*L.

The difference between the two is linear, totaling O px.

To find out far we are down the tile, we can use frac(i/H), the fractional part of i/H. For example, at p(80,0), if each tile has a height H=30, we would be frac(80/30) = 20 px relative to the top of the tile; in other words, two-thirds of the way down. We see from above that ty is floor(i/H) is actually the integer part of i/H. Thus, ty+frac(i/H) = i/H.


Thus, for tile t(ty,tx) and pixel p(i,j), (Y_MAX-i/H)*O + tx*L < j < (Y_MAX-i/H)*O + (tx+1)*L

(Y_MAX-i/H)*O + tx*L <= j                     < (Y_MAX-i/H)*O + (tx+1)*L
tx*L                 <= j-((Y_MAX-i/H)*O)     < (tx+1)*L
tx                   <= (j-((Y_MAX-i/H)*O))/L < tx+1
tx = floor((j-((Y_MAX-i/H)*O))/L)

Thus, tx = floor((j-((Y_MAX-i/H)*O))/L).

Solution

For any point p(i,j), the tile t(ty,tx) is at t(floor(i/H),floor((j-((Y_MAX-i/H)*O))/L)).

Your Specific Case

For your purposes, L = 2H and O = H are likely parameters; taking the above solution and replacing O and L would reduce the result down to one dependency H.

Upvotes: 1

Related Questions