Reputation: 775
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
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
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
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()
You can use the above hexagon(theta)
to get the maximum radius. theta
can be calculated with math.atan2(y, x)
.
Upvotes: 1
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