几何对象的运算代数#

类的实例 PointIRectRectQuadMatrix 被统称为“几何”对象。

它们都是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的所有元素都为零时,返回false

abs(OBJ)

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

norm(OBJ)

组件平方的平方根(欧几里得范数)

+对象

对象的新副本

-OBJ

带有取反分量的新 OBJ 副本

~m

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

二元操作#

这些是像 a ° b 的表达式,其中 “°” 是任何运算符 +, -, *, /。此外,二元运算是形式为 a == bb in a 的表达式。

如果“b”是一个数字,则对“a”的每个组件执行相应的操作。否则,如果“b”不是一个数字, 则会发生以下情况:

操作

结果

a+b, a-b

逐元素执行,“b” 必须与 “a” 相似。

a*m, a/m

“a” 可以是一个点、矩形或矩阵,而 “m” 是一个 matrix_like“a/m” 被视为 “a*~m” (请参阅下面有关不可逆矩阵的说明)。如果 “a” 是一个 矩形, 那么将执行 “a.transform(m)”。如果 “a” 是一个矩阵,那么将会进行矩阵连接。

a*b

返回点 “a” 和点状 “b” 的 向量点积

a&b

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

a|b

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

b 在 a 中

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

a == b

如果 bool(a-b)(“b” 可能是 “a-like”)。

注意

请注意与通常的算术运算之间的重要区别:

矩阵乘法是 不满足交换律,即对于两个矩阵,我们一般有 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

与“像”对象的操作#

二元操作的第二个操作数总是可以“像”左操作数。“像”在这里的意思是“长度相同的数字序列”。通过上述例子:

>>> 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中,我们将其视为“乘法”(或者“除法”),其中第二个操作数可能“像”一个矩阵。在这个上下文中,除法意味着“与逆矩阵的乘法”:

>>> 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
>>>

作为一种特性,矩形支持额外的二元操作:

  • 交集 – 矩形相似物的公共区域,操作符 “&”

  • 包含 – 扩大以包括一个点状或矩形,运算符 “|”

  • 包含性 检查 - 一个点或矩形是否在内部

这是一个创建包围给定点的最小矩形的示例:

>>> # 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以获取更多信息。