| """ |
| Hexagonal grid initialization for circle packing. |
| |
| A hexagonal (offset) grid provides a good starting arrangement |
| because it's the densest regular packing pattern. Even rows are |
| offset by half the spacing, which reduces wasted space. |
| """ |
|
|
| import numpy as np |
|
|
|
|
| def hexagonal_grid(n, margin=0.1): |
| """ |
| Generate n points on a hexagonal grid inside [margin, 1-margin]^2. |
| |
| Args: |
| n: number of points to generate |
| margin: distance from edges to keep clear |
| |
| Returns: |
| np.array of shape (n, 2) with (x, y) coordinates |
| """ |
| usable = 1.0 - 2 * margin |
| cols = int(np.ceil(np.sqrt(n * 2 / np.sqrt(3)))) |
| rows = int(np.ceil(n / cols)) |
|
|
| dx = usable / max(cols - 1, 1) |
| dy = usable / max(rows - 1, 1) |
|
|
| points = [] |
| for row in range(rows): |
| for col in range(cols): |
| if len(points) >= n: |
| break |
| x = margin + col * dx |
| if row % 2 == 1: |
| x += dx / 2 |
| y = margin + row * dy |
| x = np.clip(x, margin, 1 - margin) |
| y = np.clip(y, margin, 1 - margin) |
| points.append([x, y]) |
|
|
| return np.array(points[:n]) |
|
|