190 lines
3.8 KiB
Python
190 lines
3.8 KiB
Python
import math
|
|
from mathutils import Vector
|
|
|
|
|
|
class BBox:
|
|
@classmethod
|
|
def calc_bbox(cls, coords):
|
|
xmin = math.inf
|
|
xmax = -math.inf
|
|
ymin = math.inf
|
|
ymax = -math.inf
|
|
|
|
for x, y in coords:
|
|
if xmin > x:
|
|
xmin = x
|
|
if xmax < x:
|
|
xmax = x
|
|
if ymin > y:
|
|
ymin = y
|
|
if ymax < y:
|
|
ymax = y
|
|
return cls(xmin, xmax, ymin, ymax)
|
|
|
|
@classmethod
|
|
def calc_bbox_uv(cls, group, uv_layers, are_loops=False):
|
|
xmin = math.inf
|
|
xmax = -math.inf
|
|
ymin = math.inf
|
|
ymax = -math.inf
|
|
|
|
if not are_loops:
|
|
for face in group:
|
|
for loop in face.loops:
|
|
x, y = loop[uv_layers].uv
|
|
if xmin > x:
|
|
xmin = x
|
|
if xmax < x:
|
|
xmax = x
|
|
if ymin > y:
|
|
ymin = y
|
|
if ymax < y:
|
|
ymax = y
|
|
else:
|
|
for loop in group:
|
|
x, y = loop[uv_layers].uv
|
|
if xmin > x:
|
|
xmin = x
|
|
if xmax < x:
|
|
xmax = x
|
|
if ymin > y:
|
|
ymin = y
|
|
if ymax < y:
|
|
ymax = y
|
|
return cls(xmin, xmax, ymin, ymax)
|
|
|
|
@classmethod
|
|
def init_from_minmax(cls, min, max):
|
|
bbox = cls(min[0], max[0], min[1], max[1])
|
|
bbox.sanitize()
|
|
return bbox
|
|
|
|
def __init__(self, xmin=math.inf, xmax=-math.inf, ymin=math.inf, ymax=-math.inf):
|
|
self.xmin = xmin
|
|
self.xmax = xmax
|
|
self.ymin = ymin
|
|
self.ymax = ymax
|
|
|
|
def __str__(self):
|
|
return f"xmin={self.xmin:.6}, xmax={self.xmax:.6}, ymin={self.ymin:.6}, ymax={self.ymax:.6}, width={self.width:.6}, height={self.height:.6}"
|
|
|
|
@property
|
|
def is_valid(self) -> bool:
|
|
return (self.xmin < self.xmax) and (self.ymin < self.ymax)
|
|
|
|
@property
|
|
def max(self):
|
|
return Vector((self.xmax, self.ymax))
|
|
|
|
@property
|
|
def min(self):
|
|
return Vector((self.xmin, self.ymin))
|
|
|
|
@property
|
|
def left_upper(self):
|
|
return Vector((self.xmin, self.ymax))
|
|
|
|
@property
|
|
def left_bottom(self):
|
|
return Vector((self.xmin, self.ymin))
|
|
|
|
@property
|
|
def right_bottom(self):
|
|
return Vector((self.xmax, self.ymin))
|
|
|
|
@property
|
|
def right_upper(self):
|
|
return Vector((self.xmax, self.ymax))
|
|
|
|
@property
|
|
def upper(self):
|
|
return Vector(((self.xmin + self.xmax) * 0.5, self.ymax))
|
|
|
|
@property
|
|
def bottom(self):
|
|
return Vector(((self.xmin + self.xmax) * 0.5, self.ymin))
|
|
|
|
@property
|
|
def left(self):
|
|
return Vector((self.xmin, (self.ymin + self.ymax) * 0.5))
|
|
|
|
@property
|
|
def right(self):
|
|
return Vector((self.xmax, (self.ymin + self.ymax) * 0.5))
|
|
|
|
@property
|
|
def center(self):
|
|
return Vector(((self.xmin + self.xmax) * 0.5, (self.ymin + self.ymax) * 0.5))
|
|
|
|
@property
|
|
def width(self) -> float:
|
|
return self.xmax - self.xmin
|
|
|
|
@property
|
|
def height(self) -> float:
|
|
return self.ymax - self.ymin
|
|
|
|
@property
|
|
def max_lenght(self):
|
|
return max(self.width, self.height)
|
|
|
|
@property
|
|
def min_lenght(self):
|
|
return min(self.width, self.height)
|
|
|
|
@property
|
|
def half_width(self) -> float:
|
|
return (self.xmax - self.xmin) * 0.5
|
|
|
|
@property
|
|
def half_height(self) -> float:
|
|
return (self.ymax - self.ymin) * 0.5
|
|
|
|
@property
|
|
def area(self):
|
|
return self.width * self.height
|
|
|
|
@property
|
|
def is_empty(self) -> bool:
|
|
return (self.xmax <= self.xmin) or (self.ymax <= self.ymin)
|
|
|
|
def union(self, other):
|
|
if self.xmin > other.xmin:
|
|
self.xmin = other.xmin
|
|
if self.xmax < other.xmax:
|
|
self.xmax = other.xmax
|
|
if self.ymin > other.ymin:
|
|
self.ymin = other.ymin
|
|
if self.ymax < other.ymax:
|
|
self.ymax = other.ymax
|
|
return self
|
|
|
|
def sanitize(self):
|
|
if self.xmin > self.xmax:
|
|
self.xmin, self.xmax = self.xmax, self.xmin
|
|
if self.ymin > self.ymax:
|
|
self.ymin, self.ymax = self.ymax, self.ymin
|
|
# assert self.is_valid
|
|
return self
|
|
|
|
def do_minmax_v(self, xy):
|
|
if xy[0] < self.xmin:
|
|
self.xmin = xy[0]
|
|
if xy[0] > self.xmax:
|
|
self.xmax = xy[0]
|
|
if xy[1] < self.ymin:
|
|
self.ymin = xy[1]
|
|
if xy[1] > self.ymax:
|
|
self.ymax = xy[1]
|
|
|
|
def update(self, coords):
|
|
for x, y in coords:
|
|
if x < self.xmin:
|
|
self.xmin = x
|
|
if x > self.xmax:
|
|
self.xmax = x
|
|
if y < self.ymin:
|
|
self.ymin = y
|
|
if y > self.ymax:
|
|
self.ymax = y
|