Skip to content

Algebra with Matrices, Rectangles and Points

Jorj X. McKie edited this page Oct 18, 2017 · 6 revisions

For the Matrix, Rect, IRect and Point classes algebraic operations are possible to some extent. Following we will describe what they are and how they can be used.

Matrix Algebra

Matrix objects m, m1, m2 can be added, subtracted, negated, inverted or multiplied. The result of these operations always is a new matrix. In addition the "absolute value" of a matrix can be calculated - its Euclidean norm - which is a non-negative floating point number.

  • m1 + m2 is defined as the matrix [m1.a + m2.a, m1.b + m2.b, ..., m1.f + m2.f]. m2 can as well be number, which is then added component-wise. Or it can be a List / tuple of 6 numbers, instead of a matrix. Analogous is also true for the following binary operations.
  • m1 - m2 analogous to addition.
  • m1 * m2 is defined by m1.concat(m2), if m2 is a matrix. If it is a number, component-wise multiplication takes place.
  • m1 / m2 is defined by m1 * ~m2.
  • -m is defined by [-m.a, -m.b, ..., -m.f].
  • +m is just a copy of m.
  • ~m is defined by invert(m). This means that m * ~m = ~m * m = fitz.Identity. Because we are dealing with floats here, this equality often is only almost true because of rounding effects etc. If m is not invertible (degenerate), then ~m = [0, 0, 0, 0, 0, 0].
  • abs(m) is defined by math.sqrt(m.a**2 + m.b**2 + ... + m.f**2).
  • bool(m) is False if m = fitz.Matrix(0, 0, 0, 0, 0, 0), else True.
  • Comparisons are based on components, not object identities: m1 == m2 is True if all components are equal. Note however, that floating point values are compared here: therefore a false inequality may result from e.g. rounding effects.
  • In-place operators are fully supperted: m1 /= (1, 2, 3, 4, 5, 6) for example calculates the inverse of fitz.Matrix(1,2,3,4,5,6) and multiplies the result into m1.

Following are some examples to illustrate the above.

  • check if a matrix is invertible: if not bool(~m): print("m is not invertible")
  • check whether two matrices are (almost) equal: if abs(m1 - m2) < epsilon: print("m1 (almost) equals m2")
  • do a complex matrix calculation: m = m1*(m2 + ~m3)*m4
  • divide components by 2: m /= 2.

Rectangle Algebra

Rect and IRect objects can be added and subtracted to / from other rectangles or numbers or lists / tuples, they can be negated and multiplied with matrices, tuples or numbers. In addition, inclusion | and intersection & of rectangles with other objects are supported as binary operations. The result of these operations always is a new rectangle with the same type (Rect or IRect) as the left operand.

As with matrices, in-place operators are fully supported.

  • r1 + r2 and r1 - r2 are defined component-wise as with matrices. Any of the two operands can be a Rect or an IRect. In addition, r2 can also be a number or a sequence object.
  • -r is defined component-wise (Rect or IRect).
  • +r is a copy of r.
  • r * m is a new rectangle resulting from r transformed with matrix m. Works for Rect and IRect. If m is a number, it is multiplied with the coordinates.
  • r1 | r2 (inclusion) is the smallest rectangle containing both, r1 (Rect or IRect) and r2 (Rect, IRect or Point).
  • r1 & r2 (intersection) is the largest rectangle that is contained in both, r1 (Rect or IRect) and r2 (Rect or IRect).
  • bool(r) is False if all components of r are zero, else True.

Example ("rectangle hull"):

If plist = [p0, p1, ..., pn] is a list of Point objects then r computed by

r = fitz.Rect(p0, p0)
for p in plist:
    r = r | p

is the smallest rectangle containing all points in the list. Note: if you want an IRect perform a r.round() afterwards.

Example ("finite rectangle"):

MuPDF defines rectangles as infinite, if the bottom right corner is not south-eastern to the top left one. This may be awkward sometimes. So, here is a recipe to create a finite rectangle covering the same area:

r = fitz.Rect(...)      # potentiallyinfinite rectangle
s = fitz.Rect(r.top_left, r.top_left)   # rect containing just a point
s = s | r.bottom_right  # s now is a finite rectangle

Point Algebra

Point objects can be added, subtracted and negated just like rectangles, yielding new point objects.

  • p1 + p2, p1 - p2, -p, +p are defined component-wise like the rectangle operations. p2 can also be a number or a list / tuple.
  • abs(p) is the Eucldean norm math.sqrt(p.x**2 + p.y**2) as with matrices.
  • p * m is a new point resulting from p transformed with matrix m. Again, m may be a number, which then multiplies the coordinates. Or it can be a sequence of 6 numbers which will be treated as a matrix. Instead of p * ~m you can also write p / m.
  • In-place operators are also supported: if p = fitz.Point(100, 100), then p /= (1, 2, 3, 4, 5, 6) delivers fitz.Point(-49.0, 48.0), and p /= 2 is fitz.Point(50.0, 50.0).
Clone this wiki locally