Hexagonal Grids, how do you find which hexagon a point is in?

前端 未结 8 720
不知归路
不知归路 2020-12-07 15:14

I have a map made up of rows and columns of hexagons\"\"

This isn\'t an actual image of the hex-map I am using,

8条回答
  •  感动是毒
    2020-12-07 15:22

    I started out by looking at @pi 's answer https://stackoverflow.com/a/23370350/5776618 and thought it would be interesting to try something similar in cube coordinates with UVW-space (rather than the 2D, axial, UV-space).

    The following equations map (x,y) => (u,v,w)

    u = (2/3)*x;
    v = -(1/3)*x + (1/2)*y;
    w = -(1/3)*x - (1/2)*y;
    

    Then it's as simple as rounding u, v, and w to the nearest integer and converting back to x,y. However there is a major snag...

    In the answer above, it's noted that rounding in UV-space will have a few areas that map incorrectly:

    This still happens when using cube coordinates as well:

    Any area in the orange triangles is >0.5 units from the center of the hexagon and when rounded will round AWAY from the center. This is shown above as anything in the red triangle (to the left of the u=1.5 line) will have u rounded incorrectly to u=1 rather than u=2.

    Some key observations here though...

    1. The orange/red problem areas are non-overlapping

    2. In cube coordinates, valid hex centers have u + v + w = 0

    In the below code, u, v, and w, are all rounded from the start as rounding in only an issue if the rounded coordinates do not sum to zero.

    uR = Math.round(u);
    vR = Math.round(v);
    wR = Math.round(w);
    

    If these do not sum to zero, because the problem areas are non-overlapping, there will be only 1 coordinate that is rounded incorrectly. This coordinate is also the coordinate that was rounded the most.

    arr = [ Math.abs(u-uR), Math.abs(v-vR), Math.abs(w-wR) ];
    var i = arr.indexOf(Math.max(...arr));
    

    After the problem coordinate is found, it is rounded in the other direction. The final (x,y) are then calculated from rounded/corrected (u,v,w).

    nearestHex = function(x,y){
    
      u = (2/3)*x;
      v = -(1/3)*x + (1/2)*y;
      w = -(1/3)*x - (1/2)*y;
    
      uR = Math.round(u);
      vR = Math.round(v);
      wR = Math.round(w);
    
      if(uR+vR+wR !== 0){
        arr = [ Math.abs(u-uR), Math.abs(v-vR), Math.abs(w-wR) ];
        var i = arr.indexOf(Math.max(...arr));
    
        switch(i){
          case 0:
            Math.round(u)===Math.floor(u) ? u = Math.ceil(u) : u = Math.floor(u);
            v = vR; w = wR;
            break;
    
          case 1:
            Math.round(v)===Math.floor(v) ? v = Math.ceil(v) : v = Math.floor(v);
            u = uR; w = wR;
            break;
    
          case 2:
            Math.round(w)===Math.floor(w) ? w = Math.ceil(w) : w = Math.floor(w);
            u = uR; v = vR;
            break;
        }
      }
    
      return {x: (3/2)*u, y: v-w};
    
    }
    

提交回复
热议问题