You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe.
While attempting to refactor the pymupdf4llm module (and incidentally discovering several bugs in it), I came across the IRect class. What is the purpose of this class if it is entirely identical to pymupdf.Rect? The instances where the code differs have only raised further questions.
Describe the solution you'd like
Code stability and consistency, reuse of existing code directly.
Describe alternatives you've considered
At least, use Rect as baseclass for IRect. Or use Rect only and dynamically decide how to increase speed for integer rect operations (may be just argument).
Additional context
class IRect
classIRect:
""" IRect() - all zeros IRect(x0, y0, x1, y1) - 4 coordinates IRect(top-left, x1, y1) - point and 2 coordinates IRect(x0, y0, bottom-right) - 2 coordinates and point IRect(top-left, bottom-right) - 2 points IRect(sequ) - new from sequence or rect-like """def__add__(self, p):
returnRect.__add__(self, p).round()
def__and__(self, x):
returnRect.__and__(self, x).round()
def__contains__(self, x):
returnRect.__contains__(self, x)
def__eq__(self, r):
ifnothasattr(r, "__len__"):
returnFalsereturnlen(r) ==4andself.x0==r[0] andself.y0==r[1] andself.x1==r[2] andself.y1==r[3]
def__getitem__(self, i):
return (self.x0, self.y0, self.x1, self.y1)[i]
def__init__(self, *args, p0=None, p1=None, x0=None, y0=None, x1=None, y1=None):
self.x0, self.y0, self.x1, self.y1=util_make_irect( *args, p0=p0, p1=p1, x0=x0, y0=y0, x1=x1, y1=y1)
def__len__(self):
return4def__mul__(self, m):
returnRect.__mul__(self, m).round()
def__neg__(self):
returnIRect(-self.x0, -self.y0, -self.x1, -self.y1)
def__or__(self, x):
returnRect.__or__(self, x).round()
def__pos__(self):
returnIRect(self)
def__repr__(self):
return"IRect"+str(tuple(self))
def__setitem__(self, i, v):
v=int(v)
ifi==0: self.x0=velifi==1: self.y0=velifi==2: self.x1=velifi==3: self.y1=velse:
raiseIndexError("index out of range")
returnNonedef__sub__(self, p):
returnRect.__sub__(self, p).round()
def__truediv__(self, m):
returnRect.__truediv__(self, m).round()
@propertydefbottom_left(self):
"""Bottom-left corner."""returnPoint(self.x0, self.y1)
@propertydefbottom_right(self):
"""Bottom-right corner."""returnPoint(self.x1, self.y1)
@propertydefheight(self):
returnmax(0, self.y1-self.y0)
definclude_point(self, p):
"""Extend rectangle to include point p."""rect=self.rect.include_point(p)
returnrect.irectdefinclude_rect(self, r):
"""Extend rectangle to include rectangle r."""rect=self.rect.include_rect(r)
returnrect.irectdefintersect(self, r):
"""Restrict rectangle to intersection with rectangle r."""returnRect.intersect(self, r).round()
defintersects(self, x):
returnRect.intersects(self, x)
@propertydefis_empty(self):
"""True if rectangle area is empty."""returnself.x0>=self.x1orself.y0>=self.y1@propertydefis_infinite(self):
"""True if rectangle is infinite."""returnself.x0==self.y0==FZ_MIN_INF_RECTandself.x1==self.y1==FZ_MAX_INF_RECT@propertydefis_valid(self):
"""True if rectangle is valid."""returnself.x0<=self.x1andself.y0<=self.y1defmorph(self, p, m):
"""Morph with matrix-like m and point-like p. Returns a new quad."""ifself.is_infinite:
returnINFINITE_QUAD()
returnself.quad.morph(p, m)
defnorm(self):
returnmath.sqrt(sum([c*cforcinself]))
defnormalize(self):
"""Replace rectangle with its valid version."""ifself.x1<self.x0:
self.x0, self.x1=self.x1, self.x0ifself.y1<self.y0:
self.y0, self.y1=self.y1, self.y0returnself@propertydefquad(self):
"""Return Quad version of rectangle."""returnQuad(self.tl, self.tr, self.bl, self.br)
@propertydefrect(self):
returnRect(self)
@propertydeftop_left(self):
"""Top-left corner."""returnPoint(self.x0, self.y0)
@propertydeftop_right(self):
"""Top-right corner."""returnPoint(self.x1, self.y0)
deftorect(self, r):
"""Return matrix that converts to target rect."""r=Rect(r)
ifself.is_infiniteorself.is_emptyorr.is_infiniteorr.is_empty:
raiseValueError("rectangles must be finite and not empty")
return (
Matrix(1, 0, 0, 1, -self.x0, -self.y0)
*Matrix(r.width/self.width, r.height/self.height)
*Matrix(1, 0, 0, 1, r.x0, r.y0)
)
deftransform(self, m):
returnRect.transform(self, m).round()
@propertydefwidth(self):
returnmax(0, self.x1-self.x0)
br=bottom_rightbl=bottom_lefttl=top_lefttr=top_right
class Rect
classRect:
def__abs__(self):
ifself.is_emptyorself.is_infinite:
return0.0return (self.x1-self.x0) * (self.y1-self.y0)
def__add__(self, p):
ifhasattr(p, "__float__"):
returnRect(self.x0+p, self.y0+p, self.x1+p, self.y1+p)
iflen(p) !=4:
raiseValueError("Rect: bad seq len")
returnRect(self.x0+p[0], self.y0+p[1], self.x1+p[2], self.y1+p[3])
def__and__(self, x):
ifnothasattr(x, "__len__"):
raiseValueError("bad operand 2")
r1=Rect(x)
r=Rect(self)
returnr.intersect(r1)
def__bool__(self):
returnnot (max(self) ==min(self) ==0)
def__contains__(self, x):
ifhasattr(x, "__float__"):
returnxintuple(self)
l=len(x)
ifl==2:
returnutil_is_point_in_rect(x, self)
ifl==4:
r=INFINITE_RECT()
try:
r=Rect(x)
exceptException:
ifg_exceptions_verbose>1: exception_info()
r=Quad(x).rectreturn (self.x0<=r.x0<=r.x1<=self.x1andself.y0<=r.y0<=r.y1<=self.y1)
returnFalsedef__eq__(self, rect):
ifnothasattr(rect, "__len__"):
returnFalsereturnlen(rect) ==4andbool(self-rect) isFalsedef__getitem__(self, i):
return (self.x0, self.y0, self.x1, self.y1)[i]
def__hash__(self):
returnhash(tuple(self))
def__init__(self, *args, p0=None, p1=None, x0=None, y0=None, x1=None, y1=None):
""" Rect() - all zeros Rect(x0, y0, x1, y1) Rect(top-left, x1, y1) Rect(x0, y0, bottom-right) Rect(top-left, bottom-right) Rect(Rect or IRect) - new copy Rect(sequence) - from 'sequence' Explicit keyword args p0, p1, x0, y0, x1, y1 override earlier settings if not None. """x0, y0, x1, y1=util_make_rect( *args, p0=p0, p1=p1, x0=x0, y0=y0, x1=x1, y1=y1)
self.x0=float( x0)
self.y0=float( y0)
self.x1=float( x1)
self.y1=float( y1)
def__len__(self):
return4def__mul__(self, m):
ifhasattr(m, "__float__"):
returnRect(self.x0*m, self.y0*m, self.x1*m, self.y1*m)
r=Rect(self)
r=r.transform(m)
returnrdef__neg__(self):
returnRect(-self.x0, -self.y0, -self.x1, -self.y1)
def__nonzero__(self):
returnnot (max(self) ==min(self) ==0)
def__or__(self, x):
ifnothasattr(x, "__len__"):
raiseValueError("bad operand 2")
r=Rect(self)
iflen(x) ==2:
returnr.include_point(x)
iflen(x) ==4:
returnr.include_rect(x)
raiseValueError("bad operand 2")
def__pos__(self):
returnRect(self)
def__repr__(self):
return"Rect"+str(tuple(self))
def__setitem__(self, i, v):
v=float(v)
ifi==0: self.x0=velifi==1: self.y0=velifi==2: self.x1=velifi==3: self.y1=velse:
raiseIndexError("index out of range")
returnNonedef__sub__(self, p):
ifhasattr(p, "__float__"):
returnRect(self.x0-p, self.y0-p, self.x1-p, self.y1-p)
iflen(p) !=4:
raiseValueError("Rect: bad seq len")
returnRect(self.x0-p[0], self.y0-p[1], self.x1-p[2], self.y1-p[3])
def__truediv__(self, m):
ifhasattr(m, "__float__"):
returnRect(self.x0*1./m, self.y0*1./m, self.x1*1./m, self.y1*1./m)
im=util_invert_matrix(m)[1]
ifnotim:
raiseZeroDivisionError(f"Matrix not invertible: {m}")
r=Rect(self)
r=r.transform(im)
returnr@propertydefbottom_left(self):
"""Bottom-left corner."""returnPoint(self.x0, self.y1)
@propertydefbottom_right(self):
"""Bottom-right corner."""returnPoint(self.x1, self.y1)
defcontains(self, x):
"""Check if containing point-like or rect-like x."""returnself.__contains__(x)
@propertydefheight(self):
returnmax(0, self.y1-self.y0)
definclude_point(self, p):
"""Extend to include point-like p."""iflen(p) !=2:
raiseValueError("Point: bad seq len")
self.x0, self.y0, self.x1, self.y1=util_include_point_in_rect(self, p)
returnselfdefinclude_rect(self, r):
"""Extend to include rect-like r."""iflen(r) !=4:
raiseValueError("Rect: bad seq len")
r=Rect(r)
ifr.is_infiniteorself.is_infinite:
self.x0, self.y0, self.x1, self.y1=FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECTelifr.is_empty:
returnselfelifself.is_empty:
self.x0, self.y0, self.x1, self.y1=r.x0, r.y0, r.x1, r.y1else:
self.x0, self.y0, self.x1, self.y1=util_union_rect(self, r)
returnselfdefintersect(self, r):
"""Restrict to common rect with rect-like r."""ifnotlen(r) ==4:
raiseValueError("Rect: bad seq len")
r=Rect(r)
ifr.is_infinite:
returnselfelifself.is_infinite:
self.x0, self.y0, self.x1, self.y1=r.x0, r.y0, r.x1, r.y1elifr.is_empty:
self.x0, self.y0, self.x1, self.y1=r.x0, r.y0, r.x1, r.y1elifself.is_empty:
returnselfelse:
self.x0, self.y0, self.x1, self.y1=util_intersect_rect(self, r)
returnselfdefintersects(self, x):
"""Check if intersection with rectangle x is not empty."""r1=Rect(x)
ifself.is_emptyorself.is_infiniteorr1.is_emptyorr1.is_infinite:
returnFalser=Rect(self)
ifr.intersect(r1).is_empty:
returnFalsereturnTrue@propertydefis_empty(self):
"""True if rectangle area is empty."""returnself.x0>=self.x1orself.y0>=self.y1@propertydefis_infinite(self):
"""True if this is the infinite rectangle."""returnself.x0==self.y0==FZ_MIN_INF_RECTandself.x1==self.y1==FZ_MAX_INF_RECT@propertydefis_valid(self):
"""True if rectangle is valid."""returnself.x0<=self.x1andself.y0<=self.y1defmorph(self, p, m):
"""Morph with matrix-like m and point-like p. Returns a new quad."""ifself.is_infinite:
returnINFINITE_QUAD()
returnself.quad.morph(p, m)
defnorm(self):
returnmath.sqrt(sum([c*cforcinself]))
defnormalize(self):
"""Replace rectangle with its finite version."""ifself.x1<self.x0:
self.x0, self.x1=self.x1, self.x0ifself.y1<self.y0:
self.y0, self.y1=self.y1, self.y0returnself@propertydefquad(self):
"""Return Quad version of rectangle."""returnQuad(self.tl, self.tr, self.bl, self.br)
defround(self):
"""Return the IRect."""returnIRect(util_round_rect(self))
@propertydeftop_left(self):
"""Top-left corner."""returnPoint(self.x0, self.y0)
@propertydeftop_right(self):
"""Top-right corner."""returnPoint(self.x1, self.y0)
deftorect(self, r):
"""Return matrix that converts to target rect."""r=Rect(r)
ifself.is_infiniteorself.is_emptyorr.is_infiniteorr.is_empty:
raiseValueError("rectangles must be finite and not empty")
return (
Matrix(1, 0, 0, 1, -self.x0, -self.y0)
*Matrix(r.width/self.width, r.height/self.height)
*Matrix(1, 0, 0, 1, r.x0, r.y0)
)
deftransform(self, m):
"""Replace with the transformation by matrix-like m."""ifnotlen(m) ==6:
raiseValueError("Matrix: bad seq len")
self.x0, self.y0, self.x1, self.y1=util_transform_rect(self, m)
returnself@propertydefwidth(self):
returnmax(0, self.x1-self.x0)
__div__=__truediv__bl=bottom_leftbr=bottom_rightirect=property(round)
tl=top_lefttr=top_right
The text was updated successfully, but these errors were encountered:
Is your feature request related to a problem? Please describe.
While attempting to refactor the pymupdf4llm module (and incidentally discovering several bugs in it), I came across the IRect class. What is the purpose of this class if it is entirely identical to pymupdf.Rect? The instances where the code differs have only raised further questions.
Describe the solution you'd like
Code stability and consistency, reuse of existing code directly.
Describe alternatives you've considered
At least, use Rect as baseclass for IRect. Or use Rect only and dynamically decide how to increase speed for integer rect operations (may be just argument).
Additional context
class IRect
class Rect
The text was updated successfully, but these errors were encountered: