user129412
user129412

Reputation: 775

Function to determine if point is inside hexagon

Let me start by stating that while my question is of a programming nature, the part where I get stuck is a bit mathematical. So I'm not sure if this is the correct place to post about it, but I wasn't sure where else.

I'm trying to define some boolean function that returns true if a point (x,y) is inside a certain shape and false if outside. To clarify that, the following code would work for defining an annulus (a ring) of inner radius r1 and outer radius r2:

def ring(pos):
    (x, y) = pos
    rsq = x ** 2 + y ** 2
    return (r1 ** 2 < rsq < r2 ** 2)

My question would be if someone could help me come up with a clever way to define a function like this for a hexagonal region. Specifically, I'd like to define a hexagonal region with side length s (which is half of the diameter), centered around the origin. Ideally it would also be oriented such that the top and bottom are sides, paralel with the x-axis.

Upvotes: 0

Views: 2692

Answers (4)

Ma0
Ma0

Reputation: 15204

My two cents:

def inside(pos, R):
    import numpy as np
    r = R * np.sqrt(3) / 2
    try:  # thanks to @stefan-pochmann
        phi = np.arctan(pos[1] / pos[0])
    except ZeroDivisionError:
        phi = 0.0
    length = np.sqrt(pos[0] ** 2 + pos[1] ** 2)
    for i in range(3):
        rot = 2 * np.pi / 3.0 * i
        new_phi = phi + rot
        new_pos = (length * np.sin(new_phi), length * np.cos(new_phi))
        if abs(new_pos[0]) <= np.sqrt(R ** 2 - r ** 2) and abs(new_pos[1]) <= r:
            return True
    return False

It assumes that the hexagon is centered around (0, 0) and R is the prescribed circle radius and r the inscribed one.

It is not an implementation of the ring algorithm. It uses bounding boxes

Upvotes: 1

Stefan Pochmann
Stefan Pochmann

Reputation: 28606

Using symmetry to get into the first quadrant and then simple math (Pythagoras is enough) to check whether the point is both "below the diagonal" (which has y = sqrt(3) ⋅ (s - x)) and "below the top edge" (which has y = sqrt(3)/2 ⋅ s).

>>> def hexagon(pos):
        x, y = map(abs, pos)
        return y < 3**0.5 * min(s - x, s / 2)

Demo:

>>> s = 13
>>> for y in range(-s, s+1):
        print(' '.join('.X'[hexagon((x, y))] for x in range(-s, s+1)))

. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . X X X X X X X X X X X X X . . . . . . .
. . . . . . X X X X X X X X X X X X X X X . . . . . .
. . . . . . X X X X X X X X X X X X X X X . . . . . .
. . . . . X X X X X X X X X X X X X X X X X . . . . .
. . . . . X X X X X X X X X X X X X X X X X . . . . .
. . . . X X X X X X X X X X X X X X X X X X X . . . .
. . . X X X X X X X X X X X X X X X X X X X X X . . .
. . . X X X X X X X X X X X X X X X X X X X X X . . .
. . X X X X X X X X X X X X X X X X X X X X X X X . .
. . X X X X X X X X X X X X X X X X X X X X X X X . .
. X X X X X X X X X X X X X X X X X X X X X X X X X .
. X X X X X X X X X X X X X X X X X X X X X X X X X .
. X X X X X X X X X X X X X X X X X X X X X X X X X .
. . X X X X X X X X X X X X X X X X X X X X X X X . .
. . X X X X X X X X X X X X X X X X X X X X X X X . .
. . . X X X X X X X X X X X X X X X X X X X X X . . .
. . . X X X X X X X X X X X X X X X X X X X X X . . .
. . . . X X X X X X X X X X X X X X X X X X X . . . .
. . . . . X X X X X X X X X X X X X X X X X . . . . .
. . . . . X X X X X X X X X X X X X X X X X . . . . .
. . . . . . X X X X X X X X X X X X X X X . . . . . .
. . . . . . X X X X X X X X X X X X X X X . . . . . .
. . . . . . . X X X X X X X X X X X X X . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .

Upvotes: 4

Eric Duminil
Eric Duminil

Reputation: 54223

Your solution is basically based on polar coordinates. Since rings or circles are centered on the origin, you don't care about θ though : you just need to check if r is inside [0,r_max] for a disk or [r_min,r_max] for a ring.

You could use a polar definition of an hexagon and check if r is inside [0,r_hexagon(θ)].

Here's an example with numpy and matplotlib :

import numpy as np
import matplotlib.pyplot as plt
import math


theta = np.arange(0, 2 * math.pi, 0.01)

sixty_d = math.pi / 3


def hexagon(theta):
    return math.sqrt(3) / (2 * math.sin(theta + sixty_d -
                                        sixty_d * math.floor(theta / sixty_d)))

hexagon = np.vectorize(hexagon)

ax = plt.subplot(111, projection='polar')
ax.plot(theta, hexagon(theta))
ax.set_rmax(1.5)
ax.set_rticks([0.5, 1, 1.5])
ax.grid(True)

ax.set_title("Hexagon in polar coordinates", va='bottom')
plt.show()

It displays :enter image description here

You can use the above hexagon(theta) to get the maximum radius. theta can be calculated with math.atan2(y, x).

Upvotes: 1

Elie Nassif
Elie Nassif

Reputation: 462

create a bounding box around the hexagon, the height is distance between the center corners lets say a, and the width is the distance between the left and right facets lets say b.
if you have a predetermined size for the hexagon you can easily get the area of the 4 triangles that surround it.
therefore you can test if your point is in one of these triangles, if not then it is in the hexagon.

 ________
|   /\   |
|* /  \ *|  This is an illustration of the above suggestion
| /    \ |  The * are points outside the hexagon.
|/      \|
|        |
|        |
|\      /|
| \    / |
| *\  / *|
|___\/___|

Upvotes: 0

Related Questions