I know this kind of questions has been posted several times, but hear me out first before you decide anything.
In short, I want to turn this:
Into this:
All the curves are a sixth of a circle, the three poly-lines approximate three arms of a spiral, I need to fill all regions defined by two arms and two arcs.
I had viewed a bunch of questions on this site dealing similar problems, all of them mentioned ax.fill_between method, but it involves NumPy arrays, and I did not use NumPy arrays to do the calculations.
The function that calculates the things is the following (minus the bounding box part):
def polygon_spiral(unit, iterations, num_colors=12):
step = 1530/num_colors
palette = ['#'+spectrum_position(round(step*i), 1) for i in range(num_colors)]
colors = [palette[0]]
radius = unit*cos(30)/1.5
y1 = -radius/2
x1 = -unit/2
x2 = unit/2
points = [(0, radius), (x2, y1), (x1, y1)]
polygons = [points]
lines = [[(0, 0), (x1/2, radius/4)], [(0, 0), (0, y1)], [(0, 0), (x2/2, radius/4)]]
side = 4
left_start, left_end = points[0], points[2]
down_start, down_end = points[2], points[1]
right_start, right_end = points[1], points[0]
for i in range(iterations):
left = make_polygon(left_start, left_end, side)
down = make_polygon(down_start, down_end, side)
right = make_polygon(right_start, right_end, side)
polygons.append(left)
polygons.append(down)
polygons.append(right)
colors.extend([palette[(i+1)%num_colors]]*3)
half = (side/2).__ceil__()
left_start, left_end = left[half-1:half+1]
lines[0].append(mid(left_start, left_end))
down_start, down_end = down[half-1:half+1]
lines[1].append(mid(down_start, down_end))
right_start, right_end = right[half-1:half+1]
lines[2].append(mid(right_start, right_end))
side += 1
indices = {0: (1, 2), 1: (0, 2), 2: (0, 1)}
arcs = []
for i in range(iterations+1, 0, -1):
points = [lines[j][i] for j in range(3)]
(x0, y0), (x1, y1), (x2, y2) = points
dx = x1 - x0
dy = y1 - y0
r = (dx*dx + dy*dy)**.5
for k, v in indices.items():
a, b = points[k]
thetas = []
for h in v:
c, d = points[h]
angle = atan2(c - a, d - b)
if angle < 0:
angle += 360
thetas.append(angle)
theta1, theta2 = thetas
if theta1 > theta2:
theta1, theta2 = theta2, theta1
if not np.isclose(theta2 - theta1, 60):
theta1, theta2 = theta2 - 360, theta1
arcs.append([(a, b), r, theta1, theta2])
return {'polygons': polygons, 'lines': lines, 'arcs': arcs, 'colors': colors}
You can see the full script on GitHub.
The point is the lines are stored as three lists of coordinates (stored as (x, y) tuples) of discrete vertices, and they are drawn via matplotlib.collections.LineCollection, and the arcs are described by the coordinate of its center, its radius, theta1 and theta2, and drawn via matplotlib.patches.Arc.
I did not use arrays anywhere in this script, how can I fill the areas defined by two arcs and two arms without using arrays and fill_between, and if that's not possible, how do I do the same calculations in a vectorized way and use fill_between to fill the areas?


