Skip to content

Instantly share code, notes, and snippets.

@p-i-
Last active August 22, 2024 13:51
Show Gist options
  • Save p-i-/f236f662adf4b6a22aba5ac7df365af8 to your computer and use it in GitHub Desktop.
Save p-i-/f236f662adf4b6a22aba5ac7df365af8 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"`setup_ipynb.py` executed, (multi-output enabled for subsequent cell executions).\n"
]
}
],
"source": [
"import setup_ipynb\n",
"\n",
"from Coord import Coord\n",
"from Rect import Rect"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
" 1 2 to 3 4"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R = Rect((1, 2), (3, 4))\n",
"R"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"❌ What are you trying to do?\n"
]
}
],
"source": [
"try:\n",
" Rect(1, 2)\n",
"except Exception as e:\n",
" print('❌', e)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"( 5 1, 1 5)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"(1, int)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"( 1 3, Coord.Coord)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"([ 1 3, 3 5], [1, 5, 3, 3])"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R = Rect(rt_lb=(Coord(5,1), [3, 3]))\n",
"R.rt, R.tr\n",
"R.t, type(R.t)\n",
"R.tl, type(R.tl)\n",
"R.tl_br, R.trbl"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"( 9 1, 4.0 0.0)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R = Rect(0)\n",
"R.b = 8\n",
"R.hw, R.center"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
" 1 2 to 3 4"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Rect(1,2,3,4)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"9.0 9.0 to 11.0 11.0"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"99.0 -101.0 to 101.0 -99.0"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R = Rect((-1, -1), (1, 1))\n",
"\n",
"R.set(center=10)\n",
"R.set(center=(100, -100))\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"( 0 0 to 2 2, -2 -2 to 0 0)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R = Rect((-1, -1), (1, 1))\n",
"R + 1, R - 1\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
" 9 9 to 11 11"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R += 10\n",
"R"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 0, 1, 2, 3, 4],\n",
" [ 5, 6, 7, 8, 9],\n",
" [10, 11, 12, 13, 14],\n",
" [15, 16, 17, 18, 19],\n",
" [20, 21, 22, 23, 24]])"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"(slice(0, 2, None), slice(1, 4, None))"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"array([[1, 2, 3],\n",
" [6, 7, 8]])"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import numpy as np\n",
"A = np.arange(25).reshape((5, 5))\n",
"A\n",
"R = Rect((0, 1), (1, 3))\n",
"R.slice\n",
"A[R.slice]"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"-2 -2 to -2 -2"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"text/plain": [
"-2 -2 to 2 2"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A = Rect(center=(-2,-2), radius=3).int\n",
"B = Rect(center=(2,2), radius=3).int\n",
"A\n",
"A & B\n",
"A | B"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"-2.0 -2.0"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A.center"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"property 'y' of 'Coord' object has no setter\n",
"We WANT an exception here\n"
]
}
],
"source": [
"try:\n",
" A.center.y += 1\n",
"except Exception as e:\n",
" print(e)\n",
" print('We WANT an exception here')\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
from collections.abc import Iterable
from math import ceil, floor
# from numbers import Number
from Coord import Coord
VERBOSE = False
def pr(*args, **kwargs):
if VERBOSE:
print(*args, **kwargs)
class Rect:
def __init__(self, *args, **kwargs):
self._t = self._b = self._l = self._r = 0
if args:
if len(args) == 1:
a = args[0]
if isinstance(a, Rect):
self.tl_br = a.tl_br
else:
# This will handle a numeric type or an iterable
# (like Coord or [3,2] or np.array([3,2]))
self.tl = self.br = Coord(args[0])
elif len(args) == 2:
# We need to be careful whether we're dealing with (t, l) or (tl, br)
a, b = args
if isinstance(a, Iterable) or isinstance(b, Iterable):
self.tl, self.br = a, b
else:
raise Exception("What are you trying to do?")
elif len(args) == 4:
self.tlbr = args
else:
assert False
for k, v in kwargs.items():
setattr(self, k, v)
def __getattr__(self, k):
# https://stackoverflow.com/questions/78899267/
if k.startswith('_'):
return
is_property = isinstance(getattr(self.__class__, k, None), property)
if is_property:
return object.__getattribute__(self, k)
if '_' in k:
return [getattr(self, u) for u in k.split('_')]
if len(k) > 1:
is_lower = k.islower()
k = k.lower()
L = [getattr(self, u) for u in k]
return Coord(L) if len(L) == 2 and is_lower else L
assert False
def __setattr__(self, k, v):
if k.startswith('_'):
object.__setattr__(self, k, v)
return
is_property = isinstance(getattr(self.__class__, k, None), property)
if is_property:
object.__setattr__(self, k, v)
return
# We need to check whether the attribute actually exists for the object, e.g. 'center' DOES exist as a property
# This should only execute if there's NO corresponding attribute
if len(k) == 1:
object.__setattr__(self, k, v)
else:
if '_' in k:
k = k.split('_')
if not isinstance(v, Iterable):
v = [v] * len(k)
for k_, v_ in zip(k, v):
pr('setting:', k_, v_)
setattr(self, k_, v_)
def _make_property(attr):
return property(
lambda self: getattr(self, f'_{attr}'),
lambda self, v: setattr(self, f'_{attr}', v)
)
# getter, setter)
t = _make_property('t')
b = _make_property('b')
l = _make_property('l')
r = _make_property('r')
@property
def h(self):
return self.b - self.t + 1
@h.setter
def h(self, v):
self.b = self.t + v - 1
@property
def w(self):
return self.r - self.l + 1
@w.setter
def w(self, v):
self.r = self.l + v - 1
# Note `R.center.y += 1` will fail. That's as it should be.
@property
def center(self):
return (self.tl + self.br) / 2
@center.setter
def center(self, v):
self += -self.center + Coord(v)
# Allow: newR = R(t=0, b=1)
def __call__(self, **D):
R = Rect(self.t, self.b, self.l, self.r)
R.set(**D)
return R
# Allow R.set(t=0)
def set(self, **D):
for k, v in D.items():
setattr(self, k, v)
return self
@property
def copy(self):
t, l, b, r = self.tlbr
return Rect(t, l, b, r)
# Allow: newR = R.new(t=0, b=1)
def spawn(self, **D):
return self.copy.set(**D)
@property
def int(self):
return Rect([int(u) for u in self.tlbr])
def __repr__(self):
return f'{self.tl:~>2} to {self.br:~>2}'
def _slice(self, fix_right_margin=False):
return tuple(
slice(
ceil(p),
None if fix_right_margin and q == 0 else floor(q) + 1
)
for (p, q) in self.tb_lr
)
@property
def slice(self):
return self._slice()
@property
def mslice(self):
return self._slice(fix_right_margin=True)
def __contains__(self, p):
return self.tl <= Coord(p) <= self.br
def __iadd__(self, u):
u = Coord(u)
self.tl += u
self.br += u
return self
def __add__(self, u):
u = Coord(u)
return Rect(tl=self.tl + u, br=self.br + u)
def __sub__(self, u):
u = Coord(u)
return Rect(tl=self.tl - Coord(u), br=self.br - u)
def __and__(self, u):
if not isinstance(u, Rect):
u = Rect(u)
t, l, b, r = self.tlbr
T, L, B, R = u.tlbr
R = Rect(t=max(t, T), l=max(l, L), b=min(b, B), r=min(r, R))
return None if R.r < R.l or R.b < R.t else R
def __or__(self, u):
if not isinstance(u, Rect):
u = Rect(u)
t, l, b, r = self.tlbr
T, L, B, R = u.tlbr
return Rect(t=min(t, T), l=min(l, L), b=max(b, B), r=max(r, R))
def __eq__(self, u):
if not isinstance(u, Rect):
u = Rect(u)
return all(p == q for p, q in zip(self, u))
# def __mul__(self, k):
# return Rect(k * self._)
def extend(self, in_place=False, *args, **kwargs):
M = Rect(*args, **kwargs)
if in_place:
self.tl -= M.tl
self.br += M.br
return self
return Rect(tl=self.tl - M.tl, br=self.br - M.br)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment