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 }