summaryrefslogtreecommitdiffstats
path: root/src/cython/_cy_rectangle.pyx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
commit61f3ab8f23f4c924d455757bf3e65f8487521b5a (patch)
tree885599a36a308f422af98616bc733a0494fe149a /src/cython/_cy_rectangle.pyx
parentInitial commit. (diff)
downloadlib2geom-61f3ab8f23f4c924d455757bf3e65f8487521b5a.tar.xz
lib2geom-61f3ab8f23f4c924d455757bf3e65f8487521b5a.zip
Adding upstream version 1.3.upstream/1.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cython/_cy_rectangle.pyx')
-rw-r--r--src/cython/_cy_rectangle.pyx2202
1 files changed, 2202 insertions, 0 deletions
diff --git a/src/cython/_cy_rectangle.pyx b/src/cython/_cy_rectangle.pyx
new file mode 100644
index 0000000..1d1b687
--- /dev/null
+++ b/src/cython/_cy_rectangle.pyx
@@ -0,0 +1,2202 @@
+from numbers import Number
+
+from _common_decl cimport *
+from cython.operator cimport dereference as deref
+
+from _cy_affine cimport cy_Affine, get_Affine, is_transform
+
+
+cdef class cy_GenericInterval:
+ """
+ Represents all numbers between min and max.
+
+ Corresponds to GenericInterval in 2geom. min and max can be arbitrary
+ python object, they just have to implement arithmetic operations and
+ comparison - fractions.Fraction works. This is a bit experimental,
+ it leak memory right now.
+ """
+
+ cdef GenericInterval[WrappedPyObject]* thisptr
+
+ def __cinit__(self, u = 0, v = None):
+ """Create GenericInterval from either one or two values."""
+ if v is None:
+ self.thisptr = new GenericInterval[WrappedPyObject]( WrappedPyObject(u) )
+ else:
+ self.thisptr = new GenericInterval[WrappedPyObject]( WrappedPyObject(u), WrappedPyObject(v) )
+
+ def __str__(self):
+ """str(self)"""
+ return "[{}, {}]".format(self.min(), self.max())
+
+ def __repr__(self):
+ """repr(self)"""
+ if self.is_singular():
+ return "GenericInterval({})".format( str(self.min()) )
+ return "GenericInterval({}, {})".format( str(self.min()) , str(self.max()) )
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_Interval(self, i):
+ """Create GenericInterval with same minimum and maximum as argument."""
+ return cy_GenericInterval( i.min(), i.max() )
+
+ @classmethod
+ def from_list(self, lst):
+ """Create GenericInterval containing all values in list."""
+ if len(lst) == 0:
+ return cy_GenericInterval()
+ ret = cy_GenericInterval(lst[0])
+ for i in lst[1:]:
+ ret.expand_to(i)
+ return ret
+
+ def min(self):
+ """Return minimal value of interval."""
+ return self.thisptr.min().getObj()
+
+ def max(self):
+ """Return maximal value of interval."""
+ return self.thisptr.max().getObj()
+ def extent(self):
+ """Return difference between maximal and minimal value."""
+ return self.thisptr.extent().getObj()
+
+ def middle(self):
+ """Return midpoint of interval."""
+ return self.thisptr.middle().getObj()
+
+ def is_singular(self):
+ """Test for one-valued interval."""
+ return self.thisptr.isSingular()
+
+ def set_min(self, val):
+ """Set minimal value."""
+ self.thisptr.setMin( WrappedPyObject(val) )
+
+ def set_max(self, val):
+ """Set maximal value."""
+ self.thisptr.setMax( WrappedPyObject(val) )
+
+ def expand_to(self, val):
+ """Create smallest superset of self containing value."""
+ self.thisptr.expandTo( WrappedPyObject(val) )
+
+ def expand_by(self, val):
+ """Push both boundaries by value."""
+ self.thisptr.expandBy( WrappedPyObject(val) )
+ def union_with(self, cy_GenericInterval interval):
+ """self = self | other"""
+ self.thisptr.unionWith( deref(interval.thisptr) )
+
+ def contains(self, other):
+ """Check if interval contains value."""
+ return self.thisptr.contains( WrappedPyObject(other) )
+
+ def contains_interval(self, cy_GenericInterval other):
+ """Check if interval contains every point of interval."""
+ return self.thisptr.contains( deref(other.thisptr) )
+
+ def intersects(self, cy_GenericInterval other):
+ """Check for intersecting intervals."""
+ return self.thisptr.intersects(deref( other.thisptr ))
+
+ def __neg__(self):
+ """Return interval with negated boundaries."""
+ return wrap_GenericInterval(-deref(self.thisptr))
+
+ def _add_pyobj(self, X):
+ return wrap_GenericInterval(deref(self.thisptr) + WrappedPyObject(X) )
+ def _sub_pyobj(self, X):
+ return wrap_GenericInterval(deref(self.thisptr) - WrappedPyObject(X) )
+
+ def _add_interval(self, cy_GenericInterval I):
+ return wrap_GenericInterval(deref(self.thisptr)+deref(I.thisptr))
+ def _sub_interval(self, cy_GenericInterval I):
+ return wrap_GenericInterval(deref(self.thisptr)-deref(I.thisptr))
+
+ def __add__(cy_GenericInterval self, other):
+ """Add interval or value to self.
+
+ Interval I+J consists of all values i+j such that i is in I and
+ j is in J
+
+ Interval I+x consists of all values i+x such that i is in I.
+ """
+ if isinstance(other, cy_GenericInterval):
+ return self._add_interval(other)
+ else:
+ return self._add_pyobj(other)
+
+ def __sub__(cy_GenericInterval self, other):
+ """Substract interval or value.
+
+ Interval I-J consists of all values i-j such that i is in I and
+ j is in J
+
+ Interval I-x consists of all values i-x such that i is in I.
+ """
+ if isinstance(other, cy_GenericInterval):
+ return self._sub_interval(other)
+ else:
+ return self._sub_pyobj(other)
+
+ def __or__(cy_GenericInterval self, cy_GenericInterval I):
+ """Return a union of two intervals"""
+ return wrap_GenericInterval(deref(self.thisptr)|deref(I.thisptr))
+
+ def _eq(self, cy_GenericInterval other):
+ return deref(self.thisptr)==deref(other.thisptr)
+
+ def _neq(self, cy_GenericInterval other):
+ return deref(self.thisptr)!=deref(other.thisptr)
+
+ def __richcmp__(cy_GenericInterval self, other, op):
+ """Intervals are not ordered."""
+ if op == 2:
+ return self._eq(other)
+ elif op == 3:
+ return self._neq(other)
+
+cdef cy_GenericInterval wrap_GenericInterval(GenericInterval[WrappedPyObject] p):
+ cdef GenericInterval[WrappedPyObject] * retp = new GenericInterval[WrappedPyObject](WrappedPyObject(0))
+ retp[0] = p
+ cdef cy_GenericInterval r = cy_GenericInterval.__new__(
+ cy_GenericInterval, 0, 0)
+ r.thisptr = retp
+ return r
+
+
+cdef class cy_GenericOptInterval:
+
+ """Class representing optionally empty interval.
+
+ Empty interval has False bool value, and using methods that require
+ non-empty interval will result in ValueError. This is supposed to be
+ used this way:
+
+ >>> C = A & B
+ >>> if C:
+ >>> print C.min()
+
+ This class represents GenericOptInterval with python object boundaries.
+ It tries to model behaviour of std::optional.
+ """
+
+ cdef GenericOptInterval[WrappedPyObject]* thisptr
+
+ def __cinit__(self, u = None, v = None):
+ """Create interval from boundaries.
+
+ Using no arguments, you will end up with empty interval."""
+ if u is None:
+ self.thisptr = new GenericOptInterval[WrappedPyObject]()
+ elif v is None:
+ self.thisptr = new GenericOptInterval[WrappedPyObject](WrappedPyObject(u))
+ else:
+ self.thisptr = new GenericOptInterval[WrappedPyObject](WrappedPyObject(u), WrappedPyObject(v) )
+
+ def __bool__(self):
+ """Logical value of interval, False only for empty interval."""
+ return not self.thisptr.isEmpty()
+
+ def __str__(self):
+ """str(self)"""
+ if not self:
+ return "[]"
+ return "[{}, {}]".format(self.Interval.min(), self.Interval.max())
+
+ def __repr__(self):
+ """repr(self)"""
+ if not self:
+ return "GenericOptInterval()"
+ if self.Interval.isSingular():
+ return "GenericOptInterval({})".format( str(self.Interval.min()) )
+ return "GenericOptInterval({}, {})".format( str(self.Interval.min()) , str(self.Interval.max()) )
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_Interval(self, i):
+ """Create interval from existing interval."""
+ if hasattr(i, "isEmpty"):
+ if i.isEmpty():
+ return cy_GenericOptInterval()
+ else:
+ return cy_GenericOptInterval.from_Interval(i.Interval)
+ return cy_GenericOptInterval( i.min(), i.max() )
+
+ @classmethod
+ def from_list(self, lst):
+ """Create interval containing all values in list.
+
+ Empty list will result in empty interval."""
+ if len(lst) == 0:
+ return cy_GenericOptInterval()
+ ret = cy_GenericOptInterval(lst[0])
+ for i in lst[1:]:
+ ret.Interval.expandTo(i)
+ return ret
+
+ property Interval:
+ """Get underlying GenericInterval."""
+ def __get__(self):
+ if self.is_empty():
+ raise ValueError("Interval is empty.")
+ else:
+ return wrap_GenericInterval(self.thisptr.get())
+
+ def is_empty(self):
+ """Check whether interval is empty set."""
+ return self.thisptr.isEmpty()
+
+ def union_with(self, cy_GenericOptInterval o):
+ """self = self | other"""
+ self.thisptr.unionWith( deref(o.thisptr) )
+
+ def intersect_with(cy_GenericOptInterval self, cy_GenericOptInterval o):
+ """self = self & other"""
+ self.thisptr.intersectWith( deref(o.thisptr) )
+
+ def __or__(cy_GenericOptInterval self, cy_GenericOptInterval o):
+ """Return a union of two intervals."""
+ return wrap_GenericOptInterval(deref(self.thisptr) | deref(o.thisptr))
+
+ def __and__(cy_GenericOptInterval self, cy_GenericOptInterval o):
+ """Return an intersection of two intervals."""
+ return wrap_GenericOptInterval(deref(self.thisptr) & deref(o.thisptr))
+
+ def __richcmp__(cy_GenericOptInterval self, cy_GenericOptInterval o, int op):
+ """Intervals are not ordered."""
+ if op == 2:
+ return deref(self.thisptr) == deref(o.thisptr)
+ elif op == 3:
+ return deref(self.thisptr) != deref(o.thisptr)
+ return NotImplemented
+
+
+ def _get_Interval_method(self, name):
+ def f(*args, **kwargs):
+ if self.is_empty():
+ raise ValueError("GenericOptInterval is empty.")
+ else:
+ return self.Interval.__getattribute__(name)(*args, **kwargs)
+ return f
+
+ def __getattr__(self, name):
+
+ Interval_methods = set(['contains', 'contains_interval',
+ 'expand_by', 'expand_to', 'extent', 'from_Interval', 'from_list',
+ 'intersects', 'is_singular', 'max', 'middle', 'min', 'set_max',
+ 'set_min', 'union_with'])
+
+ if name in Interval_methods:
+ return self._get_Interval_method(name)
+ else:
+ raise AttributeError("GenericOptInterval instance has no attribute \"{}\"".format(name))
+
+ def _wrap_Interval_method(self, name, *args, **kwargs):
+ if self.isEmpty():
+ raise ValueError("GenericOptInterval is empty.")
+ else:
+ return self.Interval.__getattr__(name)(*args, **kwargs)
+
+ #declaring these by hand, because they take fixed number of arguments,
+ #which is enforced by cython
+
+ def __neg__(self):
+ """Return interval with negated boundaries."""
+ return self._wrap_Interval_method("__sub__")
+
+ def __add__(cy_Interval self, other):
+ """Add interval or value to self.
+
+ Interval I+J consists of all values i+j such that i is in I and
+ j is in J
+
+ Interval I+x consists of all values i+x such that i is in I.
+ """
+ return self._wrap_Interval_method("__add__", other)
+
+ def __sub__(cy_Interval self, other):
+ """Substract interval or value.
+
+ Interval I-J consists of all values i-j such that i is in I and
+ j is in J
+
+ Interval I-x consists of all values i-x such that i is in I.
+ """
+ return self._wrap_Interval_method("__sub__", other)
+
+cdef cy_GenericOptInterval wrap_GenericOptInterval(GenericOptInterval[WrappedPyObject] p):
+ cdef GenericOptInterval[WrappedPyObject] * retp = new GenericOptInterval[WrappedPyObject]()
+ retp[0] = p
+ cdef cy_GenericOptInterval r = cy_GenericOptInterval.__new__(cy_GenericOptInterval)
+ r.thisptr = retp
+ return r
+
+
+cdef class cy_Interval:
+
+ """Class representing interval on real line.
+
+ Corresponds to Interval class in 2geom.
+ """
+
+ def __cinit__(self, u = None, v = None):
+ """Create interval from it's boundaries.
+
+ One argument will create interval consisting that value, no
+ arguments create Interval(0).
+ """
+ if u is None:
+ self.thisptr = new Interval()
+ elif v is None:
+ self.thisptr = new Interval(<Coord>float(u))
+ else:
+ self.thisptr = new Interval(<Coord>float(u), <Coord>float(v))
+
+ def __str__(self):
+ """str(self)"""
+ return "[{}, {}]".format(self.min(), self.max())
+
+ def __repr__(self):
+ """repr(self)"""
+ if self.is_singular():
+ return "Interval({})".format( str(self.min()) )
+ return "Interval({}, {})".format( str(self.min()) , str(self.max()) )
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_Interval(c, i):
+ """Create Interval with same boundaries as argument."""
+ return cy_Interval( i.min(), i.max() )
+
+ @classmethod
+ def from_list(cls, lst):
+ """Create interval containing all values in a list."""
+ if len(lst) == 0:
+ return cy_Interval()
+ ret = cy_Interval(lst[0])
+ for i in lst[1:]:
+ ret.expand_to(i)
+ return ret
+
+ def min(self):
+ """Return minimal boundary."""
+ return self.thisptr.min()
+
+ def max(self):
+ """Return maximal boundary."""
+ return self.thisptr.max()
+
+ def extent(self):
+ """Return length of interval."""
+ return self.thisptr.extent()
+
+ def middle(self):
+ """Return middle value."""
+ return self.thisptr.middle()
+
+ def set_min(self, Coord val):
+ """Set minimal value."""
+ self.thisptr.setMin(val)
+
+ def set_max(self, Coord val):
+ """Set maximal value."""
+ self.thisptr.setMax(val)
+
+ def expand_to(self, Coord val):
+ """Set self to smallest superset of set containing value."""
+ self.thisptr.expandTo(val)
+
+ def expand_by(self, Coord amount):
+ """Move both boundaries by amount."""
+ self.thisptr.expandBy(amount)
+
+ def union_with(self, cy_Interval a):
+ """self = self | other"""
+ self.thisptr.unionWith(deref( a.thisptr ))
+
+# Not exposing this - deprecated
+# def __getitem__(self, unsigned int i):
+# return deref(self.thisptr)[i]
+
+ def is_singular(self):
+ """Test if interval contains only one value."""
+ return self.thisptr.isSingular()
+
+ def isFinite(self):
+ """Test for finiteness of interval's extent."""
+ return self.thisptr.isFinite()
+
+ def contains(cy_Interval self, other):
+ """Test if interval contains number."""
+ return self.thisptr.contains(float(other))
+
+ def contains_interval(cy_Interval self, cy_Interval other):
+ """Test if interval contains another interval."""
+ return self.thisptr.contains( deref(other.thisptr) )
+
+ def intersects(self, cy_Interval val):
+ """Test for intersection of intervals."""
+ return self.thisptr.intersects(deref( val.thisptr ))
+
+ def interior_contains(cy_Interval self, other):
+ """Test if interior of iterval contains number."""
+ return self.thisptr.interiorContains(float(other))
+
+ def interior_contains_interval(cy_Interval self, cy_Interval other):
+ """Test if interior of interval contains another interval."""
+ return self.thisptr.interiorContains( <Interval &> deref(other.thisptr) )
+
+
+ def interior_intersects(self, cy_Interval val):
+ """Test for intersection of interiors of two points."""
+ return self.thisptr.interiorIntersects(deref( val.thisptr ))
+
+ def _cmp_Interval(cy_Interval self, cy_Interval other, op):
+ if op == 2:
+ return deref(self.thisptr) == deref(other.thisptr)
+ elif op == 3:
+ return deref(self.thisptr) != deref(other.thisptr)
+ def _cmp_IntInterval(cy_Interval self, cy_IntInterval other, op):
+ if op == 2:
+ return deref(self.thisptr) == deref(other.thisptr)
+ elif op == 3:
+ return deref(self.thisptr) != deref(other.thisptr)
+
+ def __richcmp__(cy_Interval self, other, op):
+ """Intervals are not ordered."""
+ if isinstance(other, cy_Interval):
+ return self._cmp_Interval(other, op)
+ elif isinstance(other, cy_IntInterval):
+ return self._cmp_IntInterval(other, op)
+
+ def __neg__(self):
+ """Return interval with negated boundaries."""
+ return wrap_Interval(-deref(self.thisptr))
+
+ def _add_number(self, Coord X):
+ return wrap_Interval(deref(self.thisptr)+X)
+ def _sub_number(self, Coord X):
+ return wrap_Interval(deref(self.thisptr)-X)
+ def _mul_number(self, Coord X):
+ return wrap_Interval(deref(self.thisptr)*X)
+
+ def _add_interval(self, cy_Interval I):
+ return wrap_Interval(deref(self.thisptr)+deref(I.thisptr))
+ def _sub_interval(self, cy_Interval I):
+ return wrap_Interval(deref(self.thisptr)-deref(I.thisptr))
+ def _mul_interval(self, cy_Interval I):
+ return wrap_Interval(deref(self.thisptr)*deref(I.thisptr))
+
+ def __mul__(cy_Interval self, other):
+ """Multiply interval by interval or number.
+
+ Multiplying by number simply multiplies boundaries,
+ multiplying intervals creates all values that can be written as
+ product i*j of i in I and j in J.
+ """
+ if isinstance(other, Number):
+ return self._mul_number(float(other))
+ else:
+ return self._mul_interval(other)
+
+ def __add__(cy_Interval self, other):
+ """Add interval or value to self.
+
+ Interval I+J consists of all values i+j such that i is in I and
+ j is in J
+
+ Interval I+x consists of all values i+x such that i is in I.
+ """
+ if isinstance(other, Number):
+ return self._add_number(float(other))
+ else:
+ return self._add_interval(other)
+
+ def __sub__(cy_Interval self, other):
+ """Substract interval or value.
+
+ Interval I-J consists of all values i-j such that i is in I and
+ j is in J
+
+ Interval I-x consists of all values i-x such that i is in I.
+ """
+ if isinstance(other, Number):
+ return self._sub_number(float(other))
+ else:
+ return self._sub_interval(other)
+
+ def __div__(cy_Interval self, Coord s):
+ """Divide boundaries by number."""
+ return wrap_Interval(deref(self.thisptr)/s)
+
+ def __or__(cy_Interval self, cy_Interval I):
+ """Return union of two intervals."""
+ return wrap_Interval(deref(self.thisptr)|deref(I.thisptr))
+
+ def round_outwards(self):
+ """Create the smallest IntIterval that is superset."""
+ return wrap_IntInterval(self.thisptr.roundOutwards())
+
+ def round_inwards(self):
+ """Create the largest IntInterval that is subset."""
+ return wrap_OptIntInterval(self.thisptr.roundInwards())
+
+cdef cy_Interval wrap_Interval(Interval p):
+ cdef Interval * retp = new Interval()
+ retp[0] = p
+ cdef cy_Interval r = cy_Interval.__new__(cy_Interval)
+ r.thisptr = retp
+ return r
+
+
+cdef class cy_OptInterval:
+
+ """Class representing optionally empty interval on real line.
+
+ Empty interval has False bool value, and using methods that require
+ non-empty interval will result in ValueError. This is supposed to be
+ used this way:
+
+ >>> C = A & B
+ >>> if C:
+ >>> print C.min()
+
+ This class represents OptInterval. It tries to model behaviour of
+ std::optional.
+ """
+
+ def __cinit__(self, u = None, v = None):
+ """Create optionally empty interval form it's endpoints.
+
+ No arguments will result in empty interval.
+ """
+ if u is None:
+ self.thisptr = new OptInterval()
+ elif v is None:
+ self.thisptr = new OptInterval(<Coord>float(u))
+ else:
+ self.thisptr = new OptInterval(<Coord>float(u), <Coord>float(v))
+
+ def __bool__(self):
+ """Only empty interval is False."""
+ return not self.thisptr.isEmpty()
+
+ def __str__(self):
+ """str(self)"""
+ if not self:
+ return "[]"
+ return "[{}, {}]".format(self.Interval.min(), self.Interval.max())
+
+ def __repr__(self):
+ """repr(self)"""
+ if not self:
+ return "OptInterval()"
+ if self.Interval.isSingular():
+ return "OptInterval({})".format( str(self.Interval.min()) )
+ return "OptInterval({}, {})".format( str(self.Interval.min()) , str(self.Interval.max()) )
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_Interval(cls, i):
+ """Create interval from other (possibly empty) interval."""
+ if hasattr(i, "isEmpty"):
+ if i.isEmpty():
+ return cy_OptInterval()
+ else:
+ return cy_OptInterval.from_Interval(i.Interval)
+ return cy_OptInterval( i.min(), i.max() )
+
+ @classmethod
+ def from_list(self, lst):
+ """Create interval containing all values in list.
+
+ Empty list will result in empty interval."""
+ if len(lst) == 0:
+ return cy_OptInterval()
+ ret = cy_OptInterval(lst[0])
+ for i in lst[1:]:
+ ret.Interval.expandTo(i)
+ return ret
+
+ property Interval:
+ """Get underlying Interval."""
+ def __get__(self):
+ if self.is_empty():
+ raise ValueError("Interval is empty.")
+ else:
+ return wrap_Interval(self.thisptr.get())
+
+ def is_empty(self):
+ """Test for empty interval."""
+ return self.thisptr.isEmpty()
+
+ def union_with(self, cy_OptInterval o):
+ """self = self | other"""
+ self.thisptr.unionWith( deref(o.thisptr) )
+
+ def intersect_with(cy_OptInterval self, cy_OptInterval o):
+ """self = self & other"""
+ self.thisptr.intersectWith( deref(o.thisptr) )
+
+ def __or__(cy_OptInterval self, cy_OptInterval o):
+ """Return union of intervals."""
+ return wrap_OptInterval(deref(self.thisptr) | deref(o.thisptr))
+
+ def __and__(cy_OptInterval self, cy_OptInterval o):
+ """Return intersection of intervals."""
+ return wrap_OptInterval(deref(self.thisptr) & deref(o.thisptr))
+
+ def _get_Interval_method(self, name):
+ def f(*args, **kwargs):
+ if self.is_empty():
+ raise ValueError("OptInterval is empty.")
+ else:
+ return self.Interval.__getattribute__(name)(*args, **kwargs)
+ return f
+
+ def __getattr__(self, name):
+
+ Interval_methods = set(['contains', 'contains_interval', 'expand_by',
+ 'expand_to', 'extent', 'from_Interval', 'from_list',
+ 'interior_contains', 'interior_contains_interval',
+ 'interior_intersects', 'intersects', 'isFinite', 'is_singular',
+ 'max', 'middle', 'min', 'round_inwards', 'round_outwards',
+ 'set_max', 'set_min', 'union_with'])
+
+ if name in Interval_methods:
+ return self._get_Interval_method(name)
+ else:
+ raise AttributeError("OptInterval instance has no attribute \"{}\"".format(name))
+
+ def _wrap_Interval_method(self, name, *args, **kwargs):
+ if self.isEmpty():
+ raise ValueError("OptInterval is empty.")
+ else:
+ return self.Interval.__getattr__(name)(*args, **kwargs)
+
+ #declaring these by hand, because they take fixed number of arguments,
+ #which is enforced by cython
+
+ def __neg__(self):
+ """Return interval with negated boundaries."""
+ return self._wrap_Interval_method("__sub__")
+
+ def __mul__(cy_Interval self, other):
+ """Multiply interval by interval or number.
+
+ Multiplying by number simply multiplies boundaries,
+ multiplying intervals creates all values that can be written as
+ product i*j of i in I and j in J.
+ """
+ return self._wrap_Interval_method("__mul__", other)
+
+ def __add__(cy_Interval self, other):
+ """Add interval or value to self.
+
+ Interval I+J consists of all values i+j such that i is in I and
+ j is in J
+
+ Interval I+x consists of all values i+x such that i is in I.
+ """
+ return self._wrap_Interval_method("__add__", other)
+
+ def __sub__(cy_Interval self, other):
+ """Substract interval or value.
+
+ Interval I-J consists of all values i-j such that i is in I and
+ j is in J
+
+ Interval I-x consists of all values i-x such that i is in I.
+ """
+ return self._wrap_Interval_method("__sub__", other)
+
+ def __div__(cy_Interval self, other):
+ """Divide boundaries by number."""
+ return self._wrap_Interval_method("__div__", other)
+
+cdef cy_OptInterval wrap_OptInterval(OptInterval p):
+ cdef OptInterval * retp = new OptInterval()
+ retp[0] = p
+ cdef cy_OptInterval r = cy_OptInterval.__new__(cy_OptInterval)
+ r.thisptr = retp
+ return r
+
+
+cdef class cy_IntInterval:
+
+ """Class representing interval of integers.
+
+ Corresponds to IntInterval class in 2geom.
+ """
+
+ cdef IntInterval* thisptr
+
+ def __cinit__(self, u = None, v = None):
+ """Create interval from it's boundaries.
+
+ One argument will create interval consisting that value, no
+ arguments create IntInterval(0).
+ """
+ if u is None:
+ self.thisptr = new IntInterval()
+ elif v is None:
+ self.thisptr = new IntInterval(<IntCoord>int(u))
+ else:
+ self.thisptr = new IntInterval(<IntCoord>int(u), <IntCoord>int(v))
+
+ def __str__(self):
+ """str(self)"""
+ return "[{}, {}]".format(self.min(), self.max())
+
+ def __repr__(self):
+ """repr(self)"""
+ if self.is_singular():
+ return "IntInterval({})".format( str(self.min()) )
+ return "IntInterval({}, {})".format( str(self.min()) , str(self.max()) )
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_Interval(cls, i):
+ return cy_IntInterval( int(i.min()), int(i.max()) )
+
+ @classmethod
+ def from_list(cls, lst):
+ if len(lst) == 0:
+ return cy_IntInterval()
+ ret = cy_IntInterval(lst[0])
+ for i in lst[1:]:
+ ret.expand_to(i)
+ return ret
+
+ def min(self):
+ """Return minimal boundary."""
+ return self.thisptr.min()
+
+ def max(self):
+ """Return maximal boundary."""
+ return self.thisptr.max()
+
+ def extent(self):
+ """Return length of interval."""
+ return self.thisptr.extent()
+
+ def middle(self):
+ """Return middle value."""
+ return self.thisptr.middle()
+
+ def set_min(self, IntCoord val):
+ """Set minimal value."""
+ self.thisptr.setMin(val)
+
+ def set_max(self, IntCoord val):
+ """Set maximal value."""
+ self.thisptr.setMax(val)
+
+ def expand_to(self, IntCoord val):
+ """Set self to smallest superset of set containing value."""
+ self.thisptr.expandTo(val)
+
+ def expand_by(self, IntCoord amount):
+ """Move both boundaries by amount."""
+ self.thisptr.expandBy(amount)
+
+ def union_with(self, cy_IntInterval a):
+ """self = self | other"""
+ self.thisptr.unionWith(deref( a.thisptr ))
+
+# Not exposing this - deprecated
+# def __getitem__(self, unsigned int i):
+# return deref(self.thisptr)[i]
+
+ def is_singular(self):
+ """Test if interval contains only one value."""
+ return self.thisptr.isSingular()
+
+ def contains(cy_IntInterval self, other):
+ """Test if interval contains number."""
+ return self.thisptr.contains(<IntCoord> int(other))
+
+ def contains_interval(cy_IntInterval self, cy_IntInterval other):
+ """Test if interval contains another interval."""
+ return self.thisptr.contains( deref(other.thisptr) )
+
+ def intersects(self, cy_IntInterval val):
+ """Test for intersection with other interval."""
+ return self.thisptr.intersects(deref( val.thisptr ))
+
+ def __richcmp__(cy_IntInterval self, cy_IntInterval other, op):
+ """Intervals are not ordered."""
+ if op == 2:
+ return deref(self.thisptr) == deref(other.thisptr)
+ elif op == 3:
+ return deref(self.thisptr) != deref(other.thisptr)
+
+ def __neg__(self):
+ """Negate interval's endpoints."""
+ return wrap_IntInterval(-deref(self.thisptr))
+
+ def _add_number(self, IntCoord X):
+ return wrap_IntInterval(deref(self.thisptr)+X)
+ def _sub_number(self, IntCoord X):
+ return wrap_IntInterval(deref(self.thisptr)-X)
+
+ def _add_interval(self, cy_IntInterval I):
+ return wrap_IntInterval(deref(self.thisptr)+deref(I.thisptr))
+ def _sub_interval(self, cy_IntInterval I):
+ return wrap_IntInterval(deref(self.thisptr)-deref(I.thisptr))
+
+ def __add__(cy_IntInterval self, other):
+ """Add interval or value to self.
+
+ Interval I+J consists of all values i+j such that i is in I and
+ j is in J
+
+ Interval I+x consists of all values i+x such that i is in I.
+ """
+ if isinstance(other, Number):
+ return self._add_number(int(other))
+ else:
+ return self._add_interval(other)
+
+ def __sub__(cy_IntInterval self, other):
+ """Substract interval or value.
+
+ Interval I-J consists of all values i-j such that i is in I and
+ j is in J
+
+ Interval I-x consists of all values i-x such that i is in I.
+ """
+ if isinstance(other, Number):
+ return self._sub_number(int(other))
+ else:
+ return self._sub_interval(other)
+
+ def __or__(cy_IntInterval self, cy_IntInterval I):
+ """Return union of two intervals."""
+ return wrap_IntInterval(deref(self.thisptr)|deref(I.thisptr))
+
+cdef cy_IntInterval wrap_IntInterval(IntInterval p):
+ cdef IntInterval * retp = new IntInterval()
+ retp[0] = p
+ cdef cy_IntInterval r = cy_IntInterval.__new__(cy_IntInterval)
+ r.thisptr = retp
+ return r
+
+cdef class cy_OptIntInterval:
+
+ """Class representing optionally empty interval of integers.
+
+ Empty interval has False bool value, and using methods that require
+ non-empty interval will result in ValueError. This is supposed to be
+ used this way:
+
+ >>> C = A & B
+ >>> if C:
+ >>> print C.min()
+
+ This class represents OptIntInterval. It tries to model behaviour of
+ std::optional.
+ """
+
+ cdef OptIntInterval* thisptr
+
+ def __cinit__(self, u = None, v = None):
+ """Create optionally empty interval form it's endpoints.
+
+ No arguments will result in empty interval.
+ """
+ if u is None:
+ self.thisptr = new OptIntInterval()
+ elif v is None:
+ self.thisptr = new OptIntInterval(<IntCoord>int(u))
+ else:
+ self.thisptr = new OptIntInterval(<IntCoord>int(u), <IntCoord>int(v))
+
+ def __bool__(self):
+ """Only empty interval is False."""
+ return not self.thisptr.isEmpty()
+
+ def __str__(self):
+ """str(self)"""
+ if not self:
+ return "[]"
+ return "[{}, {}]".format(self.Interval.min(), self.Interval.max())
+
+ def __repr__(self):
+ """repr(self)"""
+ if not self:
+ return "OptIntInterval()"
+ if self.Interval.isSingular():
+ return "OptIntInterval({})".format( str(self.Interval.min()) )
+ return "OptIntInterval({}, {})".format( str(self.Interval.min()) , str(self.Interval.max()) )
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_Interval(self, i):
+ """Create interval from other (possibly empty) interval."""
+ if hasattr(i, "isEmpty"):
+ if i.isEmpty():
+ return cy_OptIntInterval()
+ else:
+ return cy_OptIntInterval.from_Interval(i.Interval)
+ return cy_OptIntInterval( i.min(), i.max() )
+
+ @classmethod
+ def from_list(self, lst):
+ """Create interval containing all values in list.
+
+ Empty list will result in empty interval."""
+ if len(lst) == 0:
+ return cy_OptIntInterval()
+ ret = cy_OptIntInterval(lst[0])
+ for i in lst[1:]:
+ ret.Interval.expandTo(i)
+ return ret
+
+ property Interval:
+ """Get underlying interval."""
+ def __get__(self):
+ return wrap_IntInterval(self.thisptr.get())
+
+ def is_empty(self):
+ """Test for empty interval."""
+ return self.thisptr.isEmpty()
+
+ def union_with(self, cy_OptIntInterval o):
+ """self = self | other"""
+ self.thisptr.unionWith( deref(o.thisptr) )
+
+ def intersect_with(cy_OptIntInterval self, cy_OptIntInterval o):
+ """self = self & other"""
+ self.thisptr.intersectWith( deref(o.thisptr) )
+
+ def __or__(cy_OptIntInterval self, cy_OptIntInterval o):
+ """Return a union of two intervals."""
+ return wrap_OptIntInterval(deref(self.thisptr) | deref(o.thisptr))
+
+ def __and__(cy_OptIntInterval self, cy_OptIntInterval o):
+ """Return an intersection of two intervals."""
+ return wrap_OptIntInterval(deref(self.thisptr) & deref(o.thisptr))
+
+ #TODO decide how to implement various combinations of comparisons!
+
+ def _get_Interval_method(self, name):
+ def f(*args, **kwargs):
+ if self.is_empty():
+ raise ValueError("OptInterval is empty.")
+ else:
+ return self.Interval.__getattribute__(name)(*args, **kwargs)
+ return f
+
+ def __getattr__(self, name):
+
+ Interval_methods = set(['contains', 'contains_interval',
+ 'expand_by', 'expand_to', 'extent', 'from_Interval', 'from_list',
+ 'intersects', 'is_singular', 'max', 'middle', 'min', 'set_max',
+ 'set_min', 'union_with'])
+
+ if name in Interval_methods:
+ return self._get_Interval_method(name)
+ else:
+ raise AttributeError("OptIntInterval instance has no attribute \"{}\"".format(name))
+
+ def _wrap_Interval_method(self, name, *args, **kwargs):
+ if self.isEmpty():
+ raise ValueError("OptIntInterval is empty.")
+ else:
+ return self.Interval.__getattr__(name)(*args, **kwargs)
+
+ #declaring these by hand, because they take fixed number of arguments,
+ #which is enforced by cython
+
+ def __neg__(self):
+ """Negate interval's endpoints."""
+ return self._wrap_Interval_method("__sub__")
+
+
+ def __add__(cy_Interval self, other):
+ """Add interval or value to self.
+
+ Interval I+J consists of all values i+j such that i is in I and
+ j is in J
+
+ Interval I+x consists of all values i+x such that i is in I.
+ """
+ return self._wrap_Interval_method("__add__", other)
+
+ def __sub__(cy_Interval self, other):
+ """Substract interval or value.
+
+ Interval I-J consists of all values i-j such that i is in I and
+ j is in J
+
+ Interval I-x consists of all values i-x such that i is in I.
+ """
+ return self._wrap_Interval_method("__sub__", other)
+
+cdef cy_OptIntInterval wrap_OptIntInterval(OptIntInterval p):
+ cdef OptIntInterval * retp = new OptIntInterval()
+ retp[0] = p
+ cdef cy_OptIntInterval r = cy_OptIntInterval.__new__(cy_OptIntInterval)
+ r.thisptr = retp
+ return r
+
+
+cdef class cy_GenericRect:
+
+ """Class representing axis aligned rectangle, with arbitrary corners.
+
+ Plane in which the rectangle lies can have any object as a coordinates,
+ as long as they implement arithmetic operations and comparison.
+
+ This is a bit experimental, corresponds to GenericRect[C] templated
+ with (wrapped) python object.
+ """
+
+ cdef GenericRect[WrappedPyObject]* thisptr
+
+ def __cinit__(self, x0=0, y0=0, x1=0, y1=0):
+ """Create rectangle from it's top-left and bottom-right corners."""
+ self.thisptr = new GenericRect[WrappedPyObject](WrappedPyObject(x0),
+ WrappedPyObject(y0),
+ WrappedPyObject(x1),
+ WrappedPyObject(y1))
+
+ def __str__(self):
+ """str(self)"""
+ return "Rectangle with dimensions {}, topleft point {}".format(
+ str(self.dimensions()),
+ str(self.min()))
+
+ def __repr__(self):
+ """repr(self)"""
+ return "Rect({}, {}, {}, {})".format( str(self.left()),
+ str(self.top()),
+ str(self.right()),
+ str(self.bottom()) )
+
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_intervals(self, I, J):
+ """Create rectangle from two intervals.
+
+ First interval corresponds to side parallel with x-axis,
+ second one with side parallel with y-axis."""
+ return cy_GenericRect(I.min(), I.max(), J.min(), J.max())
+
+ @classmethod
+ def from_list(cls, lst):
+ """Create rectangle containing all points in list.
+
+ These points are represented simply by 2-tuples.
+ """
+ ret = cy_GenericRect()
+ for a in lst:
+ ret.expand_to(a)
+ return ret
+
+ @classmethod
+ def from_xywh(cls, x, y, w, h):
+ """Create rectangle from topleft point and dimensions."""
+ return wrap_GenericRect( from_xywh(WrappedPyObject(x),
+ WrappedPyObject(y),
+ WrappedPyObject(w),
+ WrappedPyObject(h)))
+
+ def __getitem__(self, Dim2 d):
+ """self[i]"""
+ return wrap_GenericInterval( deref(self.thisptr)[d] )
+
+ def min(self):
+ """Get top-left point."""
+ return wrap_PyPoint( self.thisptr.min() )
+
+ def max(self):
+ """Get bottom-right point."""
+ return wrap_PyPoint( self.thisptr.max() )
+
+ def corner(self, unsigned int i):
+ """Get corners (modulo) indexed from 0 to 3."""
+ return wrap_PyPoint( self.thisptr.corner(i) )
+
+ def top(self):
+ """Get top coordinate."""
+ return self.thisptr.top().getObj()
+
+ def bottom(self):
+ """Get bottom coordinate."""
+ return self.thisptr.bottom().getObj()
+
+ def left(self):
+ """Get left coordinate."""
+ return self.thisptr.left().getObj()
+
+ def right(self):
+ """Get right coordinate."""
+ return self.thisptr.right().getObj()
+
+ def width(self):
+ """Get width."""
+ return self.thisptr.width().getObj()
+
+ def height(self):
+ """Get height."""
+ return self.thisptr.height().getObj()
+
+ #For some reason, Cpp aspectRatio returns Coord.
+ def aspectRatio(self):
+ """Get ratio between width and height."""
+ return float(self.width())/float(self.height())
+
+ def dimensions(self):
+ """Get dimensions as tuple."""
+ return wrap_PyPoint( self.thisptr.dimensions() )
+
+ def midpoint(self):
+ """Get midpoint as tuple."""
+ return wrap_PyPoint( self.thisptr.midpoint() )
+
+ def area(self):
+ """Get area."""
+ return self.thisptr.area().getObj()
+
+ def has_zero_area(self):
+ """Test for area being zero."""
+ return self.thisptr.hasZeroArea()
+
+ def max_extent(self):
+ """Get bigger value from width, height."""
+ return self.thisptr.maxExtent().getObj()
+
+ def min_extent(self):
+ """Get smaller value from width, height."""
+ return self.thisptr.minExtent().getObj()
+
+ def intersects(self, cy_GenericRect r):
+ """Check if rectangle intersects another rectangle."""
+ return self.thisptr.intersects(deref( r.thisptr ))
+
+ def contains(self, r):
+ """Check if rectangle contains point represented as tuple."""
+ if not isinstance(r, tuple):
+ raise TypeError("Tuple required to create point.")
+ return self.thisptr.contains( make_PyPoint(r) )
+
+ def contains_rect(self, cy_GenericRect r):
+ """Check if rectangle contains another rect."""
+ return self.thisptr.contains( deref(r.thisptr) )
+
+ def set_left(self, val):
+ """Set left coordinate."""
+ self.thisptr.setLeft( WrappedPyObject(val) )
+
+ def set_right(self, val):
+ """Set right coordinate."""
+ self.thisptr.setRight( WrappedPyObject(val) )
+
+ def set_top(self, val):
+ """Set top coordinate."""
+ self.thisptr.setTop( WrappedPyObject(val) )
+
+ def set_bottom(self, val):
+ """Set bottom coordinate."""
+ self.thisptr.setBottom( WrappedPyObject(val) )
+
+ def set_min(self, p):
+ """Set top-left point."""
+ self.thisptr.setMin(make_PyPoint(p))
+
+ def set_max(self, p):
+ """Set bottom-right point."""
+ self.thisptr.setMax(make_PyPoint(p))
+
+ def expand_to(self, p):
+ """Expand rectangle to contain point represented as tuple."""
+ self.thisptr.expandTo(make_PyPoint(p))
+
+ def union_with(self, cy_GenericRect b):
+ """self = self | other."""
+ self.thisptr.unionWith(deref( b.thisptr ))
+
+ def expand_by(self, x, y = None):
+ """Expand both intervals.
+
+ Either expand them both by one value, or each by different value.
+ """
+ if y is None:
+ self.thisptr.expandBy(WrappedPyObject(x))
+ else:
+ self.thisptr.expandBy(WrappedPyObject(x),
+ WrappedPyObject(y))
+
+
+ def __add__(cy_GenericRect self, p):
+ """Offset rectangle by point."""
+ return wrap_GenericRect( deref(self.thisptr) + make_PyPoint(p) )
+
+ def __sub__(cy_GenericRect self, p):
+ """Offset rectangle by -point."""
+ return wrap_GenericRect( deref(self.thisptr) - make_PyPoint(p) )
+
+ def __or__(cy_GenericRect self, cy_GenericRect o):
+ """Return union of two rects - it's actually bounding rect of union."""
+ return wrap_GenericRect( deref(self.thisptr) | deref( o.thisptr ))
+
+ def __richcmp__(cy_GenericRect self, cy_GenericRect o, int op):
+ """Rectangles are not ordered."""
+ if op == 2:
+ return deref(self.thisptr) == deref(o.thisptr)
+ if op == 3:
+ return deref(self.thisptr) != deref(o.thisptr)
+
+cdef PyPoint make_PyPoint(p):
+ return PyPoint( WrappedPyObject(p[0]), WrappedPyObject(p[1]) )
+
+#D2[WrappedPyObject] is converted to tuple
+cdef wrap_PyPoint(PyPoint p):
+ return (p[0].getObj(), p[1].getObj())
+
+cdef cy_GenericRect wrap_GenericRect(GenericRect[WrappedPyObject] p):
+ cdef WrappedPyObject zero = WrappedPyObject(0)
+ cdef GenericRect[WrappedPyObject] * retp = new GenericRect[WrappedPyObject](zero, zero, zero, zero)
+ retp[0] = p
+ cdef cy_GenericRect r = cy_GenericRect.__new__(cy_GenericRect)
+ r.thisptr = retp
+ return r
+
+
+cdef class cy_Rect:
+
+ """Class representing axis-aligned rectangle in 2D real plane.
+
+ Corresponds to Rect class in 2geom."""
+
+ def __cinit__(self, Coord x0=0, Coord y0=0, Coord x1=0, Coord y1=0):
+ """Create Rect from coordinates of its top-left and bottom-right corners."""
+ self.thisptr = new Rect(x0, y0, x1, y1)
+
+ def __str__(self):
+ """str(self)"""
+ return "Rectangle with dimensions {}, topleft point {}".format(str(self.dimensions()), str(self.min()))
+
+ def __repr__(self):
+ """repr(self)"""
+ return "Rect({}, {}, {}, {})".format( str(self.left()),
+ str(self.top()),
+ str(self.right()),
+ str(self.bottom()))
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_points(cls, cy_Point p0, cy_Point p1):
+ """Create rectangle from it's top-left and bottom-right corners."""
+ return wrap_Rect( Rect(deref(p0.thisptr), deref(p1.thisptr)) )
+
+ @classmethod
+ def from_intervals(cls, I, J):
+ """Create rectangle from two intervals representing its sides."""
+ return wrap_Rect( Rect( float(I.min()),
+ float(J.min()),
+ float(I.max()),
+ float(J.max()) ) )
+
+ @classmethod
+ def from_list(cls, lst):
+ """Create rectangle containing all points in list."""
+ if lst == []:
+ return cy_Rect()
+ if len(lst) == 1:
+ return cy_Rect.from_points(lst[0], lst[0])
+ ret = cy_Rect.from_points(lst[0], lst[1])
+ for a in lst:
+ ret.expand_to(a)
+ return ret
+
+ @classmethod
+ def from_xywh(cls, x, y, w, h):
+ """Create rectangle from it's topleft point and dimensions."""
+ return wrap_Rect( from_xywh(<Coord> x,
+ <Coord> y,
+ <Coord> w,
+ <Coord> h) )
+
+ @classmethod
+ def infinite(self):
+ """Create infinite rectangle."""
+ return wrap_Rect(infinite())
+
+ def __getitem__(self, Dim2 d):
+ """self[d]"""
+ return wrap_Interval( deref(self.thisptr)[d] )
+
+ def min(self):
+ """Get top-left point."""
+ return wrap_Point( self.thisptr.min() )
+
+ def max(self):
+ """Get bottom-right point."""
+ return wrap_Point( self.thisptr.max() )
+
+ def corner(self, unsigned int i):
+ """Get corners (modulo) indexed from 0 to 3."""
+ return wrap_Point( self.thisptr.corner(i) )
+
+ def top(self):
+ """Get top coordinate."""
+ return self.thisptr.top()
+
+ def bottom(self):
+ """Get bottom coordinate."""
+ return self.thisptr.bottom()
+
+ def left(self):
+ """Get left coordinate."""
+ return self.thisptr.left()
+
+ def right(self):
+ """Get right coordinate."""
+ return self.thisptr.right()
+
+ def width(self):
+ """Get width."""
+ return self.thisptr.width()
+
+ def height(self):
+ """Get height."""
+ return self.thisptr.height()
+
+ def aspect_ratio(self):
+ """Get ratio between width and height."""
+ return self.thisptr.aspectRatio()
+
+ def dimensions(self):
+ """Get dimensions as point."""
+ return wrap_Point( self.thisptr.dimensions() )
+
+ def midpoint(self):
+ """Get midpoint."""
+ return wrap_Point( self.thisptr.midpoint() )
+
+ def area(self):
+ """Get area."""
+ return self.thisptr.area()
+
+ def has_zero_area(self, Coord eps = EPSILON):
+ """Test for area being zero."""
+ return self.thisptr.hasZeroArea(eps)
+
+ def max_extent(self):
+ """Get bigger value from width, height."""
+ return self.thisptr.maxExtent()
+
+ def min_extent(self):
+ """Get smaller value from width, height."""
+ return self.thisptr.minExtent()
+
+ def intersects(self, cy_Rect r):
+ """Check if rectangle intersects another rectangle."""
+ return self.thisptr.intersects(deref( r.thisptr ))
+
+ def contains(self, cy_Point r):
+ """Check if rectangle contains point."""
+ return self.thisptr.contains( deref(r.thisptr) )
+
+ def contains_rect(self, cy_Rect r):
+ """Check if rectangle contains another rect."""
+ return self.thisptr.contains( deref(r.thisptr) )
+
+ def interior_intersects(self, cy_Rect r):
+ """Check if interior of self intersects another rectangle."""
+ return self.thisptr.interiorIntersects(deref( r.thisptr ))
+
+ def interior_contains(self, cy_Point other):
+ """Check if interior of self contains point."""
+ return self.thisptr.interiorContains( deref( (<cy_Point> other).thisptr ) )
+
+ def interior_contains_rect(self, other):
+ """Check if interior of self contains another rectangle."""
+ if isinstance(other, cy_Rect):
+ return self.thisptr.interiorContains( deref( (<cy_Rect> other).thisptr ) )
+ elif isinstance(other, cy_OptRect):
+ return self.thisptr.interiorContains( deref( (<cy_OptRect> other).thisptr ) )
+
+ def set_left(self, Coord val):
+ """Set left coordinate."""
+ self.thisptr.setLeft(val)
+
+ def set_right(self, Coord val):
+ """Set right coordinate."""
+ self.thisptr.setRight(val)
+
+ def set_top(self, Coord val):
+ """Set top coordinate."""
+ self.thisptr.setTop(val)
+
+ def set_bottom(self, Coord val):
+ """Set bottom coordinate."""
+ self.thisptr.setBottom(val)
+
+ def set_min(self, cy_Point p):
+ """Set top-left point."""
+ self.thisptr.setMin( deref( p.thisptr ) )
+
+ def set_max(self, cy_Point p):
+ """Set bottom-right point."""
+ self.thisptr.setMax( deref( p.thisptr ))
+
+ def expand_to(self, cy_Point p):
+ """Expand rectangle to contain point represented as tuple."""
+ self.thisptr.expandTo( deref( p.thisptr ) )
+
+ def union_with(self, cy_Rect b):
+ """self = self | other."""
+ self.thisptr.unionWith(deref( b.thisptr ))
+
+ def expand_by(cy_Rect self, x, y = None):
+ """Expand both intervals.
+
+ Either expand them both by one value, or each by different value.
+ """
+ if y is None:
+ if isinstance(x, cy_Point):
+ self.thisptr.expandBy( deref( (<cy_Point> x).thisptr ) )
+ else:
+ self.thisptr.expandBy( <Coord> x)
+ else:
+ self.thisptr.expandBy( <Coord> x,
+ <Coord> y)
+
+ def __add__(cy_Rect self, cy_Point p):
+ """Offset rectangle by point."""
+ return wrap_Rect( deref(self.thisptr) + deref( p.thisptr ) )
+
+ def __sub__(cy_Rect self, cy_Point p):
+ """Offset rectangle by -point."""
+ return wrap_Rect( deref(self.thisptr) - deref( p.thisptr ) )
+
+ def __mul__(cy_Rect self, t):
+ """Apply transform to rectangle."""
+ cdef Affine at
+ if is_transform(t):
+ at = get_Affine(t)
+ return wrap_Rect( deref(self.thisptr) * at )
+
+ def __or__(cy_Rect self, cy_Rect o):
+ """Return union of two rects - it's actually bounding rect of union."""
+ return wrap_Rect( deref(self.thisptr) | deref( o.thisptr ))
+
+ def __richcmp__(cy_Rect self, o, int op):
+ """Rectangles are not ordered."""
+ if op == 2:
+ if isinstance(o, cy_Rect):
+ return deref(self.thisptr) == deref( (<cy_Rect> o).thisptr)
+ elif isinstance(o, cy_IntRect):
+ return deref(self.thisptr) == deref( (<cy_IntRect> o).thisptr)
+ if op == 3:
+ if isinstance(o, cy_Rect):
+ return deref(self.thisptr) != deref( (<cy_Rect> o).thisptr)
+ elif isinstance(o, cy_IntRect):
+ return deref(self.thisptr) != deref( (<cy_IntRect> o).thisptr)
+
+ def round_inwards(self):
+ """Create OptIntRect rounding inwards."""
+ return wrap_OptIntRect(self.thisptr.roundInwards())
+
+ def round_outwards(self):
+ """Create IntRect rounding outwards."""
+ return wrap_IntRect(self.thisptr.roundOutwards())
+
+ @classmethod
+ def distanceSq(cls, cy_Point p, cy_Rect rect):
+ """Compute square of distance between point and rectangle."""
+ return distanceSq( deref(p.thisptr), deref(rect.thisptr) )
+
+ @classmethod
+ def distance(cls, cy_Point p, cy_Rect rect):
+ """Compute distance between point and rectangle."""
+ return distance( deref(p.thisptr), deref(rect.thisptr) )
+
+cdef cy_Rect wrap_Rect(Rect p):
+ cdef Rect* retp = new Rect()
+ retp[0] = p
+ cdef cy_Rect r = cy_Rect.__new__(cy_Rect)
+ r.thisptr = retp
+ return r
+
+
+cdef class cy_OptRect:
+
+ """Class representing optionally empty rect in real plane.
+
+ This class corresponds to OptRect in 2geom, and it tries to mimic
+ the behaviour of std::optional. In addition to OptRect methods,
+ this class passes calls for Rect methods to underlying Rect class,
+ or throws ValueError when it's empty.
+ """
+
+ def __cinit__(self, x0=None, y0=None, x1=None, y1=None):
+ """Create OptRect from coordinates of top-left and bottom-right corners.
+
+ No arguments will result in empty rectangle.
+ """
+ if x0 is None:
+ self.thisptr = new OptRect()
+ else:
+ self.thisptr = new OptRect( float(x0),
+ float(y0),
+ float(x1),
+ float(y1) )
+
+ def __str__(self):
+ """str(self)"""
+ if self.is_empty():
+ return "Empty OptRect."
+ return "OptRect with dimensions {}, topleft point {}".format(str(self.dimensions()), str(self.min()))
+
+ def __repr__(self):
+ """repr(self)"""
+ if self.is_empty():
+ return "OptRect()"
+ return "OptRect({}, {}, {}, {})".format( str(self.left()),
+ str(self.top()),
+ str(self.right()),
+ str(self.bottom()))
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_points(cls, cy_Point p0, cy_Point p1):
+ """Create rectangle from it's top-left and bottom-right corners."""
+ return wrap_OptRect( OptRect(deref(p0.thisptr), deref(p1.thisptr)) )
+
+ @classmethod
+ def from_intervals(cls, I, J):
+ """Create rectangle from two intervals representing its sides."""
+ if hasattr(I, "isEmpty"):
+ if I.isEmpty():
+ return cy_OptRect()
+
+ if hasattr(J, "isEmpty"):
+ if J.isEmpty():
+ return cy_OptRect()
+
+ return wrap_OptRect( OptRect( float(I.min()),
+ float(J.min()),
+ float(I.max()),
+ float(J.max()) ) )
+
+ @classmethod
+ def from_rect(cls, r):
+ """Create OptRect from other, possibly empty, rectangle."""
+ if hasattr(r, "isEmpty"):
+ if r.isEmpty():
+ return cy_OptRect()
+
+ return cy_OptRect( r.min().x,
+ r.min().y,
+ r.max().x,
+ r.max().y )
+
+ @classmethod
+ def from_list(cls, lst):
+ """Create OptRect containing all points in the list.
+
+ Empty list will result in empty OptRect.
+ """
+ if lst == []:
+ return cy_OptRect()
+ if len(lst) == 1:
+ return cy_OptRect.from_points(lst[0], lst[0])
+ ret = cy_OptRect.from_points(lst[0], lst[1])
+ for a in lst:
+ ret.expand_to(a)
+ return ret
+
+ property Rect:
+ """Get underlying Rect."""
+ def __get__(self):
+ if self.is_empty():
+ raise ValueError("Rect is empty.")
+ else:
+ return wrap_Rect(self.thisptr.get())
+
+ def __bool__(self):
+ """OptRect is False only when it's empty."""
+ return not self.thisptr.isEmpty()
+
+ def is_empty(self):
+ """Check for OptRect containing no points."""
+ return self.thisptr.isEmpty()
+
+ def intersects(self, other):
+ """Check if rectangle intersects another rectangle."""
+ if isinstance(other, cy_Rect):
+ return self.thisptr.intersects( deref( (<cy_Rect> other).thisptr ) )
+ elif isinstance(other, cy_OptRect):
+ return self.thisptr.intersects( deref( (<cy_OptRect> other).thisptr ) )
+
+ def contains(self, cy_Point r):
+ """Check if rectangle contains point."""
+ return self.thisptr.contains( deref(r.thisptr) )
+
+ def contains_rect(self, other):
+ """Check if rectangle contains another rect."""
+ if isinstance(other, cy_Rect):
+ return self.thisptr.contains( deref( (<cy_Rect> other).thisptr ) )
+ elif isinstance(other, cy_OptRect):
+ return self.thisptr.contains( deref( (<cy_OptRect> other).thisptr ) )
+
+ def union_with(self, other):
+ """self = self | other."""
+ if isinstance(other, cy_Rect):
+ self.thisptr.unionWith( deref( (<cy_Rect> other).thisptr ) )
+ elif isinstance(other, cy_OptRect):
+ self.thisptr.unionWith( deref( (<cy_OptRect> other).thisptr ) )
+
+ def intersect_with(self, other):
+ """self = self & other."""
+ if isinstance(other, cy_Rect):
+ self.thisptr.intersectWith( deref( (<cy_Rect> other).thisptr ) )
+ elif isinstance(other, cy_OptRect):
+ self.thisptr.intersectWith( deref( (<cy_OptRect> other).thisptr ) )
+
+ def expand_to(self, cy_Point p):
+ """Expand rectangle to contain point represented as tuple."""
+ self.thisptr.expandTo( deref(p.thisptr) )
+
+ def __or__(cy_OptRect self, cy_OptRect other):
+ """Return union of two rects - it's actually bounding rect of union."""
+ return wrap_OptRect( deref(self.thisptr) | deref(other.thisptr) )
+
+ def __and__(cy_OptRect self, other):
+ """Return intersection of two rectangles."""
+ if isinstance(other, cy_Rect):
+ return wrap_OptRect( deref(self.thisptr) & deref( (<cy_Rect> other).thisptr) )
+ elif isinstance(other, cy_OptRect):
+ return wrap_OptRect( deref(self.thisptr) & deref( (<cy_OptRect> other).thisptr) )
+
+ def __richcmp__(cy_OptRect self, other, op):
+ """Rectangles are not ordered."""
+ if op == 2:
+ if isinstance(other, cy_Rect):
+ return deref(self.thisptr) == deref( (<cy_Rect> other).thisptr )
+ elif isinstance(other, cy_OptRect):
+ return deref(self.thisptr) == deref( (<cy_OptRect> other).thisptr )
+ elif op == 3:
+ if isinstance(other, cy_Rect):
+ return deref(self.thisptr) != deref( (<cy_Rect> other).thisptr )
+ elif isinstance(other, cy_OptRect):
+ return deref(self.thisptr) != deref( (<cy_OptRect> other).thisptr )
+ return NotImplemented
+
+ def _get_Rect_method(self, name):
+ def f(*args, **kwargs):
+ if self.is_empty():
+ raise ValueError("OptRect is empty.")
+ else:
+ return self.Rect.__getattribute__(name)(*args, **kwargs)
+ return f
+
+ def __getattr__(self, name):
+ Rect_methods = set(['area', 'aspectRatio', 'bottom', 'contains',
+ 'contains_rect', 'corner', 'dimensions', 'distance', 'distanceSq',
+ 'expand_by', 'expand_to', 'has_zero_area', 'height', 'infinite',
+ 'interior_contains', 'interior_contains_rect',
+ 'interior_intersects', 'intersects', 'left', 'max', 'max_extent',
+ 'midpoint', 'min', 'min_extent', 'right', 'round_inwards',
+ 'round_outwards', 'set_bottom', 'set_left', 'set_max', 'set_min',
+ 'set_right', 'set_top', 'top', 'union_with', 'width'])
+
+ if name in Rect_methods:
+ return self._get_Rect_method(name)
+ else:
+ raise AttributeError("OptRect instance has no attribute \"{}\"".format(name))
+
+ def _wrap_Rect_method(self, name, *args, **kwargs):
+ if self.isEmpty():
+ raise ValueError("OptRect is empty.")
+ else:
+ return self.Rect.__getattr__(name)(*args, **kwargs)
+
+ #declaring these by hand, because they take fixed number of arguments,
+ #which is enforced by cython
+
+ def __getitem__(self, i):
+ """self[d]"""
+ return self._wrap_Rect_method("__getitem__", i)
+
+ def __add__(self, other):
+ """Offset rectangle by point."""
+ return self._wrap_Rect_method("__add__", other)
+
+ def __mul__(self, other):
+ """Apply transform to rectangle."""
+ return self._wrap_Rect_method("__mul__", other)
+
+ def __sub__(self, other):
+ """Offset rectangle by -point."""
+ return self._wrap_Rect_method("__sub__", other)
+
+
+cdef cy_OptRect wrap_OptRect(OptRect p):
+ cdef OptRect* retp = new OptRect()
+ retp[0] = p
+ cdef cy_OptRect r = cy_OptRect.__new__(cy_OptRect)
+ r.thisptr = retp
+ return r
+
+
+
+cdef class cy_IntRect:
+
+ """Class representing axis-aligned rectangle in 2D with integer coordinates.
+
+ Corresponds to IntRect class (typedef) in 2geom."""
+
+ cdef IntRect* thisptr
+
+ def __cinit__(self, IntCoord x0=0, IntCoord y0=0, IntCoord x1=0, IntCoord y1=0):
+ """Create IntRect from coordinates of its top-left and bottom-right corners."""
+ self.thisptr = new IntRect(x0, y0, x1, y1)
+
+ def __str__(self):
+ """str(self)"""
+ return "IntRect with dimensions {}, topleft point {}".format(
+ str(self.dimensions()),
+ str(self.min()))
+
+ def __repr__(self):
+ """repr(self)"""
+ return "IntRect({}, {}, {}, {})".format( str(self.left()),
+ str(self.top()),
+ str(self.right()),
+ str(self.bottom()))
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_points(cls, cy_IntPoint p0, cy_IntPoint p1):
+ """Create rectangle from it's top-left and bottom-right corners."""
+ return wrap_IntRect( IntRect(deref(p0.thisptr), deref(p1.thisptr)) )
+
+ @classmethod
+ def from_intervals(cls, I, J):
+ """Create rectangle from two intervals representing its sides."""
+ return cy_IntRect( int(I.min()),
+ int(J.min()),
+ int(I.max()),
+ int(J.max()) )
+
+ @classmethod
+ def from_list(cls, lst):
+ """Create rectangle containing all points in list."""
+ if lst == []:
+ return cy_IntRect()
+ if len(lst) == 1:
+ return cy_IntRect(lst[0], lst[0])
+ ret = cy_IntRect(lst[0], lst[1])
+ for a in lst:
+ ret.expand_to(a)
+ return ret
+
+ #didn't manage to declare from_xywh for IntRect
+ @classmethod
+ def from_xywh(cls, x, y, w, h):
+ """Create rectangle from it's topleft point and dimensions."""
+ return cy_IntRect(int(x),
+ int(y),
+ int(x) + int(w),
+ int(y) + int(h) )
+
+ def __getitem__(self, Dim2 d):
+ """self[d]"""
+ return wrap_IntInterval( deref(self.thisptr)[d] )
+
+ def min(self):
+ """Get top-left point."""
+ return wrap_IntPoint( self.thisptr.i_min() )
+
+ def max(self):
+ """Get bottom-right point."""
+ return wrap_IntPoint( self.thisptr.i_max() )
+
+ def corner(self, unsigned int i):
+ """Get corners (modulo) indexed from 0 to 3."""
+ return wrap_IntPoint( self.thisptr.i_corner(i) )
+
+ def top(self):
+ """Get top coordinate."""
+ return self.thisptr.top()
+
+ def bottom(self):
+ """Get bottom coordinate."""
+ return self.thisptr.bottom()
+
+ def left(self):
+ """Get left coordinate."""
+ return self.thisptr.left()
+
+ def right(self):
+ """Get right coordinate."""
+ return self.thisptr.right()
+
+ def width(self):
+ """Get width."""
+ return self.thisptr.width()
+
+ def height(self):
+ """Get height."""
+ return self.thisptr.height()
+
+ def aspect_ratio(self):
+ """Get ratio between width and height."""
+ return self.thisptr.aspectRatio()
+
+ def dimensions(self):
+ """Get dimensions as IntPoint."""
+ return wrap_IntPoint( self.thisptr.i_dimensions() )
+
+ def midpoint(self):
+ """Get midpoint."""
+ return wrap_IntPoint( self.thisptr.i_midpoint() )
+
+ def area(self):
+ """Get area."""
+ return self.thisptr.area()
+
+ def has_zero_area(self):
+ """Test for area being zero."""
+ return self.thisptr.hasZeroArea()
+
+ def max_extent(self):
+ """Get bigger value from width, height."""
+ return self.thisptr.maxExtent()
+
+ def min_extent(self):
+ """Get smaller value from width, height."""
+ return self.thisptr.minExtent()
+
+ def intersects(self, cy_IntRect r):
+ """Check if rectangle intersects another rectangle."""
+ return self.thisptr.intersects(deref( r.thisptr ))
+
+ def contains(self, cy_IntPoint r):
+ """Check if rectangle contains point."""
+ return self.thisptr.contains( deref(r.thisptr) )
+
+ def contains_rect(self, cy_IntRect r):
+ """Check if rectangle contains another rect."""
+ return self.thisptr.contains( deref(r.thisptr) )
+
+ def set_left(self, IntCoord val):
+ """Set left coordinate."""
+ self.thisptr.setLeft(val)
+
+ def set_right(self, IntCoord val):
+ """Set right coordinate."""
+ self.thisptr.setRight(val)
+
+ def set_top(self, IntCoord val):
+ """Set top coordinate."""
+ self.thisptr.setTop(val)
+
+ def set_bottom(self, IntCoord val):
+ """Set bottom coordinate."""
+ self.thisptr.setBottom(val)
+
+ def set_min(self, cy_IntPoint p):
+ """Set top-left point."""
+ self.thisptr.setMin( deref( p.thisptr ) )
+
+ def set_max(self, cy_IntPoint p):
+ """Set bottom-right point."""
+ self.thisptr.setMax( deref( p.thisptr ))
+
+ def expand_to(self, cy_IntPoint p):
+ """Expand rectangle to contain point represented as tuple."""
+ self.thisptr.expandTo( deref( p.thisptr ) )
+
+ def union_with(self, cy_IntRect b):
+ """self = self | other."""
+ self.thisptr.unionWith(deref( b.thisptr ))
+
+ def expand_by(cy_IntRect self, x, y = None):
+ """Expand both intervals.
+
+ Either expand them both by one value, or each by different value.
+ """
+ if y is None:
+ if isinstance(x, cy_IntPoint):
+ self.thisptr.expandBy( deref( (<cy_IntPoint> x).thisptr ) )
+ else:
+ self.thisptr.expandBy( <IntCoord> x)
+ else:
+ self.thisptr.expandBy( <IntCoord> x,
+ <IntCoord> y)
+
+ def __add__(cy_IntRect self, cy_IntPoint p):
+ """Offset rectangle by point."""
+ return wrap_IntRect( deref(self.thisptr) + deref( p.thisptr ) )
+
+ def __sub__(cy_IntRect self, cy_IntPoint p):
+ """Offset rectangle by -point."""
+ return wrap_IntRect( deref(self.thisptr) - deref( p.thisptr ) )
+
+ def __or__(cy_IntRect self, cy_IntRect o):
+ """Return union of two rects - it's actually bounding rect of union."""
+ return wrap_IntRect( deref(self.thisptr) | deref( o.thisptr ))
+
+ def __richcmp__(cy_IntRect self, cy_IntRect o, int op):
+ """Rectangles are not ordered."""
+ if op == 2:
+ return deref(self.thisptr) == deref(o.thisptr)
+ if op == 3:
+ return deref(self.thisptr) != deref(o.thisptr)
+
+cdef cy_IntRect wrap_IntRect(IntRect p):
+ cdef IntRect* retp = new IntRect()
+ retp[0] = p
+ cdef cy_IntRect r = cy_IntRect.__new__(cy_IntRect)
+ r.thisptr = retp
+ return r
+
+
+
+cdef class cy_OptIntRect:
+
+ """Class representing optionally empty rect in with integer coordinates.
+
+ This class corresponds to OptIntRect in 2geom, and it tries to mimic
+ the behaviour of std::optional. In addition to OptIntRect methods,
+ this class passes calls for IntRect methods to underlying IntRect class,
+ or throws ValueError when it's empty.
+ """
+
+ cdef OptIntRect* thisptr
+
+ def __cinit__(self, x0=None, y0=None, x1=None, y1=None):
+ """Create OptIntRect from coordinates of top-left and bottom-right corners.
+
+ No arguments will result in empty rectangle.
+ """
+ if x0 is None:
+ self.thisptr = new OptIntRect()
+ else:
+ self.thisptr = new OptIntRect( int(x0),
+ int(y0),
+ int(x1),
+ int(y1) )
+
+ def __str__(self):
+ """str(self)"""
+ if self.isEmpty():
+ return "Empty OptIntRect"
+ return "OptIntRect with dimensions {}, topleft point {}".format(
+ str(self.Rect.dimensions()),
+ str(self.Rect.min()))
+
+ def __repr__(self):
+ """repr(self)"""
+ if self.isEmpty():
+ return "OptIntRect()"
+ return "OptIntRect({}, {}, {}, {})".format( str(self.Rect.left()),
+ str(self.Rect.top()),
+ str(self.Rect.right()),
+ str(self.Rect.bottom()))
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ @classmethod
+ def from_points(cls, cy_IntPoint p0, cy_IntPoint p1):
+ """Create rectangle from it's top-left and bottom-right corners."""
+ return wrap_OptIntRect( OptIntRect(deref(p0.thisptr), deref(p1.thisptr)) )
+
+ @classmethod
+ def from_intervals(cls, I, J):
+ """Create rectangle from two intervals representing its sides."""
+ if hasattr(I, "isEmpty"):
+ if I.isEmpty():
+ return cy_OptIntRect()
+
+ if hasattr(J, "isEmpty"):
+ if J.isEmpty():
+ return cy_OptIntRect()
+
+ return wrap_OptIntRect( OptIntRect( int(I.min()),
+ int(J.min()),
+ int(I.max()),
+ int(J.max()) ) )
+
+ @classmethod
+ def from_rect(cls, r):
+ """Create OptIntRect from other, possibly empty, rectangle."""
+ if hasattr(r, "isEmpty"):
+ if r.isEmpty():
+ return cy_OptIntRect()
+ return cy_OptIntRect( r.min().x,
+ r.min().y,
+ r.max().x,
+ r.max().y )
+
+ @classmethod
+ def from_list(cls, lst):
+ """Create OptIntRect containing all points in the list.
+
+ Empty list will result in empty OptIntRect.
+ """
+ if lst == []:
+ return cy_OptIntRect()
+ if len(lst) == 1:
+ return cy_OptIntRect.from_points(lst[0], lst[0])
+ ret = cy_OptIntRect.from_points(lst[0], lst[1])
+ for a in lst:
+ ret.expand_to(a)
+ return ret
+
+ property Rect:
+ """Get underlying IntRect."""
+ def __get__(self):
+ return wrap_IntRect(self.thisptr.get())
+
+ def __bool__(self):
+ """OptIntRect is False only when it's empty."""
+ return not self.thisptr.isEmpty()
+
+ def is_empty(self):
+ """Check for OptIntRect containing no points."""
+ return self.thisptr.isEmpty()
+
+ def intersects(cy_OptIntRect self, other):
+ """Check if rectangle intersects another rectangle."""
+ if isinstance(other, cy_IntRect):
+ return self.thisptr.intersects( deref( (<cy_IntRect> other).thisptr ) )
+ elif isinstance(other, cy_OptIntRect):
+ return self.thisptr.intersects( deref( (<cy_OptIntRect> other).thisptr ) )
+
+ def contains(self, cy_IntPoint other):
+ """Check if rectangle contains point."""
+ return self.thisptr.contains( deref(other.thisptr) )
+
+ def contains_rect(cy_OptIntRect self, other):
+ """Check if rectangle contains another rectangle."""
+ if isinstance(other, cy_IntRect):
+ return self.thisptr.contains( deref( (<cy_IntRect> other).thisptr ) )
+ elif isinstance(other, cy_OptIntRect):
+ return self.thisptr.contains( deref( (<cy_OptIntRect> other).thisptr ) )
+
+
+ def union_with(cy_OptIntRect self, other):
+ """self = self | other."""
+ if isinstance(other, cy_IntRect):
+ self.thisptr.unionWith( deref( (<cy_IntRect> other).thisptr ) )
+ elif isinstance(other, cy_OptIntRect):
+ self.thisptr.unionWith( deref( (<cy_OptIntRect> other).thisptr ) )
+
+ def intersect_with(cy_OptIntRect self, other):
+ """self = self & other."""
+ if isinstance(other, cy_IntRect):
+ self.thisptr.intersectWith( deref( (<cy_IntRect> other).thisptr ) )
+ elif isinstance(other, cy_OptIntRect):
+ self.thisptr.intersectWith( deref( (<cy_OptIntRect> other).thisptr ) )
+
+ def expand_to(self, cy_IntPoint p):
+ """Expand rectangle to contain point."""
+ self.thisptr.expandTo( deref(p.thisptr) )
+
+ def __or__(cy_OptIntRect self, cy_OptIntRect other):
+ """Return union of two rects - it's actually bounding rect of union."""
+ return wrap_OptIntRect( deref(self.thisptr) | deref(other.thisptr) )
+
+ def __and__(cy_OptIntRect self, other):
+ """Return intersection of two rectangles."""
+ if isinstance(other, cy_IntRect):
+ return wrap_OptIntRect( deref(self.thisptr) & deref( (<cy_IntRect> other).thisptr) )
+ elif isinstance(other, cy_OptIntRect):
+ return wrap_OptIntRect( deref(self.thisptr) & deref( (<cy_OptIntRect> other).thisptr) )
+
+ def __richcmp__(cy_OptIntRect self, other, op):
+ """Rectangles are not ordered."""
+ if op == 2:
+ if isinstance(other, cy_IntRect):
+ return deref(self.thisptr) == deref( (<cy_IntRect> other).thisptr )
+ elif isinstance(other, cy_OptIntRect):
+ return deref(self.thisptr) == deref( (<cy_OptIntRect> other).thisptr )
+ elif op == 3:
+ if isinstance(other, cy_IntRect):
+ return deref(self.thisptr) != deref( (<cy_IntRect> other).thisptr )
+ elif isinstance(other, cy_OptIntRect):
+ return deref(self.thisptr) != deref( (<cy_OptIntRect> other).thisptr )
+
+ def _get_Rect_method(self, name):
+ def f(*args, **kwargs):
+ if self.is_empty():
+ raise ValueError("OptIntRect is empty.")
+ else:
+ return self.Rect.__getattribute__(name)(*args, **kwargs)
+ return f
+
+ def __getattr__(self, name):
+
+ Rect_methods = set(['area', 'aspect_ratio', 'bottom', 'contains',
+ 'contains_rect', 'corner', 'dimensions', 'expand_by', 'expand_to',
+ 'from_intervals', 'from_list', 'from_points', 'from_xywh',
+ 'has_zero_area', 'height', 'intersects', 'left', 'max',
+ 'max_extent', 'midpoint', 'min', 'min_extent', 'right',
+ 'set_bottom', 'set_left', 'set_max', 'set_min', 'set_right',
+ 'set_top', 'top', 'union_with', 'width'])
+
+ if name in Rect_methods:
+ return self._get_Rect_method(name)
+ else:
+ raise AttributeError("OptIntRect instance has no attribute \"{}\"".format(name))
+
+ def _wrap_Rect_method(self, name, *args, **kwargs):
+ if self.isEmpty():
+ raise ValueError("OptIntRect is empty.")
+ else:
+ return self.Rect.__getattr__(name)(*args, **kwargs)
+
+ #declaring these by hand, because they take fixed number of arguments,
+ #which is enforced by cython
+
+ def __getitem__(self, i):
+ """self[d]"""
+ return self._wrap_Rect_method("__getitem__", i)
+
+ def __add__(self, other):
+ """Offset rectangle by point."""
+ return self._wrap_Rect_method("__add__", other)
+
+ def __sub__(self, other):
+ """Offset rectangle by -point."""
+ return self._wrap_Rect_method("__sub__", other)
+
+cdef cy_OptIntRect wrap_OptIntRect(OptIntRect p):
+ cdef OptIntRect* retp = new OptIntRect()
+ retp[0] = p
+ cdef cy_OptIntRect r = cy_OptIntRect.__new__(cy_OptIntRect)
+ r.thisptr = retp
+ return r