I\'m looking for advice on the best way to proceed. I\'m trying to find whether a given point A:(a, b) is inside a regular hexagon, defined with center O:(x, y) and diameter
Subtract the position of the center of the hexagon from your point P to get a vector V. Then, take the dot product of V with the following vectors, which correspond to the three pairs of opposing hexagon edges:
[0,1] ; the edges that are flat with the horizontal
[cos(30),sin(30)] ; the upper-right and lower-left edges
[cos(-30),sin(-30)] ; the lower-right and upper-left edges
If any of the dot products are greater in magnitude than the distance from the center of the hexagon to one of its edges, then the point is not inside the hexagon.
For reference, the dot product of vectors [a,b] and [c,d] is a*c+b*d.
The angle "30" above is in degrees ;)
There's a nice generalization to a hex lattice using homogeneous coordinates, by representing the lattice as the cube-lattice intersected with the plane x+y+z=0, see https://www.redblobgames.com/grids/hexagons/#coordinates
Looks like you know general solution: "It seems like overkill to use...". So here is my idea:
Calculate distance from point to center and let's call it l
.
Then you can compare it to inradius (r
) and circumradius (R
). if l < r
then point is inside hexagon, if l > R
then outside. If r < l < R
then you have to check against each side respectively, but since R - r
is very small (13% of length of side of hex) so probability that you will have to do complex calculations is tiny.
Formulas can be found here: http://mathworld.wolfram.com/Hexagon.html
This is what I have been using:
public bool InsideHexagon(float x, float y)
{
// Check length (squared) against inner and outer radius
float l2 = x * x + y * y;
if (l2 > 1.0f) return false;
if (l2 < 0.75f) return true; // (sqrt(3)/2)^2 = 3/4
// Check against borders
float px = x * 1.15470053838f; // 2/sqrt(3)
if (px > 1.0f || px < -1.0f) return false;
float py = 0.5f * px + y;
if (py > 1.0f || py < -1.0f) return false;
if (px - py > 1.0f || px - py < -1.0f) return false;
return true;
}
px
and py
are the coordinates of x
and y
projected onto a coordinate system where it is much easier to check the boundaries.
I would first check if the point is inside the inscribed circle (you can compute the inscribed circle radius easily) or outside the circumscribed circle (that you already have).
The first means the point is in, the latter means it's out.
Statistically, most of the input points should allow you to decide based on the above simple tests.
For the worst case scenario (point is in between the inscribed and circumscribed circles), I think you can find the two vertices that are closest to the point and then see on which side of the segment V1V2 the point is (inner or outer, as relative to the O center). Special case: point is equal to one of the vertices => it's in.
If I'll have a more clever idea (or if I'll ever start to really learn trigonometry), I'll edit the answer to let you know :)
If you reduce the problem down to checking {x = 0, y = 0, d = 1}
in a single quadrant, you could make very simple.
public boolean IsInsideHexagon(float x0, float y0, float d, float x, float y) {
float dx = Math.abs(x - x0)/d;
float dy = Math.abs(y - y0)/d;
float a = 0.25 * Math.sqrt(3.0);
return (dy <= a) && (a*dx + 0.25*dy <= 0.5*a);
}
dy <= a
checks that the point is below the horizontal edge.a*dx + 0.25*dy <= 0.5*a
checks that the point is to the left of the sloped right edge.For {x0 = 0, y0 = 0, d = 1}
, the corner points would be (±0.25, ±0.43)
and (±0.5, 0.0)
.