I created a hexagon blur that gives this kind of results:
To make the code a bit cleaner, I created a hexagon class. I'm now implementing different methods inside.
My constructor look to this for now:
def __init__(self, radius, center_x, center_y, angle=0):
self._dmin = np.sqrt(3)/2
self._radius = radius
self._radius_min = radius * self.dmin
self._center_x = center_x
self._center_y = center_y
self._angle = angle # Angle in degrees
self._radian = np.radians(self.angle)
self._period = 60
I stuck on the methods radiusX and radiusY. This methods should give in output the distance from the center to the border based on the current hexagon center. For radiusX with a y at 0 and radiusY with a x at 0.
I tried different implementations but the more accurate one I got until now is:
def radiusX(self) -> float:
return self.radius_min + Trigonometry.one2Zero2One(x=self.angle%self.period, period=self.period) * (self.radius - self.radius_min)
def radiusY(self) -> float:
return self.radius_min + Trigonometry.zero2One2Zero(x=self.angle%self.period, period=self.period) * (self.radius - self.radius_min)
The methods one2Zero2One() and
zero2One2Zero() are implemented like this:
@staticmethod
def one2Zero2One(x, period):
return 0.5 + 0.5 * np.cos(x * np.pi / (period / 2))
@staticmethod
def zero2One2Zero(x, period):
return 0.5 + 0.5 * np.sin(x * np.pi / (period / 2) - 1.58)
They allow you to obtain a value on a bell between 0 and 1. zero2One2Zero look to this:
In my class, a hexagon with an angle of 0 is in this direction:
I know that my two methods are not good because when I visualise the results with plotly, I directly see that the radius doesn't follow the one2Zero2One and zero2One2Zero curves. In the examples below, above and on the right is have a green point which indicate the end of the x and y radius:
This graphics are obtained with:
h = Hexagon(radius=0.5, center_x=0.5, center_y=0.5, angle=j)
fig = go.Figure()
inside = {'x':[], 'y':[]}
outside = {'x':[], 'y':[]}
radius = {'x':[h.center_x + h.radiusX(), h.center_y], 'y':[h.center_y, h.center_y + h.radiusY()]}
print(h.radiusX())
for i in range(int(10e3)):
# print(i,'/',int(10e3))
x, y = random(), random()
if h.isPointInside(x, y):
inside['x'].append(x)
inside['y'].append(y)
else:
outside['x'].append(x)
outside['y'].append(y)
fig.add_trace(go.Scatter(x=inside['x'], y=inside['y'], mode='markers', name='Inside'))
fig.add_trace(go.Scatter(x=outside['x'], y=outside['y'], mode='markers', name='Outside'))
fig.add_trace(go.Scatter(x=radius['x'], y=radius['y'], mode='markers', name='radius', marker={'size':10}))
fig.show()
What is the correct equation for getting the radiusX and radiusY based on the current hexagon angle?
As far as your code goes, you don't need to use anything besides core Python for the geometric computations.
The math
module provides the trigonometric and transcendental functions you need:
from math import sin, cos, sqrt, degrees, radians, pi
No need for NumPy:
radians
. E.g. radians(360)/(2*pi) == 1.0
degrees
. E.g. degrees(2*pi)/360 == 1.0
.The only use for np
variants of radians
, degrees
, sqrt
, etc. is to have automatic broadcasting across NumPy arrays. Since you're dealing with scalars, bringing NumPy into the picture only muddies the water. Stick to core Python where possible - it makes the code easier to understand.
NumPy is useful for image manipulations, since it'll be faster than even fairly streamlined Python code. Nevertheless, the specializing compiler in Python 3.13 can already make NumPy unnecessary for some tasks :)
Suppose we have an n-polygon inscribed into a circle of radius r.
Then:
(1) α = 360°/n
From basic trigonometry:
(2) h/r = cos(γ) = cos(α/2), thus h = r cos(α/2)
(3) h/dx = cos(β), thus dx = h/cos(β)
Substituting (2) into (3), we get
(4) dx = r cos(α/2) / cos(β)
Then we substitute (1) into (4), and finally
(5) dx = r cos(180°/n) / cos(β)
You can work out dy similarly.
To investigate such geometric problems, GeoGebra works well. That's what I used to make the illustration above. That's what you should use to make properly labeled illustrations for your question. Help us help you!
Note: It is not possible to select overlapping objects well in GeoGebra - only the "first one" gets selected when you click on overlapping objects. To help selecting a particular object when they overlap (e.g. a short segment overlapping a long segment), switch from "Tools" to "Algebra" and you'll get a list of objects that you can select within the list.