Skip to content

Commit

Permalink
Region._merge_regions and Region._coalesce
Browse files Browse the repository at this point in the history
changed to methods.
  • Loading branch information
salt-die committed Aug 28, 2023
1 parent 79b5a44 commit 3fdf6f7
Showing 1 changed file with 48 additions and 29 deletions.
77 changes: 48 additions & 29 deletions rects/region.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from dataclasses import dataclass
from dataclasses import dataclass, field
from operator import or_, and_, xor
from typing import Callable, Iterator

Expand Down Expand Up @@ -49,6 +49,9 @@ class Rect:

@dataclass(slots=True)
class Band:
"""
A row of mutually exclusive rects.
"""
y1: int
y2: int
walls: list[int]
Expand All @@ -61,15 +64,15 @@ def __post_init__(self):
@dataclass(slots=True)
class Region:
"""
Collection of mutually exclusive bands.
Collection of mutually exclusive bands of rects.
"""
bands: list[Band]
bands: list[Band] = field(default_factory=[])

@staticmethod
def _coalesce(bands: list[Band]):
def _coalesce(self):
"""
Join contiguous bands with the same walls to reduce rects.
"""
bands = self.bands
i = 0
while i < len(bands) - 1:
a, b = bands[i], bands[i + 1]
Expand All @@ -83,14 +86,13 @@ def _coalesce(bands: list[Band]):
else:
i += 1

@classmethod
def _merge_regions(cls, op: BoolOp, a: "Region", b: "Region") -> "Region":
def _merge_regions(self, other: "Region", op: BoolOp) -> "Region":
bands = []
i = j = 0
scanline = -float("inf")

while i < len(a.bands) and j < len(b.bands):
r, s = a.bands[i], b.bands[j]
while i < len(self.bands) and j < len(other.bands):
r, s = self.bands[i], other.bands[j]
if r.y1 <= s.y1:
if scanline < r.y1:
scanline = r.y1
Expand Down Expand Up @@ -202,41 +204,35 @@ def _merge_regions(cls, op: BoolOp, a: "Region", b: "Region") -> "Region":
j += 1
i += 1

while i < len(a.bands):
r = a.bands[i]
while i < len(self.bands):
r = self.bands[i]
if scanline < r.y1:
scanline = r.y1
bands.append(Band(scanline, r.y2, _merge(op, r.walls, _NO_WALLS)))
i += 1

while j < len(b.bands):
s = b.bands[j]
while j < len(other.bands):
s = other.bands[j]
if scanline < s.y1:
scanline = s.y1
bands.append(Band(scanline, s.y2, _merge(op, _NO_WALLS, s.walls)))
j += 1

cls._coalesce(bands)
return cls(bands)

@classmethod
def from_rect(cls, rect: Rect) -> "Region":
"""
Make a region from a `Rect`.
"""
return cls([Band(rect.y, rect.y + rect.height, [rect.x, rect.x + rect.width])])
region = Region(bands=bands)
region._coalesce()
return region

def __and__(self, other: "Region") -> "Region":
return Region._merge_regions(and_, self, other)
return self._merge_regions(other, and_)

def __add__(self, other: "Region") -> "Region":
return Region._merge_regions(or_, self, other)
return self._merge_regions(other, or_)

def __sub__(self, other: "Region") -> "Region":
return Region._merge_regions(sub, self, other)
return self._merge_regions(other, sub)

def __xor__(self, other: "Region") -> "Region":
return Region._merge_regions(xor, self, other)
return self._merge_regions(other, xor)

def rects(self) -> Iterator[Rect]:
"""
Expand All @@ -249,6 +245,25 @@ def rects(self) -> Iterator[Rect]:
yield Rect(band.y1, band.walls[i], height, band.walls[i + 1] - band.walls[i])
i += 2

@property
def bbox(self) -> Rect | None:
"""
Bounding box of region or None if region is empty.
"""
if not self.bands:
return

y = self.bands[0].y1
x = min(band.walls[0] for band in self.bands)
height = self.bands[-1].y2 - y
width = max(band.walls[-1] for band in self.bands) - x

return Rect(y, x, height, width)

@classmethod
def from_rect(cls, rect: Rect) -> "Region":
return cls([Band(rect.y, rect.y + rect.height, [rect.x, rect.x + rect.width])])


if __name__ == "__main__":
r = Region.from_rect(Rect(0, 0, 60, 60))
Expand All @@ -257,9 +272,13 @@ def rects(self) -> Iterator[Rect]:

assert r == r - s + s - t + t

print(r - s - t)
for rect in (r - s - t).rects():
print(rect)
v = r - s - t

print("v:", v)
print("v.bbox:", v.bbox)

for i, rect in enumerate(v.rects()):
print(f"rect {i} of v:", rect)

try:
Band(5, 3, [1, 2, 3])
Expand Down

0 comments on commit 3fdf6f7

Please sign in to comment.