149 lines
5.4 KiB
Python
149 lines
5.4 KiB
Python
"""Border merging post-pass — fix junction characters where borders meet.
|
|
|
|
Scans the CharGrid for adjacent border cells and replaces with the
|
|
correct junction character (T-junctions, crosses, corners) from the
|
|
Unicode box-drawing set.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from uframe.grid import CharGrid
|
|
from uframe.ir import BorderWeight
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Connection detection
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# For each border cell, check which directions have adjacent borders.
|
|
# Direction flags:
|
|
UP = 1
|
|
DOWN = 2
|
|
LEFT = 4
|
|
RIGHT = 8
|
|
|
|
# Junction lookup: connections bitmask → character
|
|
# Only light weight for now (most common case)
|
|
_LIGHT_JUNCTIONS: dict[int, str] = {
|
|
UP | DOWN: "│",
|
|
LEFT | RIGHT: "─",
|
|
DOWN | RIGHT: "┌",
|
|
DOWN | LEFT: "┐",
|
|
UP | RIGHT: "└",
|
|
UP | LEFT: "┘",
|
|
UP | DOWN | RIGHT: "├",
|
|
UP | DOWN | LEFT: "┤",
|
|
LEFT | RIGHT | DOWN: "┬",
|
|
LEFT | RIGHT | UP: "┴",
|
|
UP | DOWN | LEFT | RIGHT: "┼",
|
|
RIGHT: "─",
|
|
LEFT: "─",
|
|
UP: "│",
|
|
DOWN: "│",
|
|
}
|
|
|
|
_HEAVY_JUNCTIONS: dict[int, str] = {
|
|
UP | DOWN: "┃",
|
|
LEFT | RIGHT: "━",
|
|
DOWN | RIGHT: "┏",
|
|
DOWN | LEFT: "┓",
|
|
UP | RIGHT: "┗",
|
|
UP | LEFT: "┛",
|
|
UP | DOWN | RIGHT: "┣",
|
|
UP | DOWN | LEFT: "┫",
|
|
LEFT | RIGHT | DOWN: "┳",
|
|
LEFT | RIGHT | UP: "┻",
|
|
UP | DOWN | LEFT | RIGHT: "╋",
|
|
RIGHT: "━",
|
|
LEFT: "━",
|
|
UP: "┃",
|
|
DOWN: "┃",
|
|
}
|
|
|
|
_DOUBLE_JUNCTIONS: dict[int, str] = {
|
|
UP | DOWN: "║",
|
|
LEFT | RIGHT: "═",
|
|
DOWN | RIGHT: "╔",
|
|
DOWN | LEFT: "╗",
|
|
UP | RIGHT: "╚",
|
|
UP | LEFT: "╝",
|
|
UP | DOWN | RIGHT: "╠",
|
|
UP | DOWN | LEFT: "╣",
|
|
LEFT | RIGHT | DOWN: "╦",
|
|
LEFT | RIGHT | UP: "╩",
|
|
UP | DOWN | LEFT | RIGHT: "╬",
|
|
RIGHT: "═",
|
|
LEFT: "═",
|
|
UP: "║",
|
|
DOWN: "║",
|
|
}
|
|
|
|
_JUNCTION_TABLES = {
|
|
BorderWeight.LIGHT: _LIGHT_JUNCTIONS,
|
|
BorderWeight.HEAVY: _HEAVY_JUNCTIONS,
|
|
BorderWeight.DOUBLE: _DOUBLE_JUNCTIONS,
|
|
BorderWeight.ROUNDED: _LIGHT_JUNCTIONS, # rounded uses light junctions
|
|
}
|
|
|
|
# Weight priority for mixed-weight junctions
|
|
_WEIGHT_PRIORITY = {
|
|
BorderWeight.DOUBLE: 3,
|
|
BorderWeight.HEAVY: 2,
|
|
BorderWeight.LIGHT: 1,
|
|
BorderWeight.ROUNDED: 0,
|
|
}
|
|
|
|
|
|
def merge_borders(grid: CharGrid) -> None:
|
|
"""Scan the grid for adjacent border cells and fix junction characters.
|
|
|
|
This pass resolves cases where two boxes share an edge or corner,
|
|
replacing the overlapping border characters with proper junctions.
|
|
"""
|
|
for row in range(grid.height):
|
|
for col in range(grid.width):
|
|
cell = grid.cells[row][col]
|
|
if not cell.is_border:
|
|
continue
|
|
|
|
# Detect connections in 4 directions
|
|
connections = 0
|
|
max_weight = cell.border_weight or BorderWeight.LIGHT
|
|
|
|
# Check each neighbor
|
|
if row > 0 and grid.cells[row - 1][col].is_border:
|
|
connections |= UP
|
|
nw = grid.cells[row - 1][col].border_weight or BorderWeight.LIGHT
|
|
if _WEIGHT_PRIORITY.get(nw, 0) > _WEIGHT_PRIORITY.get(max_weight, 0):
|
|
max_weight = nw
|
|
|
|
if row < grid.height - 1 and grid.cells[row + 1][col].is_border:
|
|
connections |= DOWN
|
|
nw = grid.cells[row + 1][col].border_weight or BorderWeight.LIGHT
|
|
if _WEIGHT_PRIORITY.get(nw, 0) > _WEIGHT_PRIORITY.get(max_weight, 0):
|
|
max_weight = nw
|
|
|
|
if col > 0 and grid.cells[row][col - 1].is_border:
|
|
connections |= LEFT
|
|
nw = grid.cells[row][col - 1].border_weight or BorderWeight.LIGHT
|
|
if _WEIGHT_PRIORITY.get(nw, 0) > _WEIGHT_PRIORITY.get(max_weight, 0):
|
|
max_weight = nw
|
|
|
|
if col < grid.width - 1 and grid.cells[row][col + 1].is_border:
|
|
connections |= RIGHT
|
|
nw = grid.cells[row][col + 1].border_weight or BorderWeight.LIGHT
|
|
if _WEIGHT_PRIORITY.get(nw, 0) > _WEIGHT_PRIORITY.get(max_weight, 0):
|
|
max_weight = nw
|
|
|
|
# Skip rounded corners — they should preserve ╭╮╰╯
|
|
if cell.border_weight == BorderWeight.ROUNDED and connections in (
|
|
DOWN | RIGHT, DOWN | LEFT, UP | RIGHT, UP | LEFT
|
|
):
|
|
continue
|
|
|
|
# Look up the junction character
|
|
if connections:
|
|
table = _JUNCTION_TABLES.get(max_weight, _LIGHT_JUNCTIONS)
|
|
junction = table.get(connections)
|
|
if junction:
|
|
cell.char = junction
|