impl/python/avoid_collisions.py
1,154 bytes · the Python implementation · view raw
from typing import List, Sequence
from .charts_layout_types import LabelBox
def avoid_collisions(boxes: Sequence[LabelBox], padding: float) -> List[bool]:
"""Which labels to show so none overlap: greedily, highest priority first
(then input order), keeping a label only if it clears every kept label by
at least padding. Touching is not overlapping. Result in input order."""
if not padding >= 0:
raise ValueError("padding must not be negative, received %r" % (padding,))
for b in boxes:
if not (b.width >= 0 and b.height >= 0):
raise ValueError("label boxes must not have negative size")
order = sorted(range(len(boxes)), key=lambda i: (-boxes[i].priority, i))
shown = [False] * len(boxes)
kept: List[LabelBox] = []
for i in order:
a = boxes[i]
clash = any(
a.x < k.x + k.width + padding
and k.x < a.x + a.width + padding
and a.y < k.y + k.height + padding
and k.y < a.y + a.height + padding
for k in kept
)
if not clash:
kept.append(a)
shown[i] = True
return shown