几何对象的运算符代数#

Point、IRect、Rect、Quad 和 Matrix 类实例统称为“几何”对象。

它们都是 Python 序列的特例,更多背景信息请参阅在 PyMuPDF 中使用 Python 序列作为参数

我们为这些类定义了运算符,使其(几乎)可以像普通数字一样进行加、减、乘、除等运算。

本章概述了可能的操作。

一般说明#

  1. 运算符可以是二元的(即涉及两个对象)或一元的。

  2. 二元运算的结果类型是左操作数类的一个新对象,或者是一个布尔值,或者(对于点积)一个浮点数。

  3. 一元运算的结果是同类的一个新对象,或者是一个布尔值,或者一个浮点数。

  4. 二元运算符 +, -, *, / 为所有类定义。它们大致执行您期望的操作——但第二操作数除外,因为它…

    • 可能总是一个数字,该数字将对第一个操作数的每个分量执行运算,

    • 可能总是一个相同长度(2、4 或 6)的数字序列——我们将此类序列分别称为 point_likerect_likequad_likematrix_like

  5. 矩形支持额外的二元运算:交集(运算符 "&")、并集(运算符 "|")和包含检查。

  6. 二元运算符完全支持原地操作。因此,如果“°”是二元运算符,则表达式 a °= b 始终有效,且与 a = a ° b 相同。因此,请小心,不要对两个点执行 p1 *= p2,因为此后“p1”将是一个浮点数。

一元运算#

运算符

结果

bool(OBJ)

当且仅当 OBJ 的所有分量均为零时为假

abs(OBJ)

矩形面积——对于其他类型等于 norm(OBJ)

norm(OBJ)

分量平方和的平方根(欧几里得范数)

+OBJ

OBJ 的新副本

-OBJ

分量取反的 OBJ 新副本

~m

矩阵“m”的逆矩阵,如果不可逆则为零矩阵

二元运算#

这些是像 a ° b 这样的表达式,其中“°”可以是运算符 +, -, *, / 中的任意一个。a == bb in a 形式的表达式也是二元运算。

如果“b”是一个数字,则对“a”的每个分量执行相应的运算。否则,如果“b”不是一个数字,则发生以下情况

运算符

结果

a+b, a-b

按分量执行,“b”必须是“a-like”。

a*m, a/m

“a”可以是点、矩形或矩阵,“m”是 matrix_like。“a/m”被视为“a*~m”(对于不可逆矩阵,请参阅下面的说明)。如果“a”是一个或一个矩形,则执行“a.transform(m)”。如果“a”是一个矩阵,则发生矩阵连接。

a*b

返回点“a”与 point-like “b”的向量点积

a&b

交集矩形:“a”必须是一个矩形,“b”是 rect_like。返回包含在两个操作数中的最大矩形

a|b

并集矩形:“a”必须是一个矩形,“b”可以是 point_likerect_like。返回包含两个操作数的最小矩形

b in a

如果“b”是一个数字,则返回 b in tuple(a)。如果“b”是 point_likerect_likequad_like,则“a”必须是一个矩形,并返回 a.contains(b)

a == b

如果 *bool(a-b)* 为 False 则为 True(“b”可以是“a-like”)。

注意

请注意与通常算术的一个重要区别

矩阵乘法不满足交换律,即通常对于两个矩阵 m 和 n,有 m*n != n*m。此外,存在没有逆的非零矩阵,例如 m = Matrix(1, 0, 1, 0, 1, 0)。如果您尝试除以这些矩阵中的任何一个,使用运算符“/”时将收到 ZeroDivisionError 异常,例如对于表达式 pymupdf.Identity / m。但如果您写成 pymupdf.Identity * ~m,结果将是 pymupdf.Matrix()(零矩阵)。

诚然,这代表了一个不一致之处,我们正在考虑移除它。目前,您可以选择通过检查 ~m 是否为零矩阵来避免异常,或者通过使用 pymupdf.Identity / m 接受潜在的 ZeroDivisionError

注意

  • 遵循这些约定,所有通常的代数规则均适用。例如,可以任意使用括号(在同类对象之间!):如果 r1, r2 是矩形,m1, m2 是矩阵,您可以执行 (r1 + r2) * m1 * m2

  • 对于所有同类对象,a + b + c == (a + b) + c == a + (b + c) 为真。

  • 此外,对于矩阵,以下为真:(m1 + m2) * m3 == m1 * m3 + m2 * m3 (分配律)。

  • 但是应用矩阵的顺序很重要:如果 r 是一个矩形,m1 和 m2 是矩阵,那么——注意!:
    • r * m1 * m2 == (r * m1) * m2 != r * (m1 * m2)

一些示例#

数字操作#

对于通常的算术运算,数字始终允许作为第二个操作数。此外,您可以写成 "x in OBJ",其中 x 是一个数字。它的实现是 "x in tuple(OBJ)"

