Determine closest vertex to line passing through a hexagon

65 Views Asked by At

Background

Looking to determine the nearest vertex to a line that crosses the edge of a hexagon.

Problem

There are a few problems.

  • Can't use the atan2 function (seems to be unimplemented in the programming language).
  • I'm having trouble converting the slope of the line to degrees comparable to the degree of a vertex.

In the attached images, the variables have the following meanings:

  • s -- the slope of the line.
  • t -- the arc-tangent of s in radians ($atan( s ) \times 180 / \pi$)
  • v -- the vertex number in degrees ($v_n = 60 \times \frac{\pi}{180}$), marked in shades of magenta around the starting hex.

My question follows the pictures (scroll down):

Calc 1

Calc 2

Calc 3

Question

How would you convert the slope (and/or the coordinates of the line's endpoints) into degrees that can be compared to the degrees of each vertex without using $atan2(y, x)$?

Alternatively, is there a simple formula that, given the coordinates for two points (i.e., x1/y1 and x2/y2), it will return the nearest vertex between 0 and 5 of the intersecting line (or even an angle rounded to the nearest 60th degree)? (The line is guaranteed to cross an edge of the hex because the starting and ending points are in different hexes, so there aren't any edge cases ...)

Addendum

In the following images,

  • v -- The angle from each vertex to the hex center point.

  • s_mv -- The slope of each line from the starting hex coordinate to each vertex (in degrees).

  • s_mo -- The slope of the line from the starting point to the ending point (in degrees).

  • d_ov -- The difference between s_mv and s_mo governed by:

    $atan( \frac{s_{mo} - s_{mv}}{1 + s_{mo} \times s_{mv}} ) \times \frac{180}{\pi}$

Slopes to Degrees 1

Slopes to Degrees 2

Slopes to Degrees 3

1

There are 1 best solutions below

0
On BEST ANSWER

Wikipedia defines $atan2()$ function in terms of $atan()$, allowing for a reasonable solution. First, we define our own atan2() function as follows:

vardef atantwo( expr ax, ay, bx, by ) =
  numeric dx;
  numeric dy;

  dx := bx - ax;
  dy := by - ay;

  numeric theta;
  theta := 0;

  if (dx > 0):
    theta := atan( dy / dx );
  elseif (dx < 0) and (dy >= 0):
    theta := atan( dy / dx ) + pi;
  elseif (dx < 0) and (dy < 0):
    theta := atan( dy / dx ) - pi;
  elseif (dx == 0) and (dy > 0):
    theta := pi / 2;
  elseif (dx == 0) and (dy < 0):
    theta := -pi / 2;
  fi;

  theta
enddef;

Next, because we want to compensate for quadrants, we define a conversion function for radians that honours the sign:

vardef degrees( expr radians ) =
  numeric degrees;
  degrees := radians * 180 / pi;

  if (degrees < 0):
    degrees := 360 + degrees;
  fi;

  degrees
enddef;

Given a Cartesian-style grid of hexagons and a point at (X, Y), we can compute the center offset for a unit hexagon (a) using:

HEIGHT  = sqrt( 3 );
HHEIGHT = HEIGHT / 2;
WIDTH   = 2;

hex_ax := X * WIDTH * (HHEIGHT - 1/8);
hex_ay := Y * HEIGHT - (X mod 2 * HHEIGHT);

We apply the same calculation for the second unit hexagon (b).

Next, we obtain the slope of the line between the two hexagon centers in degrees by calling atan2 then converting radians to degrees:

numeric theta;
theta := degrees( atantwo( hex_ax, hex_ay, hex_bx, hex_by ) );

Finally, we can determine the closest vertex by dividing the result by 60 and rounding:

vertex := round( theta / 60 );

In effect, given (X1, Y1) and (X2, Y2) as the coordinates for two points on a hexagonal grid, we can find the nearest vertex to the starting point using:

v = round(
  degrees(
    atan2(
      X1 * 2 * sqrt( 3 ) / 2 - 1 / 8, 
      Y1 * sqrt( 3 ) - (X1 mod 2 * sqrt( 3 ) / 2),
      X2 * 2 * sqrt( 3 ) / 2 - 1 / 8, 
      Y2 * sqrt( 3 ) - (X2 mod 2 * sqrt( 3 ) / 2)
    ) 
  ) / 60
)

The constant expressions for converting to a hexagon-based offset can be eliminated, simplifying this solution to:

$v = round( \frac{degrees( atan2( X1, Y1, X2, Y2 ) ) )}{60} )$

Here's a collage of the results where the red line points to the selected vertex that most closely aligns with the slope of the green line segment that connects the hexes:

Collage of Vertex Choices

Simpler solutions welcome.