Find column, row on 2D isometric grid from x,y scr

2019-05-15 22:43发布

问题:

I'm trying to find the row, column in a 2d isometric grid of a screen space point (x, y)

Now I pretty much know what I need to do which is find the length of the vectors in red in the pictures above and then compare it to the length of the vector that represent the bounds of the grid (which is represented by the black vectors)

Now I asked for help over at mathematics stack exchange to get the equation for figuring out what the parallel vectors are of a point x,y compared to the black boundary vectors. Link here Length of Perpendicular/Parallel Vectors

but im having trouble converting this to a function

Ideally i need enough of a function to get the length of both red vectors from three sets of points, the x,y of the end of the 2 black vectors and the point at the end of the red vectors.

Any language is fine but ideally javascript

回答1:

What you need is a base transformation:

Suppose the coordinates of the first black vector are (x1, x2) and the coordinates of the second vector are (y1, y2).

Therefore, finding the red vectors that get at a point (z1, z2) is equivalent to solving the following linear system:

x1*r1 + y1*r2 = z1
x2*r1 + y2*r2 = z2

or in matrix form:

   A      x  =  b

/x1 y1\ |r1| = |z1|
\x2 y2/ |r2|   |z2|

          x = inverse(A)*b

For example, lets have the black vector be (2, 1) and (2, -1). The corresponding matrix A will be

2 2
1 -1

and its inverse will be

1/4 1/2
1/4 -1/2

So a point (x, y) in the original coordinates will be able to be represened in the alternate base, bia the following formula:

(x, y) = (1/4 * x + 1/2 * y)*(2,1)  + (1/4 * x -1/2 * y)*(2, -1)


回答2:

What exactly is the point of doing it like this? Any isometric grid you display usually contains cells of equal size, so you can skip all the vector math and simply do something like:

var xStep = 50,
    yStep = 30, // roughly matches your image

   pointX = 2*xStep,
   pointY = 0;

Basically the points on any isometric grid fall onto the intersections of a non-isometric grid. Isometric grid controller:

screenPositionToIsoXY : function(o, w, h){
    var sX   = ((((o.x - this.canvas.xPosition) - this.screenOffsetX) / this.unitWidth ) * 2) >> 0,
        sY   = ((((o.y - this.canvas.yPosition) - this.screenOffsetY) / this.unitHeight) * 2) >> 0,
        isoX = ((sX + sY - this.cols) / 2) >> 0,
        isoY = (((-1 + this.cols) - (sX - sY)) / 2) >> 0;

    // isoX = ((sX + sY) / isoGrid.width) - 1
    // isoY = ((-2 + isoGrid.width) - sX - sY) / 2

    return $.extend(o, {
        isoX : Math.constrain(isoX, 0, this.cols - (w||0)),
        isoY : Math.constrain(isoY, 0, this.rows - (h||0))
    });
},

// ...

isoToUnitGrid : function(isoX, isoY){
    var offset = this.grid.offset(),
        isoX   = $.uD(isoX) ? this.isoX : isoX,
        isoY   = $.uD(isoY) ? this.isoY : isoY;

    return {
        x : (offset.x + (this.grid.unitWidth  / 2) * (this.grid.rows - this.isoWidth + isoX - isoY)) >> 0,
        y : (offset.y + (this.grid.unitHeight / 2) * (isoX + isoY)) >> 0
    };
},


回答3:

Okay so with the help of other answers (sorry guys neither quite provided the answer i was after)

I present my function for finding the grid position on an iso 2d grid using a world x,y coordinate where the world x,y is an offset screen space coord.

WorldPosToGridPos: function(iPosX, iPosY){
    var d = (this.mcBoundaryVectors.upper.x * this.mcBoundaryVectors.lower.y) - (this.mcBoundaryVectors.upper.y * this.mcBoundaryVectors.lower.x);

    var a = ((iPosX * this.mcBoundaryVectors.lower.y) - (this.mcBoundaryVectors.lower.x * iPosY)) / d;
    var b = ((this.mcBoundaryVectors.upper.x * iPosY) - (iPosX * this.mcBoundaryVectors.upper.y)) / d;

    var cParaUpperVec = new Vector2(a * this.mcBoundaryVectors.upper.x, a * this.mcBoundaryVectors.upper.y);
    var cParaLowerVec = new Vector2(b * this.mcBoundaryVectors.lower.x, b * this.mcBoundaryVectors.lower.y);

    var iGridWidth = 40;
    var iGridHeight = 40;

    var iGridX = Math.floor((cParaLowerVec.length() / this.mcBoundaryVectors.lower.length()) * iGridWidth);
    var iGridY = Math.floor((cParaUpperVec.length() / this.mcBoundaryVectors.upper.length()) * iGridHeight);

    return {gridX: iGridX, gridY: iGridY};
},

The first line is best done once in an init function or similar to save doing the same calculation over and over, I just included it for completeness.

The mcBoundaryVectors are two vectors defining the outer limits of the x and y axis of the isometric grid (The black vectors shown in the picture above).

Hope this helps anyone else in the future