几何对象的运算代数#
类的实例 Point、IRect、Rect、Quad 和 Matrix 被统称为“几何”对象。
它们都是Python序列的特殊情况,详见 在PyMuPDF中使用Python序列作为参数 的更多背景信息。
我们为这些类定义了运算符,使其在加法、减法、乘法、除法等方面(几乎)可以像普通数字一样处理。
本章是对可能性的概述。
一般说明#
运算符可以是二元(即涉及两个对象)或一元。
二元运算的结果类型是左操作数的类的新对象、布尔值或(对于点积)浮点数。
一元操作的结果要么是同一类的新对象,要么是布尔值或浮点数。
二元运算符
+, -, *, /对所有类都是定义的。它们 大概 做你所期望的事情 – 但第二个操作数 …可能始终是一个数字,然后对第一个组件的每个部分执行操作,
可能始终是相同长度的数字序列(2、4或6)——我们称这样的序列为
point_like、rect_like、quad_like或matrix_like,分别。
矩形支持 额外的二元 操作: 交集 (操作符
"&"), 并集 (操作符"|") 和 包含 检查。二元运算符完全支持原地操作。因此,如果“°”是一个二元运算符,那么表达式
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 == b 和 b in a 的表达式。
如果“b”是一个数字,则对“a”的每个组件执行相应的操作。否则,如果“b”不是一个数字, 则会发生以下情况:
操作 |
结果 |
|---|---|
a+b, a-b |
逐元素执行,“b” 必须与 “a” 相似。 |
a*m, a/m |
“a” 可以是一个点、矩形或矩阵,而 “m” 是一个
|
a*b |
返回点 “a” 和点状 “b” 的 向量点积。 |
a&b |
交集矩形: “a” 必须是一个矩形,而 “b” |
a|b |
并集矩形: “a” 必须是一个矩形,而 “b” 可以是
|
b 在 a 中 |
如果 “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)
>>>
以下内容将提供连接两个点p1和p2的中点:
>>> 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
>>>