fimama.voronoi

  1# from icecream import ic
  2
  3import numpy as np
  4from matplotlib.axes import Axes
  5from matplotlib.collections import PatchCollection
  6from matplotlib.colors import LinearSegmentedColormap
  7from matplotlib.patches import Polygon
  8
  9from scipy.spatial import Voronoi, voronoi_plot_2d
 10
 11from .configuration import VoronoiConfiguration
 12
 13
 14def _generate_voronoi_grid(heightmap: np.ndarray | None = None):
 15    np.random.seed(1234)
 16    if heightmap is not None:
 17        grid_shape = (heightmap.shape[0] - 1, heightmap.shape[1] - 1, )
 18    else:
 19        grid_shape = (200, 200)
 20
 21    # make up data points
 22    base_points = np.mgrid[
 23        0:(grid_shape[0]):(grid_shape[0]+1)*1j,
 24        0:(grid_shape[1]):(grid_shape[1]+1)*1j
 25    ]
 26    base_points = base_points.reshape(2, -1).T
 27    points = base_points + np.random.random_sample(base_points.shape) - .5
 28
 29    # TODO 0.6: better dummy points or better yet exclude outermost ring of
 30    # points while keeping them saved as the basis of extending the map.
 31    # add 4 distant dummy points
 32    dummy_points = []
 33    dummy_points = [[999, 999], [-999, 999], [999, -999], [-999, -999]]
 34    base_points = np.append(base_points, dummy_points, axis=0)
 35    points = np.append(points, dummy_points, axis=0)
 36
 37    # compute Voronoi tessellation
 38    voronoi = Voronoi(points)
 39    return voronoi, points, dummy_points, grid_shape
 40
 41
 42def voronoi_map(
 43    axes: Axes,
 44    fig,
 45    heightmap: np.ndarray = None,
 46    colormap: LinearSegmentedColormap = None,
 47    config: VoronoiConfiguration = None,
 48):
 49    """
 50    Plot a voronoi heightmap.
 51
 52    Parameters
 53    ----------
 54    axes : Axes
 55        axes to plot on
 56    fig : _type_
 57        Figure we are plotting into. Used for adding a colorbar.
 58    heightmap : np.ndarray, optional
 59        The heightmap, by default None
 60    colormap : LinearSegmentedColormap, optional
 61        _description_, by default None
 62    config : VoronoiConfiguration, optional
 63        _description_, by default None
 64    """
 65    if colormap is None:
 66        colormap = "terrain"
 67    if config is None:
 68        config = VoronoiConfiguration()
 69
 70    voronoi, points, dummy_points, grid_shape = _generate_voronoi_grid(
 71        heightmap=heightmap)
 72
 73    if config.plot_voronoi_grid:
 74        voronoi_plot_2d(
 75            vor=voronoi,
 76            ax=axes,
 77            show_vertices=config.show_vertices,
 78            show_points=config.show_points
 79        )
 80
 81    # map regions to points
 82    regions_to_points = np.argsort(voronoi.point_region)
 83
 84    # Polygon patches for the voronoi regions
 85    polygons = []
 86    polygon_index = 0
 87    heights = np.zeros(len(points) - len(dummy_points))
 88    heightmap = heightmap.flatten()
 89    for i, region in enumerate(voronoi.regions):
 90        if -1 not in region and len(region) > 0:
 91            vertices = [voronoi.vertices[i] for i in region]
 92            polygon = Polygon(vertices, closed=True)
 93            polygons.append(polygon)
 94            # center = np.mean(polygon.get_xy(), axis=0)
 95            # axes.text(center[0], center[1], f"{i}")
 96            # index, = np.where(voronoi.point_region == i)
 97            # index = index[0]
 98            # ic(index, regions_to_points[i-1])
 99            heights[polygon_index] = heightmap[regions_to_points[i-1]]