>>> pymupdf.Rect(1, 2, 3, 4) + 5
pymupdf.Rect(6.0, 7.0, 8.0, 9.0)
>>> 3 in pymupdf.Rect(1, 2, 3, 4)
True
>>>

以下代码将创建一个文档页面矩形的左上角四分之一

>>> page.rect
Rect(0.0, 0.0, 595.0, 842.0)
>>> page.rect / 2
Rect(0.0, 0.0, 297.5, 421.0)
>>>

以下代码将返回连接两个点 p1p2线段中点

>>> p1 = pymupdf.Point(1, 2)
>>> p2 = pymupdf.Point(4711, 3141)
>>> mp = (p1 + p2) / 2
>>> mp
Point(2356.0, 1571.5)
>>>

计算两个点的向量点积。您可以计算夹角的余弦并检查正交性。

>>> p1 = pymupdf.Point(1, 0)
>>> p2 = pymupdf.Point(1, 1)
>>> dot = p1 * p2
>>> dot
1.0
>>> # compute the cosine of the angle between p1 and p2:
>>> cosine = dot / (abs(p1) * abs(p2))
>>> cosine  # cosine of 45 degrees
0.7071067811865475
>>> math.cos(mat.radians(45))  # verify:
0.7071067811865476
>>> # check orhogonality
>>> p3 = pymupdf.Point(0, 1)
>>> # p1 and p3 are orthogonal so, as expected:
>>> p1 * p3
0.0

“Like”对象操作#

二元运算的第二个操作数始终可以是左操作数的“like”类型。“Like”在此语境下表示“相同长度的数字序列”。结合以上示例

>>> p1 + p2
Point(4712.0, 3143.0)
>>> p1 + (4711, 3141)
Point(4712.0, 3143.0)
>>> p1 += (4711, 3141)
>>> p1
Point(4712.0, 3143.0)
>>>

要将矩形向右移动 5 个像素,请执行此操作

>>> pymupdf.Rect(100, 100, 200, 200) + (5, 0, 5, 0)  # add 5 to the x coordinates
Rect(105.0, 100.0, 205.0, 200.0)
>>>

点、矩形和矩阵可以被矩阵变换。在 PyMuPDF 中,我们将其视为一种“乘法”(或相应的“除法”),其中第二个操作数可以是 matrix 的“like”类型。此处的除法表示“乘以逆矩阵”

>>> m = pymupdf.Matrix(1, 2, 3, 4, 5, 6)
>>> n = pymupdf.Matrix(6, 5, 4, 3, 2, 1)
>>> p = pymupdf.Point(1, 2)
>>> p * m
Point(12.0, 16.0)
>>> p * (1, 2, 3, 4, 5, 6)
Point(12.0, 16.0)
>>> p / m
Point(2.0, -2.0)
>>> p / (1, 2, 3, 4, 5, 6)
Point(2.0, -2.0)
>>>
>>> m * n  # matrix multiplication
Matrix(14.0, 11.0, 34.0, 27.0, 56.0, 44.0)
>>> m / n  # matrix division
Matrix(2.5, -3.5, 3.5, -4.5, 5.5, -7.5)
>>>
>>> m / m  # result is equal to the Identity matrix
Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)
>>>
>>> # look at this non-invertible matrix:
>>> m = pymupdf.Matrix(1, 0, 1, 0, 1, 0)
>>> ~m
Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
>>> # we try dividing by it in two ways:
>>> p = pymupdf.Point(1, 2)
>>> p * ~m  # this delivers point (0, 0):
Point(0.0, 0.0)
>>> p / m  # but this is an exception:
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    p / m
  File "... /site-packages/fitz/pymupdf.py", line 869, in __truediv__
    raise ZeroDivisionError("matrix not invertible")
ZeroDivisionError: matrix not invertible
>>>

作为一项特色,矩形支持额外的二元运算

  • 交集 – rectangle-likes 的共同区域,运算符 “&”

  • 包含 – 扩大以包含 point-like 或 rect-like,运算符 “|”

  • 包含检查 – point-like 或 rect-like 是否在内部

以下是创建包含给定点的最小矩形的示例

>>> # first define some point-likes
>>> points = []
>>> for i in range(10):
        for j in range(10):
            points.append((i, j))
>>>
>>> # now create a rectangle containing all these 100 points
>>> # start with an empty rectangle
>>> r = pymupdf.Rect(points[0], points[0])
>>> for p in points[1:]:  # and include remaining points one by one
        r |= p
>>> r  # here is the to be expected result:
Rect(0.0, 0.0, 9.0, 9.0)
>>> (4, 5) in r  # this point-like lies inside the rectangle
True
>>> # and this rect-like is also inside
>>> (4, 4, 5, 5) in r
True
>>>

本软件按原样提供,不附带任何明示或暗示的保证。本软件按许可分发,除许可条款明确授权外,不得复制、修改或分发。请参阅 artifex.com 的许可信息,或联系 Artifex Software Inc., 39 Mesa Street, Suite 108A, San Francisco CA 94129, United States 获取更多信息。