census.py

3.3 kB · python · 103 lines

1from typing import Dict, List, Tuple2from mrlypy.core.errors import MrlyError3from . import VOID, FILL, GRID45# TRIANGLE GEOMETRY67def _north(x: int, y: int) -> List[Tuple[int, int]]:8    return [(x, 2 * y + 2), (x + 1, 2 * y), (x + 2, 2 * y + 2)]910def _south(x: int, y: int) -> List[Tuple[int, int]]:11    return [(x, 2 * y), (x + 1, 2 * y + 2), (x + 2, 2 * y)]1213def _corners(x: int, y: int, start: int) -> List[Tuple[int, int]]:14    north = (x + y + start) % 2 == 015    return _north(x, y) if north else _south(x, y)1617def _edges_of(corners: List[Tuple[int, int]]) -> List[Tuple[Tuple[int, int], Tuple[int, int]]]:18    a, b, c = corners19    return [tuple(sorted((a, b))), tuple(sorted((b, c))), tuple(sorted((a, c)))]2021# CENSUS2223def _present(value: int, include_grid: bool) -> bool:24    if value == FILL:25        return True26    if value == VOID:27        return True28    if value == GRID:29        return include_grid30    return True3132def census_triangles(cell, start: int = None, include_grid: bool = False) -> Dict[str, int]:33    inner = cell._cell if hasattr(cell, "_cell") else cell34    if start is None:35        start = getattr(cell, "start", 0)36    types = inner.types37    height, width = types.shape38    fills = voids = grids = 039    vertices = set()40    edge_count: Dict[Tuple, int] = {}41    for y in range(height):42        for x in range(width):43            v = int(types[y, x])44            if v == GRID and not include_grid:45                grids += 146                continue47            if v == FILL:48                fills += 149            elif v == VOID:50                voids += 151            elif v == GRID:52                grids += 153            corners = _corners(x, y, start)54            for c in corners:55                vertices.add(c)56            for e in _edges_of(corners):57                edge_count[e] = edge_count.get(e, 0) + 158    triangles = fills + voids + (grids if include_grid else 0)59    edges = len(edge_count)60    boundary = sum(1 for n in edge_count.values() if n == 1)61    interior = edges - boundary62    euler = len(vertices) - edges + triangles63    return {64        "triangles": triangles,65        "fills": fills,66        "voids": voids,67        "grids": grids,68        "vertices": len(vertices),69        "edges": edges,70        "boundary_edges": boundary,71        "interior_edges": interior,72        "euler": euler,73    }7475def fills_only(cell, start: int = None) -> Dict[str, int]:76    inner = cell._cell if hasattr(cell, "_cell") else cell77    if start is None:78        start = getattr(cell, "start", 0)79    types = inner.types80    height, width = types.shape81    count = 082    vertices = set()83    edge_count: Dict[Tuple, int] = {}84    for y in range(height):85        for x in range(width):86            if int(types[y, x]) != FILL:87                continue88            count += 189            corners = _corners(x, y, start)90            for c in corners:91                vertices.add(c)92            for e in _edges_of(corners):93                edge_count[e] = edge_count.get(e, 0) + 194    edges = len(edge_count)95    boundary = sum(1 for n in edge_count.values() if n == 1)96    return {97        "triangles": count,98        "vertices": len(vertices),99        "edges": edges,100        "boundary_edges": boundary,101        "interior_edges": edges - boundary,102        "euler": len(vertices) - edges + count,103    }