100            polygon_index += 1
101            # axes.text(
102            #     point[0], point[1],
103            #     f"{j}, {i}",
104            #     horizontalalignment='center',
105            #     verticalalignment='center'
106            # )
107    # ic(points_in_regions[1:])
108    # ic(region_to_polygon[1:])
109    # ic(voronoi.point_region)
110    # ic(regions_to_points)
111    poly_collection = PatchCollection(patches=polygons, cmap=colormap)
112
113    poly_collection.set_array(heights)
114    axes.add_collection(poly_collection)
115    fig.colorbar(poly_collection, ax=axes)
116
117    # fix the range of axes
118    axes.set_xlim([-1, grid_shape[0]+1])
119    axes.set_ylim([-1, grid_shape[1]+1])
def voronoi_map( axes: matplotlib.axes._axes.Axes, fig, heightmap: numpy.ndarray = None, colormap: matplotlib.colors.LinearSegmentedColormap = None, config: fimama.configuration.VoronoiConfiguration = None):
 43def voronoi_map(
 44    axes: Axes,
 45    fig,
 46    heightmap: np.ndarray = None,
 47    colormap: LinearSegmentedColormap = None,
 48    config: VoronoiConfiguration = None,
 49):
 50    """
 51    Plot a voronoi heightmap.
 52
 53    Parameters
 54    ----------
 55    axes : Axes
 56        axes to plot on
 57    fig : _type_
 58        Figure we are plotting into. Used for adding a colorbar.
 59    heightmap : np.ndarray, optional
 60        The heightmap, by default None
 61    colormap : LinearSegmentedColormap, optional
 62        _description_, by default None
 63    config : VoronoiConfiguration, optional
 64        _description_, by default None
 65    """
 66    if colormap is None:
 67        colormap = "terrain"
 68    if config is None:
 69        config = VoronoiConfiguration()
 70
 71    voronoi, points, dummy_points, grid_shape = _generate_voronoi_grid(
 72        heightmap=heightmap)
 73
 74    if config.plot_voronoi_grid:
 75        voronoi_plot_2d(
 76            vor=voronoi,
 77            ax=axes,
 78            show_vertices=config.show_vertices,
 79            show_points=config.show_points
 80        )
 81
 82    # map regions to points
 83    regions_to_points = np.argsort(voronoi.point_region)
 84
 85    # Polygon patches for the voronoi regions
 86    polygons = []
 87    polygon_index = 0
 88    heights = np.zeros(len(points) - len(dummy_points))
 89    heightmap = heightmap.flatten()
 90    for i, region in enumerate(voronoi.regions):
 91        if -1 not in region and len(region) > 0:
 92            vertices = [voronoi.vertices[i] for i in region]
 93            polygon = Polygon(vertices, closed=True)
 94            polygons.append(polygon)
 95            # center = np.mean(polygon.get_xy(), axis=0)
 96            # axes.text(center[0], center[1], f"{i}")
 97            # index, = np.where(voronoi.point_region == i)
 98            # index = index[0]
 99            # ic(index, regions_to_points[i-1])
100            heights[polygon_index] = heightmap[regions_to_points[i-1]]
101            polygon_index += 1
102            # axes.text(
103            #     point[0], point[1],
104            #     f"{j}, {i}",
105            #     horizontalalignment='center',
106            #     verticalalignment='center'
107            # )
108    # ic(points_in_regions[1:])
109    # ic(region_to_polygon[1:])
110    # ic(voronoi.point_region)
111    # ic(regions_to_points)
112    poly_collection = PatchCollection(patches=polygons, cmap=colormap)
113
114    poly_collection.set_array(heights)
115    axes.add_collection(poly_collection)
116    fig.colorbar(poly_collection, ax=axes)
117
118    # fix the range of axes
119    axes.set_xlim([-1, grid_shape[0]+1])
120    axes.set_ylim([-1, grid_shape[1]+1])

Plot a voronoi heightmap.

Parameters
  • axes (Axes): axes to plot on
  • fig (_type_): Figure we are plotting into. Used for adding a colorbar.
  • heightmap (np.ndarray, optional): The heightmap, by default None
  • colormap (LinearSegmentedColormap, optional): _description_, by default None
  • config (VoronoiConfiguration, optional): _description_, by default None