mirror of
https://github.com/snowykami/mbcp.git
synced 2024-11-25 15:55:03 +08:00
📝 构建文档测试
This commit is contained in:
parent
86b8a4c922
commit
5763a84679
2
.github/workflows/deploy-docs.yml
vendored
2
.github/workflows/deploy-docs.yml
vendored
@ -39,7 +39,7 @@ jobs:
|
||||
|
||||
- name: Setup API markdown
|
||||
run: |-
|
||||
python -m pip install pydantic
|
||||
python -m pip install litedoc
|
||||
python -m litedoc mbcp -o docs/api -l zh-Hans
|
||||
python -m litedoc mbcp -o docs/en/api -l en
|
||||
python -m litedoc mbcp -o docs/ja/api -l ja
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -12,3 +12,5 @@ node_modules/
|
||||
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
|
||||
litedoc/
|
@ -7,13 +7,13 @@ title: mbcp.mp_math.equation
|
||||
|
||||
**说明**: 求N元函数一阶偏导函数。这玩意不太稳定,慎用。
|
||||
|
||||
**返回**: 偏导函数
|
||||
|
||||
**参数**:
|
||||
> - func: 函数
|
||||
> - var: 变量位置,可为整数(一阶偏导)或整数元组(高阶偏导)
|
||||
> - epsilon: 偏移量
|
||||
|
||||
**返回**: 偏导函数
|
||||
|
||||
**引发**:
|
||||
> - ValueError 无效变量类型
|
||||
|
||||
|
@ -35,12 +35,12 @@ def __init__(self, point: 'Point3', direction: 'Vector3'):
|
||||
|
||||
**说明**: 判断两条直线是否近似相等。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**参数**:
|
||||
> - other: 另一条直线
|
||||
> - epsilon: 误差
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -65,11 +65,11 @@ def approx(self, other: 'Line3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**说明**: 计算直线和直线之间的夹角。
|
||||
|
||||
**返回**: 夹角弧度
|
||||
|
||||
**参数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 夹角弧度
|
||||
|
||||
**引发**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -98,11 +98,11 @@ def cal_angle(self, other: 'Line3') -> 'AnyAngle':
|
||||
|
||||
**说明**: 计算直线和直线或点之间的距离。
|
||||
|
||||
**返回**: 距离
|
||||
|
||||
**参数**:
|
||||
> - other: 平行直线或点
|
||||
|
||||
**返回**: 距离
|
||||
|
||||
**引发**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -144,11 +144,11 @@ def cal_distance(self, other: 'Line3 | Point3') -> float:
|
||||
|
||||
**说明**: 计算两条直线的交点。
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**参数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**引发**:
|
||||
> - ValueError 直线平行
|
||||
> - ValueError 直线不共面
|
||||
@ -183,11 +183,11 @@ def cal_intersection(self, other: 'Line3') -> 'Point3':
|
||||
|
||||
**说明**: 计算直线经过指定点p的垂线。
|
||||
|
||||
**返回**: 垂线
|
||||
|
||||
**参数**:
|
||||
> - point: 指定点
|
||||
|
||||
**返回**: 垂线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -211,11 +211,11 @@ def cal_perpendicular(self, point: 'Point3') -> 'Line3':
|
||||
|
||||
**说明**: 获取直线上的点。同一条直线,但起始点和方向向量不同,则同一个t对应的点不同。
|
||||
|
||||
**返回**: 点
|
||||
|
||||
**参数**:
|
||||
> - t: 参数t
|
||||
|
||||
**返回**: 点
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -262,12 +262,12 @@ def get_parametric_equations(self) -> tuple[OneSingleVarFunc, OneSingleVarFunc,
|
||||
|
||||
**说明**: 判断两条直线是否近似平行。
|
||||
|
||||
**返回**: 是否近似平行
|
||||
|
||||
**参数**:
|
||||
> - other: 另一条直线
|
||||
> - epsilon: 误差
|
||||
|
||||
**返回**: 是否近似平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -292,11 +292,11 @@ def is_approx_parallel(self, other: 'Line3', epsilon: float=1e-06) -> bool:
|
||||
|
||||
**说明**: 判断两条直线是否平行。
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
**参数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -320,11 +320,11 @@ def is_parallel(self, other: 'Line3') -> bool:
|
||||
|
||||
**说明**: 判断两条直线是否共线。
|
||||
|
||||
**返回**: 是否共线
|
||||
|
||||
**参数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 是否共线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -348,11 +348,11 @@ def is_collinear(self, other: 'Line3') -> bool:
|
||||
|
||||
**说明**: 判断点是否在直线上。
|
||||
|
||||
**返回**: 是否在直线上
|
||||
|
||||
**参数**:
|
||||
> - point: 点
|
||||
|
||||
**返回**: 是否在直线上
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -377,11 +377,11 @@ def is_point_on(self, point: 'Point3') -> bool:
|
||||
**说明**: 判断两条直线是否共面。
|
||||
充要条件:两直线方向向量的叉乘与两直线上任意一点的向量的点积为0。
|
||||
|
||||
**返回**: 是否共面
|
||||
|
||||
**参数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 是否共面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -438,12 +438,12 @@ def simplify(self):
|
||||
|
||||
**说明**: 工厂函数 由两点构造直线。
|
||||
|
||||
**返回**: 直线
|
||||
|
||||
**参数**:
|
||||
> - p1: 点1
|
||||
> - p2: 点2
|
||||
|
||||
**返回**: 直线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -470,11 +470,11 @@ def from_two_points(cls, p1: 'Point3', p2: 'Point3') -> 'Line3':
|
||||
|
||||
**说明**: 计算两条直线点集合的交集。重合线返回自身,平行线返回None,交线返回交点。
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**参数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
|
@ -41,11 +41,11 @@ def __init__(self, a: float, b: float, c: float, d: float):
|
||||
|
||||
**说明**: 判断两个平面是否近似相等。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**参数**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -79,11 +79,11 @@ def approx(self, other: 'Plane3') -> bool:
|
||||
|
||||
**说明**: 计算平面与平面之间的夹角。
|
||||
|
||||
**返回**: 夹角弧度
|
||||
|
||||
**参数**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**返回**: 夹角弧度
|
||||
|
||||
**引发**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -117,11 +117,11 @@ def cal_angle(self, other: 'Line3 | Plane3') -> 'AnyAngle':
|
||||
|
||||
**说明**: 计算平面与平面或点之间的距离。
|
||||
|
||||
**返回**: 距离
|
||||
|
||||
**参数**:
|
||||
> - other: 另一个平面或点
|
||||
|
||||
**返回**: 距离
|
||||
|
||||
**引发**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -155,11 +155,11 @@ def cal_distance(self, other: 'Plane3 | Point3') -> float:
|
||||
|
||||
**说明**: 计算两平面的交线。
|
||||
|
||||
**返回**: 两平面的交线
|
||||
|
||||
**参数**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**返回**: 两平面的交线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -200,11 +200,11 @@ def cal_intersection_line3(self, other: 'Plane3') -> 'Line3':
|
||||
|
||||
**说明**: 计算平面与直线的交点。
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**参数**:
|
||||
> - other: 不与平面平行或在平面上的直线
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**引发**:
|
||||
> - ValueError 平面与直线平行或重合
|
||||
|
||||
@ -237,11 +237,11 @@ def cal_intersection_point3(self, other: 'Line3') -> 'Point3':
|
||||
|
||||
**说明**: 计算平行于该平面且过指定点的平面。
|
||||
|
||||
**返回**: 所求平面
|
||||
|
||||
**参数**:
|
||||
> - point: 指定点
|
||||
|
||||
**返回**: 所求平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -265,11 +265,11 @@ def cal_parallel_plane3(self, point: 'Point3') -> 'Plane3':
|
||||
|
||||
**说明**: 判断两个平面是否平行。
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
**参数**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -319,12 +319,12 @@ def normal(self) -> 'Vector3':
|
||||
|
||||
**说明**: 工厂函数 由点和法向量构造平面(点法式构造)。
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
**参数**:
|
||||
> - point: 平面上的一点
|
||||
> - normal: 法向量
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -353,13 +353,13 @@ def from_point_and_normal(cls, point: 'Point3', normal: 'Vector3') -> 'Plane3':
|
||||
|
||||
**说明**: 工厂函数 由三点构造平面。
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
**参数**:
|
||||
> - p1: 点1
|
||||
> - p2: 点2
|
||||
> - p3: 点3
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -390,12 +390,12 @@ def from_three_points(cls, p1: 'Point3', p2: 'Point3', p3: 'Point3') -> 'Plane3'
|
||||
|
||||
**说明**: 工厂函数 由两直线构造平面。
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
**参数**:
|
||||
> - l1: 直线1
|
||||
> - l2: 直线2
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -426,12 +426,12 @@ def from_two_lines(cls, l1: 'Line3', l2: 'Line3') -> 'Plane3':
|
||||
|
||||
**说明**: 工厂函数 由点和直线构造平面。
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
**参数**:
|
||||
> - point: 面上一点
|
||||
> - line: 面上直线,不包含点
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -485,11 +485,11 @@ def __and__(self, other: 'Plane3') -> 'Line3 | None':
|
||||
|
||||
**说明**: 取两平面的交集(人话:交线)
|
||||
|
||||
**返回**: 不平行平面的交线,平面平行返回None
|
||||
|
||||
**参数**:
|
||||
> - other:
|
||||
|
||||
**返回**: 不平行平面的交线,平面平行返回None
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
|
@ -38,12 +38,12 @@ def __init__(self, x: float, y: float, z: float):
|
||||
|
||||
**说明**: 判断两个点是否近似相等。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**参数**:
|
||||
> - other:
|
||||
> - epsilon:
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
|
@ -7,13 +7,13 @@ title: mbcp.mp_math.utils
|
||||
|
||||
**说明**: 区间限定函数
|
||||
|
||||
**返回**: 限制后的值
|
||||
|
||||
**参数**:
|
||||
> - x: 待限定的值
|
||||
> - min_: 最小值
|
||||
> - max_: 最大值
|
||||
|
||||
**返回**: 限制后的值
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -40,13 +40,13 @@ def clamp(x: float, min_: float, max_: float) -> float:
|
||||
|
||||
**说明**: 判断两个数是否近似相等。或包装一个实数,用于判断是否近似于0。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**参数**:
|
||||
> - x: 数1
|
||||
> - y: 数2
|
||||
> - epsilon: 误差
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -72,12 +72,12 @@ def approx(x: float, y: float=0.0, epsilon: float=APPROX) -> bool:
|
||||
|
||||
**说明**: 获取数的符号。
|
||||
|
||||
**返回**: 符号 + - ""
|
||||
|
||||
**参数**:
|
||||
> - x: 数
|
||||
> - only_neg: 是否只返回负数的符号
|
||||
|
||||
**返回**: 符号 + - ""
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -109,12 +109,12 @@ def sign(x: float, only_neg: bool=False) -> str:
|
||||
1 -> +1
|
||||
0 -> ""
|
||||
|
||||
**返回**: 符号 + - ""
|
||||
|
||||
**参数**:
|
||||
> - x: 数
|
||||
> - only_neg: 是否只返回负数的符号
|
||||
|
||||
**返回**: 符号 + - ""
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
|
@ -38,12 +38,12 @@ def __init__(self, x: float, y: float, z: float):
|
||||
|
||||
**说明**: 判断两个向量是否近似相等。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**参数**:
|
||||
> - other:
|
||||
> - epsilon:
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -69,11 +69,11 @@ def approx(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**说明**: 计算两个向量之间的夹角。
|
||||
|
||||
**返回**: 夹角
|
||||
|
||||
**参数**:
|
||||
> - other: 另一个向量
|
||||
|
||||
**返回**: 夹角
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -101,11 +101,11 @@ def cal_angle(self, other: 'Vector3') -> 'AnyAngle':
|
||||
其余结果的模为平行四边形的面积。
|
||||
|
||||
|
||||
**返回**: 行列式的结果
|
||||
|
||||
**参数**:
|
||||
> - other:
|
||||
|
||||
**返回**: 行列式的结果
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -141,12 +141,12 @@ def cross(self, other: 'Vector3') -> 'Vector3':
|
||||
|
||||
**说明**: 判断两个向量是否近似平行。
|
||||
|
||||
**返回**: 是否近似平行
|
||||
|
||||
**参数**:
|
||||
> - other: 另一个向量
|
||||
> - epsilon: 允许的误差
|
||||
|
||||
**返回**: 是否近似平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -171,11 +171,11 @@ def is_approx_parallel(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**说明**: 判断两个向量是否平行。
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
**参数**:
|
||||
> - other: 另一个向量
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
@ -370,11 +370,11 @@ def __add__(self, other):
|
||||
|
||||
**说明**: 判断两个向量是否相等。
|
||||
|
||||
**返回**: 是否相等
|
||||
|
||||
**参数**:
|
||||
> - other:
|
||||
|
||||
**返回**: 是否相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
|
@ -9,12 +9,12 @@ title: mbcp.presets.model
|
||||
|
||||
**说明**: 生成球体上的点集。
|
||||
|
||||
**返回**: List[Point3]: 球体上的点集。
|
||||
|
||||
**参数**:
|
||||
> - radius:
|
||||
> - density:
|
||||
|
||||
**返回**: List[Point3]: 球体上的点集。
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源代码</b> </summary>
|
||||
|
@ -7,13 +7,13 @@ title: mbcp.mp_math.equation
|
||||
|
||||
**Description**: 求N元函数一阶偏导函数。这玩意不太稳定,慎用。
|
||||
|
||||
**Return**: 偏导函数
|
||||
|
||||
**Arguments**:
|
||||
> - func: 函数
|
||||
> - var: 变量位置,可为整数(一阶偏导)或整数元组(高阶偏导)
|
||||
> - epsilon: 偏移量
|
||||
|
||||
**Return**: 偏导函数
|
||||
|
||||
**Raises**:
|
||||
> - ValueError 无效变量类型
|
||||
|
||||
|
@ -35,12 +35,12 @@ def __init__(self, point: 'Point3', direction: 'Vector3'):
|
||||
|
||||
**Description**: 判断两条直线是否近似相等。
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一条直线
|
||||
> - epsilon: 误差
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -65,11 +65,11 @@ def approx(self, other: 'Line3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**Description**: 计算直线和直线之间的夹角。
|
||||
|
||||
**Return**: 夹角弧度
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**Return**: 夹角弧度
|
||||
|
||||
**Raises**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -98,11 +98,11 @@ def cal_angle(self, other: 'Line3') -> 'AnyAngle':
|
||||
|
||||
**Description**: 计算直线和直线或点之间的距离。
|
||||
|
||||
**Return**: 距离
|
||||
|
||||
**Arguments**:
|
||||
> - other: 平行直线或点
|
||||
|
||||
**Return**: 距离
|
||||
|
||||
**Raises**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -144,11 +144,11 @@ def cal_distance(self, other: 'Line3 | Point3') -> float:
|
||||
|
||||
**Description**: 计算两条直线的交点。
|
||||
|
||||
**Return**: 交点
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**Return**: 交点
|
||||
|
||||
**Raises**:
|
||||
> - ValueError 直线平行
|
||||
> - ValueError 直线不共面
|
||||
@ -183,11 +183,11 @@ def cal_intersection(self, other: 'Line3') -> 'Point3':
|
||||
|
||||
**Description**: 计算直线经过指定点p的垂线。
|
||||
|
||||
**Return**: 垂线
|
||||
|
||||
**Arguments**:
|
||||
> - point: 指定点
|
||||
|
||||
**Return**: 垂线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -211,11 +211,11 @@ def cal_perpendicular(self, point: 'Point3') -> 'Line3':
|
||||
|
||||
**Description**: 获取直线上的点。同一条直线,但起始点和方向向量不同,则同一个t对应的点不同。
|
||||
|
||||
**Return**: 点
|
||||
|
||||
**Arguments**:
|
||||
> - t: 参数t
|
||||
|
||||
**Return**: 点
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -262,12 +262,12 @@ def get_parametric_equations(self) -> tuple[OneSingleVarFunc, OneSingleVarFunc,
|
||||
|
||||
**Description**: 判断两条直线是否近似平行。
|
||||
|
||||
**Return**: 是否近似平行
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一条直线
|
||||
> - epsilon: 误差
|
||||
|
||||
**Return**: 是否近似平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -292,11 +292,11 @@ def is_approx_parallel(self, other: 'Line3', epsilon: float=1e-06) -> bool:
|
||||
|
||||
**Description**: 判断两条直线是否平行。
|
||||
|
||||
**Return**: 是否平行
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**Return**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -320,11 +320,11 @@ def is_parallel(self, other: 'Line3') -> bool:
|
||||
|
||||
**Description**: 判断两条直线是否共线。
|
||||
|
||||
**Return**: 是否共线
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**Return**: 是否共线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -348,11 +348,11 @@ def is_collinear(self, other: 'Line3') -> bool:
|
||||
|
||||
**Description**: 判断点是否在直线上。
|
||||
|
||||
**Return**: 是否在直线上
|
||||
|
||||
**Arguments**:
|
||||
> - point: 点
|
||||
|
||||
**Return**: 是否在直线上
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -377,11 +377,11 @@ def is_point_on(self, point: 'Point3') -> bool:
|
||||
**Description**: 判断两条直线是否共面。
|
||||
充要条件:两直线方向向量的叉乘与两直线上任意一点的向量的点积为0。
|
||||
|
||||
**Return**: 是否共面
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**Return**: 是否共面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -438,12 +438,12 @@ def simplify(self):
|
||||
|
||||
**Description**: 工厂函数 由两点构造直线。
|
||||
|
||||
**Return**: 直线
|
||||
|
||||
**Arguments**:
|
||||
> - p1: 点1
|
||||
> - p2: 点2
|
||||
|
||||
**Return**: 直线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -470,11 +470,11 @@ def from_two_points(cls, p1: 'Point3', p2: 'Point3') -> 'Line3':
|
||||
|
||||
**Description**: 计算两条直线点集合的交集。重合线返回自身,平行线返回None,交线返回交点。
|
||||
|
||||
**Return**: 交点
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**Return**: 交点
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
|
@ -41,11 +41,11 @@ def __init__(self, a: float, b: float, c: float, d: float):
|
||||
|
||||
**Description**: 判断两个平面是否近似相等。
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -79,11 +79,11 @@ def approx(self, other: 'Plane3') -> bool:
|
||||
|
||||
**Description**: 计算平面与平面之间的夹角。
|
||||
|
||||
**Return**: 夹角弧度
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**Return**: 夹角弧度
|
||||
|
||||
**Raises**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -117,11 +117,11 @@ def cal_angle(self, other: 'Line3 | Plane3') -> 'AnyAngle':
|
||||
|
||||
**Description**: 计算平面与平面或点之间的距离。
|
||||
|
||||
**Return**: 距离
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一个平面或点
|
||||
|
||||
**Return**: 距离
|
||||
|
||||
**Raises**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -155,11 +155,11 @@ def cal_distance(self, other: 'Plane3 | Point3') -> float:
|
||||
|
||||
**Description**: 计算两平面的交线。
|
||||
|
||||
**Return**: 两平面的交线
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**Return**: 两平面的交线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -200,11 +200,11 @@ def cal_intersection_line3(self, other: 'Plane3') -> 'Line3':
|
||||
|
||||
**Description**: 计算平面与直线的交点。
|
||||
|
||||
**Return**: 交点
|
||||
|
||||
**Arguments**:
|
||||
> - other: 不与平面平行或在平面上的直线
|
||||
|
||||
**Return**: 交点
|
||||
|
||||
**Raises**:
|
||||
> - ValueError 平面与直线平行或重合
|
||||
|
||||
@ -237,11 +237,11 @@ def cal_intersection_point3(self, other: 'Line3') -> 'Point3':
|
||||
|
||||
**Description**: 计算平行于该平面且过指定点的平面。
|
||||
|
||||
**Return**: 所求平面
|
||||
|
||||
**Arguments**:
|
||||
> - point: 指定点
|
||||
|
||||
**Return**: 所求平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -265,11 +265,11 @@ def cal_parallel_plane3(self, point: 'Point3') -> 'Plane3':
|
||||
|
||||
**Description**: 判断两个平面是否平行。
|
||||
|
||||
**Return**: 是否平行
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**Return**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -319,12 +319,12 @@ def normal(self) -> 'Vector3':
|
||||
|
||||
**Description**: 工厂函数 由点和法向量构造平面(点法式构造)。
|
||||
|
||||
**Return**: 平面
|
||||
|
||||
**Arguments**:
|
||||
> - point: 平面上的一点
|
||||
> - normal: 法向量
|
||||
|
||||
**Return**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -353,13 +353,13 @@ def from_point_and_normal(cls, point: 'Point3', normal: 'Vector3') -> 'Plane3':
|
||||
|
||||
**Description**: 工厂函数 由三点构造平面。
|
||||
|
||||
**Return**: 平面
|
||||
|
||||
**Arguments**:
|
||||
> - p1: 点1
|
||||
> - p2: 点2
|
||||
> - p3: 点3
|
||||
|
||||
**Return**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -390,12 +390,12 @@ def from_three_points(cls, p1: 'Point3', p2: 'Point3', p3: 'Point3') -> 'Plane3'
|
||||
|
||||
**Description**: 工厂函数 由两直线构造平面。
|
||||
|
||||
**Return**: 平面
|
||||
|
||||
**Arguments**:
|
||||
> - l1: 直线1
|
||||
> - l2: 直线2
|
||||
|
||||
**Return**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -426,12 +426,12 @@ def from_two_lines(cls, l1: 'Line3', l2: 'Line3') -> 'Plane3':
|
||||
|
||||
**Description**: 工厂函数 由点和直线构造平面。
|
||||
|
||||
**Return**: 平面
|
||||
|
||||
**Arguments**:
|
||||
> - point: 面上一点
|
||||
> - line: 面上直线,不包含点
|
||||
|
||||
**Return**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -485,11 +485,11 @@ def __and__(self, other: 'Plane3') -> 'Line3 | None':
|
||||
|
||||
**Description**: 取两平面的交集(人话:交线)
|
||||
|
||||
**Return**: 不平行平面的交线,平面平行返回None
|
||||
|
||||
**Arguments**:
|
||||
> - other:
|
||||
|
||||
**Return**: 不平行平面的交线,平面平行返回None
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
|
@ -38,12 +38,12 @@ def __init__(self, x: float, y: float, z: float):
|
||||
|
||||
**Description**: 判断两个点是否近似相等。
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
**Arguments**:
|
||||
> - other:
|
||||
> - epsilon:
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
|
@ -7,13 +7,13 @@ title: mbcp.mp_math.utils
|
||||
|
||||
**Description**: 区间限定函数
|
||||
|
||||
**Return**: 限制后的值
|
||||
|
||||
**Arguments**:
|
||||
> - x: 待限定的值
|
||||
> - min_: 最小值
|
||||
> - max_: 最大值
|
||||
|
||||
**Return**: 限制后的值
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -40,13 +40,13 @@ def clamp(x: float, min_: float, max_: float) -> float:
|
||||
|
||||
**Description**: 判断两个数是否近似相等。或包装一个实数,用于判断是否近似于0。
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
**Arguments**:
|
||||
> - x: 数1
|
||||
> - y: 数2
|
||||
> - epsilon: 误差
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -72,12 +72,12 @@ def approx(x: float, y: float=0.0, epsilon: float=APPROX) -> bool:
|
||||
|
||||
**Description**: 获取数的符号。
|
||||
|
||||
**Return**: 符号 + - ""
|
||||
|
||||
**Arguments**:
|
||||
> - x: 数
|
||||
> - only_neg: 是否只返回负数的符号
|
||||
|
||||
**Return**: 符号 + - ""
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -109,12 +109,12 @@ def sign(x: float, only_neg: bool=False) -> str:
|
||||
1 -> +1
|
||||
0 -> ""
|
||||
|
||||
**Return**: 符号 + - ""
|
||||
|
||||
**Arguments**:
|
||||
> - x: 数
|
||||
> - only_neg: 是否只返回负数的符号
|
||||
|
||||
**Return**: 符号 + - ""
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
|
@ -38,12 +38,12 @@ def __init__(self, x: float, y: float, z: float):
|
||||
|
||||
**Description**: 判断两个向量是否近似相等。
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
**Arguments**:
|
||||
> - other:
|
||||
> - epsilon:
|
||||
|
||||
**Return**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -69,11 +69,11 @@ def approx(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**Description**: 计算两个向量之间的夹角。
|
||||
|
||||
**Return**: 夹角
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一个向量
|
||||
|
||||
**Return**: 夹角
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -101,11 +101,11 @@ def cal_angle(self, other: 'Vector3') -> 'AnyAngle':
|
||||
其余结果的模为平行四边形的面积。
|
||||
|
||||
|
||||
**Return**: 行列式的结果
|
||||
|
||||
**Arguments**:
|
||||
> - other:
|
||||
|
||||
**Return**: 行列式的结果
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -141,12 +141,12 @@ def cross(self, other: 'Vector3') -> 'Vector3':
|
||||
|
||||
**Description**: 判断两个向量是否近似平行。
|
||||
|
||||
**Return**: 是否近似平行
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一个向量
|
||||
> - epsilon: 允许的误差
|
||||
|
||||
**Return**: 是否近似平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -171,11 +171,11 @@ def is_approx_parallel(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**Description**: 判断两个向量是否平行。
|
||||
|
||||
**Return**: 是否平行
|
||||
|
||||
**Arguments**:
|
||||
> - other: 另一个向量
|
||||
|
||||
**Return**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
@ -370,11 +370,11 @@ def __add__(self, other):
|
||||
|
||||
**Description**: 判断两个向量是否相等。
|
||||
|
||||
**Return**: 是否相等
|
||||
|
||||
**Arguments**:
|
||||
> - other:
|
||||
|
||||
**Return**: 是否相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
|
@ -9,12 +9,12 @@ title: mbcp.presets.model
|
||||
|
||||
**Description**: 生成球体上的点集。
|
||||
|
||||
**Return**: List[Point3]: 球体上的点集。
|
||||
|
||||
**Arguments**:
|
||||
> - radius:
|
||||
> - density:
|
||||
|
||||
**Return**: List[Point3]: 球体上的点集。
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>Source code</b> </summary>
|
||||
|
@ -7,13 +7,13 @@ title: mbcp.mp_math.equation
|
||||
|
||||
**説明**: 求N元函数一阶偏导函数。这玩意不太稳定,慎用。
|
||||
|
||||
**戻り値**: 偏导函数
|
||||
|
||||
**引数**:
|
||||
> - func: 函数
|
||||
> - var: 变量位置,可为整数(一阶偏导)或整数元组(高阶偏导)
|
||||
> - epsilon: 偏移量
|
||||
|
||||
**戻り値**: 偏导函数
|
||||
|
||||
**例外**:
|
||||
> - ValueError 无效变量类型
|
||||
|
||||
|
@ -35,12 +35,12 @@ def __init__(self, point: 'Point3', direction: 'Vector3'):
|
||||
|
||||
**説明**: 判断两条直线是否近似相等。
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
**引数**:
|
||||
> - other: 另一条直线
|
||||
> - epsilon: 误差
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -65,11 +65,11 @@ def approx(self, other: 'Line3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**説明**: 计算直线和直线之间的夹角。
|
||||
|
||||
**戻り値**: 夹角弧度
|
||||
|
||||
**引数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**戻り値**: 夹角弧度
|
||||
|
||||
**例外**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -98,11 +98,11 @@ def cal_angle(self, other: 'Line3') -> 'AnyAngle':
|
||||
|
||||
**説明**: 计算直线和直线或点之间的距离。
|
||||
|
||||
**戻り値**: 距离
|
||||
|
||||
**引数**:
|
||||
> - other: 平行直线或点
|
||||
|
||||
**戻り値**: 距离
|
||||
|
||||
**例外**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -144,11 +144,11 @@ def cal_distance(self, other: 'Line3 | Point3') -> float:
|
||||
|
||||
**説明**: 计算两条直线的交点。
|
||||
|
||||
**戻り値**: 交点
|
||||
|
||||
**引数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**戻り値**: 交点
|
||||
|
||||
**例外**:
|
||||
> - ValueError 直线平行
|
||||
> - ValueError 直线不共面
|
||||
@ -183,11 +183,11 @@ def cal_intersection(self, other: 'Line3') -> 'Point3':
|
||||
|
||||
**説明**: 计算直线经过指定点p的垂线。
|
||||
|
||||
**戻り値**: 垂线
|
||||
|
||||
**引数**:
|
||||
> - point: 指定点
|
||||
|
||||
**戻り値**: 垂线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -211,11 +211,11 @@ def cal_perpendicular(self, point: 'Point3') -> 'Line3':
|
||||
|
||||
**説明**: 获取直线上的点。同一条直线,但起始点和方向向量不同,则同一个t对应的点不同。
|
||||
|
||||
**戻り値**: 点
|
||||
|
||||
**引数**:
|
||||
> - t: 参数t
|
||||
|
||||
**戻り値**: 点
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -262,12 +262,12 @@ def get_parametric_equations(self) -> tuple[OneSingleVarFunc, OneSingleVarFunc,
|
||||
|
||||
**説明**: 判断两条直线是否近似平行。
|
||||
|
||||
**戻り値**: 是否近似平行
|
||||
|
||||
**引数**:
|
||||
> - other: 另一条直线
|
||||
> - epsilon: 误差
|
||||
|
||||
**戻り値**: 是否近似平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -292,11 +292,11 @@ def is_approx_parallel(self, other: 'Line3', epsilon: float=1e-06) -> bool:
|
||||
|
||||
**説明**: 判断两条直线是否平行。
|
||||
|
||||
**戻り値**: 是否平行
|
||||
|
||||
**引数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**戻り値**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -320,11 +320,11 @@ def is_parallel(self, other: 'Line3') -> bool:
|
||||
|
||||
**説明**: 判断两条直线是否共线。
|
||||
|
||||
**戻り値**: 是否共线
|
||||
|
||||
**引数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**戻り値**: 是否共线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -348,11 +348,11 @@ def is_collinear(self, other: 'Line3') -> bool:
|
||||
|
||||
**説明**: 判断点是否在直线上。
|
||||
|
||||
**戻り値**: 是否在直线上
|
||||
|
||||
**引数**:
|
||||
> - point: 点
|
||||
|
||||
**戻り値**: 是否在直线上
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -377,11 +377,11 @@ def is_point_on(self, point: 'Point3') -> bool:
|
||||
**説明**: 判断两条直线是否共面。
|
||||
充要条件:两直线方向向量的叉乘与两直线上任意一点的向量的点积为0。
|
||||
|
||||
**戻り値**: 是否共面
|
||||
|
||||
**引数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**戻り値**: 是否共面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -438,12 +438,12 @@ def simplify(self):
|
||||
|
||||
**説明**: 工厂函数 由两点构造直线。
|
||||
|
||||
**戻り値**: 直线
|
||||
|
||||
**引数**:
|
||||
> - p1: 点1
|
||||
> - p2: 点2
|
||||
|
||||
**戻り値**: 直线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -470,11 +470,11 @@ def from_two_points(cls, p1: 'Point3', p2: 'Point3') -> 'Line3':
|
||||
|
||||
**説明**: 计算两条直线点集合的交集。重合线返回自身,平行线返回None,交线返回交点。
|
||||
|
||||
**戻り値**: 交点
|
||||
|
||||
**引数**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**戻り値**: 交点
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
|
@ -41,11 +41,11 @@ def __init__(self, a: float, b: float, c: float, d: float):
|
||||
|
||||
**説明**: 判断两个平面是否近似相等。
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
**引数**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -79,11 +79,11 @@ def approx(self, other: 'Plane3') -> bool:
|
||||
|
||||
**説明**: 计算平面与平面之间的夹角。
|
||||
|
||||
**戻り値**: 夹角弧度
|
||||
|
||||
**引数**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**戻り値**: 夹角弧度
|
||||
|
||||
**例外**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -117,11 +117,11 @@ def cal_angle(self, other: 'Line3 | Plane3') -> 'AnyAngle':
|
||||
|
||||
**説明**: 计算平面与平面或点之间的距离。
|
||||
|
||||
**戻り値**: 距离
|
||||
|
||||
**引数**:
|
||||
> - other: 另一个平面或点
|
||||
|
||||
**戻り値**: 距离
|
||||
|
||||
**例外**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -155,11 +155,11 @@ def cal_distance(self, other: 'Plane3 | Point3') -> float:
|
||||
|
||||
**説明**: 计算两平面的交线。
|
||||
|
||||
**戻り値**: 两平面的交线
|
||||
|
||||
**引数**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**戻り値**: 两平面的交线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -200,11 +200,11 @@ def cal_intersection_line3(self, other: 'Plane3') -> 'Line3':
|
||||
|
||||
**説明**: 计算平面与直线的交点。
|
||||
|
||||
**戻り値**: 交点
|
||||
|
||||
**引数**:
|
||||
> - other: 不与平面平行或在平面上的直线
|
||||
|
||||
**戻り値**: 交点
|
||||
|
||||
**例外**:
|
||||
> - ValueError 平面与直线平行或重合
|
||||
|
||||
@ -237,11 +237,11 @@ def cal_intersection_point3(self, other: 'Line3') -> 'Point3':
|
||||
|
||||
**説明**: 计算平行于该平面且过指定点的平面。
|
||||
|
||||
**戻り値**: 所求平面
|
||||
|
||||
**引数**:
|
||||
> - point: 指定点
|
||||
|
||||
**戻り値**: 所求平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -265,11 +265,11 @@ def cal_parallel_plane3(self, point: 'Point3') -> 'Plane3':
|
||||
|
||||
**説明**: 判断两个平面是否平行。
|
||||
|
||||
**戻り値**: 是否平行
|
||||
|
||||
**引数**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**戻り値**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -319,12 +319,12 @@ def normal(self) -> 'Vector3':
|
||||
|
||||
**説明**: 工厂函数 由点和法向量构造平面(点法式构造)。
|
||||
|
||||
**戻り値**: 平面
|
||||
|
||||
**引数**:
|
||||
> - point: 平面上的一点
|
||||
> - normal: 法向量
|
||||
|
||||
**戻り値**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -353,13 +353,13 @@ def from_point_and_normal(cls, point: 'Point3', normal: 'Vector3') -> 'Plane3':
|
||||
|
||||
**説明**: 工厂函数 由三点构造平面。
|
||||
|
||||
**戻り値**: 平面
|
||||
|
||||
**引数**:
|
||||
> - p1: 点1
|
||||
> - p2: 点2
|
||||
> - p3: 点3
|
||||
|
||||
**戻り値**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -390,12 +390,12 @@ def from_three_points(cls, p1: 'Point3', p2: 'Point3', p3: 'Point3') -> 'Plane3'
|
||||
|
||||
**説明**: 工厂函数 由两直线构造平面。
|
||||
|
||||
**戻り値**: 平面
|
||||
|
||||
**引数**:
|
||||
> - l1: 直线1
|
||||
> - l2: 直线2
|
||||
|
||||
**戻り値**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -426,12 +426,12 @@ def from_two_lines(cls, l1: 'Line3', l2: 'Line3') -> 'Plane3':
|
||||
|
||||
**説明**: 工厂函数 由点和直线构造平面。
|
||||
|
||||
**戻り値**: 平面
|
||||
|
||||
**引数**:
|
||||
> - point: 面上一点
|
||||
> - line: 面上直线,不包含点
|
||||
|
||||
**戻り値**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -485,11 +485,11 @@ def __and__(self, other: 'Plane3') -> 'Line3 | None':
|
||||
|
||||
**説明**: 取两平面的交集(人话:交线)
|
||||
|
||||
**戻り値**: 不平行平面的交线,平面平行返回None
|
||||
|
||||
**引数**:
|
||||
> - other:
|
||||
|
||||
**戻り値**: 不平行平面的交线,平面平行返回None
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
|
@ -38,12 +38,12 @@ def __init__(self, x: float, y: float, z: float):
|
||||
|
||||
**説明**: 判断两个点是否近似相等。
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
**引数**:
|
||||
> - other:
|
||||
> - epsilon:
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
|
@ -7,13 +7,13 @@ title: mbcp.mp_math.utils
|
||||
|
||||
**説明**: 区间限定函数
|
||||
|
||||
**戻り値**: 限制后的值
|
||||
|
||||
**引数**:
|
||||
> - x: 待限定的值
|
||||
> - min_: 最小值
|
||||
> - max_: 最大值
|
||||
|
||||
**戻り値**: 限制后的值
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -40,13 +40,13 @@ def clamp(x: float, min_: float, max_: float) -> float:
|
||||
|
||||
**説明**: 判断两个数是否近似相等。或包装一个实数,用于判断是否近似于0。
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
**引数**:
|
||||
> - x: 数1
|
||||
> - y: 数2
|
||||
> - epsilon: 误差
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -72,12 +72,12 @@ def approx(x: float, y: float=0.0, epsilon: float=APPROX) -> bool:
|
||||
|
||||
**説明**: 获取数的符号。
|
||||
|
||||
**戻り値**: 符号 + - ""
|
||||
|
||||
**引数**:
|
||||
> - x: 数
|
||||
> - only_neg: 是否只返回负数的符号
|
||||
|
||||
**戻り値**: 符号 + - ""
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -109,12 +109,12 @@ def sign(x: float, only_neg: bool=False) -> str:
|
||||
1 -> +1
|
||||
0 -> ""
|
||||
|
||||
**戻り値**: 符号 + - ""
|
||||
|
||||
**引数**:
|
||||
> - x: 数
|
||||
> - only_neg: 是否只返回负数的符号
|
||||
|
||||
**戻り値**: 符号 + - ""
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
|
@ -38,12 +38,12 @@ def __init__(self, x: float, y: float, z: float):
|
||||
|
||||
**説明**: 判断两个向量是否近似相等。
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
**引数**:
|
||||
> - other:
|
||||
> - epsilon:
|
||||
|
||||
**戻り値**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -69,11 +69,11 @@ def approx(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**説明**: 计算两个向量之间的夹角。
|
||||
|
||||
**戻り値**: 夹角
|
||||
|
||||
**引数**:
|
||||
> - other: 另一个向量
|
||||
|
||||
**戻り値**: 夹角
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -101,11 +101,11 @@ def cal_angle(self, other: 'Vector3') -> 'AnyAngle':
|
||||
其余结果的模为平行四边形的面积。
|
||||
|
||||
|
||||
**戻り値**: 行列式的结果
|
||||
|
||||
**引数**:
|
||||
> - other:
|
||||
|
||||
**戻り値**: 行列式的结果
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -141,12 +141,12 @@ def cross(self, other: 'Vector3') -> 'Vector3':
|
||||
|
||||
**説明**: 判断两个向量是否近似平行。
|
||||
|
||||
**戻り値**: 是否近似平行
|
||||
|
||||
**引数**:
|
||||
> - other: 另一个向量
|
||||
> - epsilon: 允许的误差
|
||||
|
||||
**戻り値**: 是否近似平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -171,11 +171,11 @@ def is_approx_parallel(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**説明**: 判断两个向量是否平行。
|
||||
|
||||
**戻り値**: 是否平行
|
||||
|
||||
**引数**:
|
||||
> - other: 另一个向量
|
||||
|
||||
**戻り値**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
@ -370,11 +370,11 @@ def __add__(self, other):
|
||||
|
||||
**説明**: 判断两个向量是否相等。
|
||||
|
||||
**戻り値**: 是否相等
|
||||
|
||||
**引数**:
|
||||
> - other:
|
||||
|
||||
**戻り値**: 是否相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
|
@ -9,12 +9,12 @@ title: mbcp.presets.model
|
||||
|
||||
**説明**: 生成球体上的点集。
|
||||
|
||||
**戻り値**: List[Point3]: 球体上的点集。
|
||||
|
||||
**引数**:
|
||||
> - radius:
|
||||
> - density:
|
||||
|
||||
**戻り値**: List[Point3]: 球体上的点集。
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>ソースコード</b> </summary>
|
||||
|
@ -7,13 +7,13 @@ title: mbcp.mp_math.equation
|
||||
|
||||
**説明**: 求N元函数一阶偏导函数。这玩意不太稳定,慎用。
|
||||
|
||||
**返回**: 偏导函数
|
||||
|
||||
**變數説明**:
|
||||
> - func: 函数
|
||||
> - var: 变量位置,可为整数(一阶偏导)或整数元组(高阶偏导)
|
||||
> - epsilon: 偏移量
|
||||
|
||||
**返回**: 偏导函数
|
||||
|
||||
**抛出**:
|
||||
> - ValueError 无效变量类型
|
||||
|
||||
|
@ -35,12 +35,12 @@ def __init__(self, point: 'Point3', direction: 'Vector3'):
|
||||
|
||||
**説明**: 判断两条直线是否近似相等。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一条直线
|
||||
> - epsilon: 误差
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -65,11 +65,11 @@ def approx(self, other: 'Line3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**説明**: 计算直线和直线之间的夹角。
|
||||
|
||||
**返回**: 夹角弧度
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 夹角弧度
|
||||
|
||||
**抛出**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -98,11 +98,11 @@ def cal_angle(self, other: 'Line3') -> 'AnyAngle':
|
||||
|
||||
**説明**: 计算直线和直线或点之间的距离。
|
||||
|
||||
**返回**: 距离
|
||||
|
||||
**變數説明**:
|
||||
> - other: 平行直线或点
|
||||
|
||||
**返回**: 距离
|
||||
|
||||
**抛出**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -144,11 +144,11 @@ def cal_distance(self, other: 'Line3 | Point3') -> float:
|
||||
|
||||
**説明**: 计算两条直线的交点。
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**抛出**:
|
||||
> - ValueError 直线平行
|
||||
> - ValueError 直线不共面
|
||||
@ -183,11 +183,11 @@ def cal_intersection(self, other: 'Line3') -> 'Point3':
|
||||
|
||||
**説明**: 计算直线经过指定点p的垂线。
|
||||
|
||||
**返回**: 垂线
|
||||
|
||||
**變數説明**:
|
||||
> - point: 指定点
|
||||
|
||||
**返回**: 垂线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -211,11 +211,11 @@ def cal_perpendicular(self, point: 'Point3') -> 'Line3':
|
||||
|
||||
**説明**: 获取直线上的点。同一条直线,但起始点和方向向量不同,则同一个t对应的点不同。
|
||||
|
||||
**返回**: 点
|
||||
|
||||
**變數説明**:
|
||||
> - t: 参数t
|
||||
|
||||
**返回**: 点
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -262,12 +262,12 @@ def get_parametric_equations(self) -> tuple[OneSingleVarFunc, OneSingleVarFunc,
|
||||
|
||||
**説明**: 判断两条直线是否近似平行。
|
||||
|
||||
**返回**: 是否近似平行
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一条直线
|
||||
> - epsilon: 误差
|
||||
|
||||
**返回**: 是否近似平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -292,11 +292,11 @@ def is_approx_parallel(self, other: 'Line3', epsilon: float=1e-06) -> bool:
|
||||
|
||||
**説明**: 判断两条直线是否平行。
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -320,11 +320,11 @@ def is_parallel(self, other: 'Line3') -> bool:
|
||||
|
||||
**説明**: 判断两条直线是否共线。
|
||||
|
||||
**返回**: 是否共线
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 是否共线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -348,11 +348,11 @@ def is_collinear(self, other: 'Line3') -> bool:
|
||||
|
||||
**説明**: 判断点是否在直线上。
|
||||
|
||||
**返回**: 是否在直线上
|
||||
|
||||
**變數説明**:
|
||||
> - point: 点
|
||||
|
||||
**返回**: 是否在直线上
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -377,11 +377,11 @@ def is_point_on(self, point: 'Point3') -> bool:
|
||||
**説明**: 判断两条直线是否共面。
|
||||
充要条件:两直线方向向量的叉乘与两直线上任意一点的向量的点积为0。
|
||||
|
||||
**返回**: 是否共面
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 是否共面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -438,12 +438,12 @@ def simplify(self):
|
||||
|
||||
**説明**: 工厂函数 由两点构造直线。
|
||||
|
||||
**返回**: 直线
|
||||
|
||||
**變數説明**:
|
||||
> - p1: 点1
|
||||
> - p2: 点2
|
||||
|
||||
**返回**: 直线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -470,11 +470,11 @@ def from_two_points(cls, p1: 'Point3', p2: 'Point3') -> 'Line3':
|
||||
|
||||
**説明**: 计算两条直线点集合的交集。重合线返回自身,平行线返回None,交线返回交点。
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一条直线
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
|
@ -41,11 +41,11 @@ def __init__(self, a: float, b: float, c: float, d: float):
|
||||
|
||||
**説明**: 判断两个平面是否近似相等。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -79,11 +79,11 @@ def approx(self, other: 'Plane3') -> bool:
|
||||
|
||||
**説明**: 计算平面与平面之间的夹角。
|
||||
|
||||
**返回**: 夹角弧度
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**返回**: 夹角弧度
|
||||
|
||||
**抛出**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -117,11 +117,11 @@ def cal_angle(self, other: 'Line3 | Plane3') -> 'AnyAngle':
|
||||
|
||||
**説明**: 计算平面与平面或点之间的距离。
|
||||
|
||||
**返回**: 距离
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一个平面或点
|
||||
|
||||
**返回**: 距离
|
||||
|
||||
**抛出**:
|
||||
> - TypeError 不支持的类型
|
||||
|
||||
@ -155,11 +155,11 @@ def cal_distance(self, other: 'Plane3 | Point3') -> float:
|
||||
|
||||
**説明**: 计算两平面的交线。
|
||||
|
||||
**返回**: 两平面的交线
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**返回**: 两平面的交线
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -200,11 +200,11 @@ def cal_intersection_line3(self, other: 'Plane3') -> 'Line3':
|
||||
|
||||
**説明**: 计算平面与直线的交点。
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**變數説明**:
|
||||
> - other: 不与平面平行或在平面上的直线
|
||||
|
||||
**返回**: 交点
|
||||
|
||||
**抛出**:
|
||||
> - ValueError 平面与直线平行或重合
|
||||
|
||||
@ -237,11 +237,11 @@ def cal_intersection_point3(self, other: 'Line3') -> 'Point3':
|
||||
|
||||
**説明**: 计算平行于该平面且过指定点的平面。
|
||||
|
||||
**返回**: 所求平面
|
||||
|
||||
**變數説明**:
|
||||
> - point: 指定点
|
||||
|
||||
**返回**: 所求平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -265,11 +265,11 @@ def cal_parallel_plane3(self, point: 'Point3') -> 'Plane3':
|
||||
|
||||
**説明**: 判断两个平面是否平行。
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一个平面
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -319,12 +319,12 @@ def normal(self) -> 'Vector3':
|
||||
|
||||
**説明**: 工厂函数 由点和法向量构造平面(点法式构造)。
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
**變數説明**:
|
||||
> - point: 平面上的一点
|
||||
> - normal: 法向量
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -353,13 +353,13 @@ def from_point_and_normal(cls, point: 'Point3', normal: 'Vector3') -> 'Plane3':
|
||||
|
||||
**説明**: 工厂函数 由三点构造平面。
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
**變數説明**:
|
||||
> - p1: 点1
|
||||
> - p2: 点2
|
||||
> - p3: 点3
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -390,12 +390,12 @@ def from_three_points(cls, p1: 'Point3', p2: 'Point3', p3: 'Point3') -> 'Plane3'
|
||||
|
||||
**説明**: 工厂函数 由两直线构造平面。
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
**變數説明**:
|
||||
> - l1: 直线1
|
||||
> - l2: 直线2
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -426,12 +426,12 @@ def from_two_lines(cls, l1: 'Line3', l2: 'Line3') -> 'Plane3':
|
||||
|
||||
**説明**: 工厂函数 由点和直线构造平面。
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
**變數説明**:
|
||||
> - point: 面上一点
|
||||
> - line: 面上直线,不包含点
|
||||
|
||||
**返回**: 平面
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -485,11 +485,11 @@ def __and__(self, other: 'Plane3') -> 'Line3 | None':
|
||||
|
||||
**説明**: 取两平面的交集(人话:交线)
|
||||
|
||||
**返回**: 不平行平面的交线,平面平行返回None
|
||||
|
||||
**變數説明**:
|
||||
> - other:
|
||||
|
||||
**返回**: 不平行平面的交线,平面平行返回None
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
|
@ -38,12 +38,12 @@ def __init__(self, x: float, y: float, z: float):
|
||||
|
||||
**説明**: 判断两个点是否近似相等。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**變數説明**:
|
||||
> - other:
|
||||
> - epsilon:
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
|
@ -7,13 +7,13 @@ title: mbcp.mp_math.utils
|
||||
|
||||
**説明**: 区间限定函数
|
||||
|
||||
**返回**: 限制后的值
|
||||
|
||||
**變數説明**:
|
||||
> - x: 待限定的值
|
||||
> - min_: 最小值
|
||||
> - max_: 最大值
|
||||
|
||||
**返回**: 限制后的值
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -40,13 +40,13 @@ def clamp(x: float, min_: float, max_: float) -> float:
|
||||
|
||||
**説明**: 判断两个数是否近似相等。或包装一个实数,用于判断是否近似于0。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**變數説明**:
|
||||
> - x: 数1
|
||||
> - y: 数2
|
||||
> - epsilon: 误差
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -72,12 +72,12 @@ def approx(x: float, y: float=0.0, epsilon: float=APPROX) -> bool:
|
||||
|
||||
**説明**: 获取数的符号。
|
||||
|
||||
**返回**: 符号 + - ""
|
||||
|
||||
**變數説明**:
|
||||
> - x: 数
|
||||
> - only_neg: 是否只返回负数的符号
|
||||
|
||||
**返回**: 符号 + - ""
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -109,12 +109,12 @@ def sign(x: float, only_neg: bool=False) -> str:
|
||||
1 -> +1
|
||||
0 -> ""
|
||||
|
||||
**返回**: 符号 + - ""
|
||||
|
||||
**變數説明**:
|
||||
> - x: 数
|
||||
> - only_neg: 是否只返回负数的符号
|
||||
|
||||
**返回**: 符号 + - ""
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
|
@ -38,12 +38,12 @@ def __init__(self, x: float, y: float, z: float):
|
||||
|
||||
**説明**: 判断两个向量是否近似相等。
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
**變數説明**:
|
||||
> - other:
|
||||
> - epsilon:
|
||||
|
||||
**返回**: 是否近似相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -69,11 +69,11 @@ def approx(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**説明**: 计算两个向量之间的夹角。
|
||||
|
||||
**返回**: 夹角
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一个向量
|
||||
|
||||
**返回**: 夹角
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -101,11 +101,11 @@ def cal_angle(self, other: 'Vector3') -> 'AnyAngle':
|
||||
其余结果的模为平行四边形的面积。
|
||||
|
||||
|
||||
**返回**: 行列式的结果
|
||||
|
||||
**變數説明**:
|
||||
> - other:
|
||||
|
||||
**返回**: 行列式的结果
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -141,12 +141,12 @@ def cross(self, other: 'Vector3') -> 'Vector3':
|
||||
|
||||
**説明**: 判断两个向量是否近似平行。
|
||||
|
||||
**返回**: 是否近似平行
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一个向量
|
||||
> - epsilon: 允许的误差
|
||||
|
||||
**返回**: 是否近似平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -171,11 +171,11 @@ def is_approx_parallel(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
|
||||
|
||||
**説明**: 判断两个向量是否平行。
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
**變數説明**:
|
||||
> - other: 另一个向量
|
||||
|
||||
**返回**: 是否平行
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
@ -370,11 +370,11 @@ def __add__(self, other):
|
||||
|
||||
**説明**: 判断两个向量是否相等。
|
||||
|
||||
**返回**: 是否相等
|
||||
|
||||
**變數説明**:
|
||||
> - other:
|
||||
|
||||
**返回**: 是否相等
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
|
@ -9,12 +9,12 @@ title: mbcp.presets.model
|
||||
|
||||
**説明**: 生成球体上的点集。
|
||||
|
||||
**返回**: List[Point3]: 球体上的点集。
|
||||
|
||||
**變數説明**:
|
||||
> - radius:
|
||||
> - density:
|
||||
|
||||
**返回**: List[Point3]: 球体上的点集。
|
||||
|
||||
|
||||
<details>
|
||||
<summary> <b>源碼</b> </summary>
|
||||
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午12:52
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : __init__.py.py
|
||||
@Software: PyCharm
|
||||
"""
|
@ -1,46 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午4:08
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : __main__.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
# command line tool
|
||||
# args[0] path
|
||||
# -o|--output output path
|
||||
# -l|--lang zh-Hans en jp default zh-Hans
|
||||
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
from litedoc.output import generate_from_module
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate documentation from Python modules.")
|
||||
parser.add_argument("path", type=str, help="Path to the Python module or package.")
|
||||
parser.add_argument("-o", "--output", default="doc-output", type=str, help="Output directory.")
|
||||
parser.add_argument("-c", "--contain-top", action="store_true", help="Whether to contain top-level dir in output dir.")
|
||||
parser.add_argument("-l", "--lang", nargs='+', default=["zh-Hans"], type=str, help="Languages of the document.")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not os.path.exists(args.path):
|
||||
print(f"Error: The path {args.path} does not exist.")
|
||||
sys.exit(1)
|
||||
|
||||
if not os.path.exists(args.output):
|
||||
os.makedirs(args.output)
|
||||
|
||||
langs = args.lang
|
||||
for lang in langs:
|
||||
generate_from_module(args.path, args.output, with_top=args.contain_top, lang=lang)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午1:46
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : __init__.py.py
|
||||
@Software: PyCharm
|
||||
"""
|
@ -1,154 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午1:46
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : docstring.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from litedoc.i18n import get_text
|
||||
|
||||
|
||||
class Attr(BaseModel):
|
||||
name: str
|
||||
type: str = ""
|
||||
desc: str = ""
|
||||
|
||||
|
||||
class Args(BaseModel):
|
||||
name: str
|
||||
type: str = ""
|
||||
desc: str = ""
|
||||
|
||||
|
||||
class Return(BaseModel):
|
||||
desc: str = ""
|
||||
|
||||
|
||||
class Exception_(BaseModel):
|
||||
name: str
|
||||
desc: str = ""
|
||||
|
||||
|
||||
class Raise(BaseModel):
|
||||
exceptions: list[Exception_] = []
|
||||
|
||||
|
||||
class Example(BaseModel):
|
||||
desc: str = ""
|
||||
input: str = ""
|
||||
output: str = ""
|
||||
|
||||
|
||||
class Docstring(BaseModel):
|
||||
desc: str = ""
|
||||
args: list[Args] = []
|
||||
attrs: list[Attr] = []
|
||||
return_: Optional[Return] = None
|
||||
raise_: list[Exception_] = []
|
||||
example: list[Example] = []
|
||||
|
||||
def add_desc(self, desc: str):
|
||||
if self.desc == "":
|
||||
self.desc = desc
|
||||
else:
|
||||
self.desc += "\n" + desc
|
||||
|
||||
def add_arg(self, name: str, type_: str = "", desc: str = ""):
|
||||
self.args.append(Args(name=name, type=type_, desc=desc))
|
||||
|
||||
def add_attrs(self, name: str, type_: str = "", desc: str = ""):
|
||||
self.attrs.append(Attr(name=name, type=type_, desc=desc))
|
||||
|
||||
def add_return(self, desc: str = ""):
|
||||
self.return_ = Return(desc=desc)
|
||||
|
||||
def add_raise(self, name: str, desc: str = ""):
|
||||
self.raise_.append(Exception_(name=name, desc=desc))
|
||||
|
||||
def add_example(self, desc: str = "", input_: str = "", output: str = ""):
|
||||
self.example.append(Example(desc=desc, input=input_, output=output))
|
||||
|
||||
def reduction(self) -> str:
|
||||
"""
|
||||
通过解析结果还原docstring
|
||||
Args:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
ret = ""
|
||||
ret += self.desc + "\n"
|
||||
if self.args:
|
||||
ret += "Args:\n"
|
||||
for arg in self.args:
|
||||
ret += f" {arg.name}: {arg.type}\n {arg.desc}\n"
|
||||
if self.attrs:
|
||||
ret += "Attributes:\n"
|
||||
for attr in self.attrs:
|
||||
ret += f" {attr.name}: {attr.type}\n {attr.desc}\n"
|
||||
if self.return_:
|
||||
ret += "Returns:\n"
|
||||
ret += f" {self.return_.desc}\n"
|
||||
|
||||
if self.raise_:
|
||||
ret += "Raises:\n"
|
||||
for exception in self.raise_:
|
||||
ret += f" {exception.name}\n {exception.desc}\n"
|
||||
|
||||
if self.example:
|
||||
ret += "Examples:\n"
|
||||
for example in self.example:
|
||||
ret += f" {example.desc}\n Input: {example.input}\n Output: {example.output}\n"
|
||||
|
||||
return ret
|
||||
|
||||
def markdown(self, lang: str, indent: int = 4, is_classmethod: bool = False) -> str:
|
||||
"""
|
||||
生成markdown文档
|
||||
Args:
|
||||
is_classmethod:
|
||||
lang:
|
||||
indent:
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
PREFIX = "" * indent
|
||||
ret = ""
|
||||
# ret += self.desc + "\n\n"
|
||||
# print(self.reduction())
|
||||
# print(self.desc, self.return_)
|
||||
# 单数属性
|
||||
if self.desc:
|
||||
ret += PREFIX + f"\n**{get_text(lang, 'desc')}**: {self.desc}\n"
|
||||
if self.return_ is not None:
|
||||
ret += PREFIX + f"\n**{get_text(lang, 'docstring.return')}**: {self.return_.desc}\n"
|
||||
|
||||
# 复数属性
|
||||
if self.args:
|
||||
ret += PREFIX + f"\n**{get_text(lang, 'docstring.args')}**:\n"
|
||||
for arg in self.args:
|
||||
ret += PREFIX + f"> - {arg.name}: {arg.type} {arg.desc}\n"
|
||||
if self.attrs:
|
||||
ret += PREFIX + f"\n**{get_text(lang, 'docstring.attrs')}**:\n"
|
||||
for attr in self.attrs:
|
||||
ret += PREFIX + f"> - {attr.name}: {attr.type} {attr.desc}\n"
|
||||
if self.raise_:
|
||||
ret += PREFIX + f"\n**{get_text(lang, 'docstring.raises')}**:\n"
|
||||
for exception in self.raise_:
|
||||
ret += PREFIX + f"> - {exception.name} {exception.desc}\n"
|
||||
if self.example:
|
||||
ret += PREFIX + f"\n**{get_text(lang, 'docstring.example')}**:\n"
|
||||
for example in self.example:
|
||||
ret += PREFIX + f" - {example.desc}\n> **{get_text(lang, 'docs.input')}**: {example.input}\n> **{get_text(lang, 'docs.output')}**: {example.output}\n"
|
||||
return ret
|
||||
|
||||
def __str__(self):
|
||||
return self.desc
|
@ -1,192 +0,0 @@
|
||||
"""
|
||||
Google docstring parser for Python.
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
from litedoc.docstring.docstring import Docstring
|
||||
|
||||
|
||||
class Parser:
|
||||
...
|
||||
|
||||
|
||||
class GoogleDocstringParser(Parser):
|
||||
_tokens = {
|
||||
"Args" : "args",
|
||||
"Arguments" : "args",
|
||||
"参数" : "args",
|
||||
|
||||
"Return" : "return",
|
||||
"Returns" : "return",
|
||||
"返回" : "return",
|
||||
|
||||
"Attribute" : "attribute",
|
||||
"Attributes" : "attribute",
|
||||
"属性" : "attribute",
|
||||
|
||||
"Raises" : "raises",
|
||||
"Raise" : "raises",
|
||||
"引发" : "raises",
|
||||
|
||||
"Example" : "example",
|
||||
"Examples" : "example",
|
||||
"示例" : "example",
|
||||
|
||||
"Yields" : "yields",
|
||||
"Yield" : "yields",
|
||||
"产出" : "yields",
|
||||
|
||||
"Requires" : "requires",
|
||||
"Require" : "requires",
|
||||
"需要" : "requires",
|
||||
|
||||
"FrontMatter": "front_matter",
|
||||
"前言" : "front_matter",
|
||||
}
|
||||
|
||||
def __init__(self, docstring: str, indent: int = 4):
|
||||
self.lines = docstring.splitlines()
|
||||
self.indent = indent
|
||||
self.lineno = 0 # Current line number
|
||||
self.char = 0 # Current character position
|
||||
|
||||
self.docstring = Docstring()
|
||||
|
||||
def read_line(self, move: bool = True) -> str:
|
||||
"""
|
||||
每次读取一行
|
||||
Args:
|
||||
move: 是否移动指针
|
||||
Returns:
|
||||
"""
|
||||
if self.lineno >= len(self.lines):
|
||||
return ""
|
||||
line = self.lines[self.lineno]
|
||||
if move:
|
||||
self.lineno += 1
|
||||
return line
|
||||
|
||||
def match_token(self) -> Optional[str]:
|
||||
"""
|
||||
解析下一行的token
|
||||
Returns:
|
||||
|
||||
"""
|
||||
for token in self._tokens:
|
||||
line = self.read_line(move=False)
|
||||
if line.strip().startswith(token):
|
||||
self.lineno += 1
|
||||
return self._tokens[token]
|
||||
return None
|
||||
|
||||
def parse_args(self):
|
||||
"""
|
||||
依次解析后面的参数行,直到缩进小于等于当前行的缩进
|
||||
"""
|
||||
while line := self.match_next_line():
|
||||
if ":" in line:
|
||||
name, desc = line.split(":", 1)
|
||||
self.docstring.add_arg(name.strip(), desc.strip())
|
||||
else:
|
||||
self.docstring.add_arg(line.strip())
|
||||
|
||||
def parse_return(self):
|
||||
"""
|
||||
解析返回值行
|
||||
"""
|
||||
if line := self.match_next_line():
|
||||
self.docstring.add_return(line.strip())
|
||||
|
||||
def parse_raises(self):
|
||||
"""
|
||||
解析异常行
|
||||
"""
|
||||
while line := self.match_next_line():
|
||||
if ":" in line:
|
||||
name, desc = line.split(":", 1)
|
||||
self.docstring.add_raise(name.strip(), desc.strip())
|
||||
else:
|
||||
self.docstring.add_raise(line.strip())
|
||||
|
||||
def parse_example(self):
|
||||
"""
|
||||
解析示例行
|
||||
"""
|
||||
while line := self.match_next_line():
|
||||
if ":" in line:
|
||||
name, desc = line.split(":", 1)
|
||||
self.docstring.add_example(name.strip(), desc.strip())
|
||||
else:
|
||||
self.docstring.add_example(line.strip())
|
||||
|
||||
def parse_attrs(self):
|
||||
"""
|
||||
解析属性行
|
||||
"""
|
||||
while line := self.match_next_line():
|
||||
if ":" in line:
|
||||
name, desc = line.split(":", 1)
|
||||
self.docstring.add_attrs(name.strip(), desc.strip())
|
||||
else:
|
||||
self.docstring.add_attrs(line.strip())
|
||||
|
||||
def match_next_line(self) -> Optional[str]:
|
||||
"""
|
||||
在一个子解析器中,解析下一行,直到缩进小于等于当前行的缩进
|
||||
Returns:
|
||||
"""
|
||||
line = self.read_line(move=False)
|
||||
if line.startswith(" " * self.indent):
|
||||
self.lineno += 1
|
||||
return line[self.indent:]
|
||||
else:
|
||||
return None
|
||||
|
||||
def parse(self) -> Docstring:
|
||||
"""
|
||||
逐行解析,直到遇到EOS
|
||||
|
||||
最开始未解析到的内容全部加入desc
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
add_desc = True
|
||||
while self.lineno < len(self.lines):
|
||||
token = self.match_token()
|
||||
if token is None and add_desc:
|
||||
self.docstring.add_desc(self.lines[self.lineno].strip())
|
||||
|
||||
if token is not None:
|
||||
add_desc = False
|
||||
|
||||
match token:
|
||||
case "args":
|
||||
self.parse_args()
|
||||
case "return":
|
||||
self.parse_return()
|
||||
case "attribute":
|
||||
self.parse_attrs()
|
||||
case "raises":
|
||||
self.parse_raises()
|
||||
case "example":
|
||||
self.parse_example()
|
||||
case _:
|
||||
self.lineno += 1
|
||||
|
||||
return self.docstring
|
||||
|
||||
|
||||
class NumpyDocstringParser(Parser):
|
||||
...
|
||||
|
||||
|
||||
class ReStructuredParser(Parser):
|
||||
...
|
||||
|
||||
|
||||
def parse(docstring: str, parser: str = "google", indent: int = 4) -> Docstring:
|
||||
if parser == "google":
|
||||
return GoogleDocstringParser(docstring, indent).parse()
|
||||
else:
|
||||
raise ValueError(f"Unknown parser: {parser}")
|
131
litedoc/i18n.py
131
litedoc/i18n.py
@ -1,131 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Internationalization module.
|
||||
"""
|
||||
from typing import Optional, TypeAlias
|
||||
|
||||
NestedDict: TypeAlias = dict[str, 'str | NestedDict']
|
||||
|
||||
i18n_dict: dict[str, NestedDict] = {
|
||||
"en" : {
|
||||
"docstring": {
|
||||
"args" : "Arguments",
|
||||
"return" : "Return",
|
||||
"attribute": "Attribute",
|
||||
"raises" : "Raises",
|
||||
"example" : "Examples",
|
||||
"yields" : "Yields",
|
||||
},
|
||||
"src": "Source code",
|
||||
"desc": "Description",
|
||||
"type": "Type",
|
||||
},
|
||||
"zh-Hans": {
|
||||
"docstring": {
|
||||
"args" : "参数",
|
||||
"return" : "返回",
|
||||
"attribute": "属性",
|
||||
"raises" : "引发",
|
||||
"example" : "示例",
|
||||
"yields" : "产出",
|
||||
},
|
||||
"src": "源代码",
|
||||
"desc": "说明",
|
||||
"type": "类型",
|
||||
},
|
||||
"zh-Hant": {
|
||||
"docstring": {
|
||||
"args" : "變數説明",
|
||||
"return" : "返回",
|
||||
"attribute": "屬性",
|
||||
"raises" : "抛出",
|
||||
"example" : "範例",
|
||||
"yields" : "產出",
|
||||
},
|
||||
"src": "源碼",
|
||||
"desc": "説明",
|
||||
"type": "類型",
|
||||
},
|
||||
"ja" : {
|
||||
"docstring": {
|
||||
"args" : "引数",
|
||||
"return" : "戻り値",
|
||||
"attribute": "属性",
|
||||
"raises" : "例外",
|
||||
"example" : "例",
|
||||
"yields" : "生成",
|
||||
},
|
||||
"src": "ソースコード",
|
||||
"desc": "説明",
|
||||
"type": "タイプ",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def flat_i18n_dict(data: dict[str, NestedDict]) -> dict[str, dict[str, str]]:
|
||||
"""
|
||||
Flatten i18n_dict.
|
||||
Examples:
|
||||
```python
|
||||
{
|
||||
"en": {
|
||||
"docs": {
|
||||
"key1": "val1",
|
||||
"key2": "val2",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
to
|
||||
|
||||
```python
|
||||
{
|
||||
"en": {
|
||||
"docs.key1": "val1",
|
||||
"docs.key2": "val2",
|
||||
}
|
||||
}
|
||||
```
|
||||
Returns:
|
||||
"""
|
||||
ret: dict[str, dict[str, str]] = {}
|
||||
|
||||
def _flat(_lang_data: NestedDict) -> dict[str, str]:
|
||||
res = {}
|
||||
for k, v in _lang_data.items():
|
||||
if isinstance(v, dict):
|
||||
for kk, vv in _flat(v).items():
|
||||
res[f"{k}.{kk}"] = vv
|
||||
else:
|
||||
res[k] = v
|
||||
return res
|
||||
|
||||
for lang, lang_data in data.items():
|
||||
ret[lang] = _flat(lang_data)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
i18n_flat_dict = flat_i18n_dict(i18n_dict)
|
||||
|
||||
|
||||
def get_text(lang: str, key: str, default: Optional[str] = None, fallback: Optional[str] = "en") -> str:
|
||||
"""
|
||||
Get text from i18n_dict.
|
||||
Args:
|
||||
lang: language name
|
||||
key: text key
|
||||
default: default text, if None return fallback language or key
|
||||
fallback: fallback language, priority is higher than default
|
||||
Returns:
|
||||
str: text
|
||||
"""
|
||||
if lang in i18n_flat_dict:
|
||||
if key in i18n_flat_dict[lang]:
|
||||
return i18n_flat_dict[lang][key]
|
||||
|
||||
if fallback is not None:
|
||||
return i18n_flat_dict.get(fallback, {}).get(key, default or key)
|
||||
else:
|
||||
return default or key
|
@ -1,107 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午3:59
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : output.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
import os.path
|
||||
|
||||
from litedoc.style.markdown import generate
|
||||
from litedoc.syntax.astparser import AstParser
|
||||
|
||||
|
||||
def write_to_file(content: str, output: str) -> None:
|
||||
"""
|
||||
Write content to file.
|
||||
|
||||
Args:
|
||||
content: str, content to write.
|
||||
output: str, path to output file.
|
||||
"""
|
||||
if not os.path.exists(os.path.dirname(output)):
|
||||
os.makedirs(os.path.dirname(output))
|
||||
|
||||
with open(output, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
def get_file_list(module_folder: str):
|
||||
file_list = []
|
||||
for root, dirs, files in os.walk(module_folder):
|
||||
for file in files:
|
||||
if file.endswith((".py", ".pyi")):
|
||||
file_list.append(os.path.join(root, file))
|
||||
return file_list
|
||||
|
||||
|
||||
def get_relative_path(base_path: str, target_path: str) -> str:
|
||||
"""
|
||||
获取相对路径
|
||||
Args:
|
||||
base_path: 基础路径
|
||||
target_path: 目标路径
|
||||
"""
|
||||
return os.path.relpath(target_path, base_path)
|
||||
|
||||
|
||||
def generate_from_module(module_folder: str, output_dir: str, with_top: bool = False, lang: str = "zh-Hans", ignored_paths=None):
|
||||
"""
|
||||
生成文档
|
||||
Args:
|
||||
module_folder: 模块文件夹
|
||||
output_dir: 输出文件夹
|
||||
with_top: 是否包含顶层文件夹 False时例如docs/api/module_a, docs/api/module_b, True时例如docs/api/module/module_a.md, docs/api/module/module_b.md
|
||||
ignored_paths: 忽略的路径
|
||||
lang: 语言
|
||||
"""
|
||||
if ignored_paths is None:
|
||||
ignored_paths = []
|
||||
file_data: dict[str, str] = {} # 路径 -> 字串
|
||||
|
||||
file_list = get_file_list(module_folder)
|
||||
|
||||
# 清理输出目录
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
replace_data = {
|
||||
"__init__": "index",
|
||||
".py" : ".md",
|
||||
}
|
||||
|
||||
for pyfile_path in file_list:
|
||||
if any(ignored_path.replace("\\", "/") in pyfile_path.replace("\\", "/") for ignored_path in ignored_paths):
|
||||
continue
|
||||
|
||||
no_module_name_pyfile_path = get_relative_path(module_folder, pyfile_path) # 去头路径
|
||||
|
||||
# markdown相对路径
|
||||
rel_md_path = pyfile_path if with_top else no_module_name_pyfile_path
|
||||
for rk, rv in replace_data.items():
|
||||
rel_md_path = rel_md_path.replace(rk, rv)
|
||||
|
||||
abs_md_path = os.path.join(output_dir, rel_md_path)
|
||||
|
||||
# 获取模块信息
|
||||
ast_parser = AstParser(open(pyfile_path, "r", encoding="utf-8").read())
|
||||
|
||||
# 生成markdown
|
||||
|
||||
front_matter = {
|
||||
"title" : pyfile_path.replace("\\", "/").
|
||||
replace("/", ".").
|
||||
replace(".py", "").
|
||||
replace(".__init__", ""),
|
||||
|
||||
}
|
||||
|
||||
md_content = generate(ast_parser, lang=lang, frontmatter=front_matter)
|
||||
print(f"Generate {pyfile_path} -> {abs_md_path}")
|
||||
file_data[abs_md_path] = md_content
|
||||
|
||||
for fn, content in file_data.items():
|
||||
write_to_file(content, fn)
|
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午3:39
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : __init__.py.py
|
||||
@Software: PyCharm
|
||||
"""
|
@ -1,59 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午3:39
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : markdown.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
from litedoc.syntax.astparser import AstParser
|
||||
from litedoc.syntax.node import *
|
||||
from litedoc.i18n import get_text
|
||||
|
||||
|
||||
def generate(parser: AstParser, lang: str, frontmatter: Optional[dict] = None) -> str:
|
||||
"""
|
||||
Generate markdown style document from ast
|
||||
You can modify this function to generate markdown style that enjoys you
|
||||
Args:
|
||||
parser:
|
||||
lang: language
|
||||
frontmatter:
|
||||
Returns:
|
||||
markdown style document
|
||||
"""
|
||||
if frontmatter is not None:
|
||||
md = "---\n"
|
||||
for k, v in frontmatter.items():
|
||||
md += f"{k}: {v}\n"
|
||||
md += "---\n"
|
||||
else:
|
||||
md = ""
|
||||
|
||||
# var > func > class
|
||||
|
||||
"""遍历函数"""
|
||||
for func in parser.functions:
|
||||
if func.name.startswith("_"):
|
||||
continue
|
||||
md += func.markdown(lang)
|
||||
|
||||
"""遍历类"""
|
||||
|
||||
for cls in parser.classes:
|
||||
md += cls.markdown(lang)
|
||||
|
||||
"""遍历变量"""
|
||||
for var in parser.variables:
|
||||
md += f"### ***var*** `{var.name} = {var.value}`\n\n"
|
||||
if var.type != TypeHint.NO_TYPEHINT:
|
||||
md += f"- **{get_text(lang, 'type')}**: `{var.type}`\n\n"
|
||||
|
||||
if var.docs is not None:
|
||||
md += f"- **{get_text(lang, 'desc')}**: {var.docs}\n\n"
|
||||
|
||||
return md
|
@ -1,293 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午2:13
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : astparser.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
import ast
|
||||
import inspect
|
||||
|
||||
from .node import *
|
||||
from ..docstring.parser import parse
|
||||
|
||||
class AstParser:
|
||||
def __init__(self, code: str):
|
||||
self.code = code
|
||||
self.tree = ast.parse(code)
|
||||
|
||||
self.classes: list[ClassNode] = []
|
||||
self.functions: list[FunctionNode] = []
|
||||
self.variables: list[AssignNode] = []
|
||||
|
||||
self.parse()
|
||||
|
||||
@staticmethod
|
||||
def clear_quotes(s: str) -> str:
|
||||
"""
|
||||
去除类型注解中的引号
|
||||
Args:
|
||||
s:
|
||||
Returns:
|
||||
"""
|
||||
return s.replace("'", "").replace('"', "")
|
||||
|
||||
def get_line_content(self, lineno: int, ignore_index_out: bool = True) -> str:
|
||||
"""获取代码行内容
|
||||
Args:
|
||||
lineno: 行号
|
||||
ignore_index_out: 是否忽略索引越界
|
||||
Returns:
|
||||
代码行内容
|
||||
"""
|
||||
if ignore_index_out:
|
||||
if lineno < 1 or lineno > len(self.code.split("\n")):
|
||||
return ""
|
||||
return self.code.split("\n")[lineno - 1]
|
||||
|
||||
@staticmethod
|
||||
def match_line_docs(linecontent: str) -> str:
|
||||
"""匹配行内注释
|
||||
Args:
|
||||
linecontent: 行内容
|
||||
Returns:
|
||||
文档字符串
|
||||
"""
|
||||
in_string = False
|
||||
string_char = ''
|
||||
for i, char in enumerate(linecontent):
|
||||
if char in ('"', "'"):
|
||||
if in_string:
|
||||
if char == string_char:
|
||||
in_string = False
|
||||
else:
|
||||
in_string = True
|
||||
string_char = char
|
||||
elif char == '#' and not in_string:
|
||||
return linecontent[i + 1:].strip()
|
||||
return ""
|
||||
|
||||
def parse(self):
|
||||
for node in ast.walk(self.tree):
|
||||
if isinstance(node, ast.ClassDef):
|
||||
if not self._is_module_level_class(node):
|
||||
continue
|
||||
|
||||
class_node = ClassNode(
|
||||
name=node.name,
|
||||
docs=parse(ast.get_docstring(node)) if ast.get_docstring(node) else None,
|
||||
inherits=[ast.unparse(base) for base in node.bases]
|
||||
)
|
||||
self.classes.append(class_node)
|
||||
|
||||
# 继续遍历类内部的函数
|
||||
for sub_node in node.body:
|
||||
if isinstance(sub_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
class_node.methods.append(FunctionNode(
|
||||
name=sub_node.name,
|
||||
docs=parse(ast.get_docstring(sub_node)) if ast.get_docstring(sub_node) else None,
|
||||
posonlyargs=[
|
||||
ArgNode(
|
||||
name=arg.arg,
|
||||
type=self.clear_quotes(ast.unparse(arg.annotation).strip()) if arg.annotation else TypeHint.NO_TYPEHINT,
|
||||
)
|
||||
for arg in sub_node.args.posonlyargs
|
||||
],
|
||||
args=[
|
||||
ArgNode(
|
||||
name=arg.arg,
|
||||
type=self.clear_quotes(ast.unparse(arg.annotation).strip()) if arg.annotation else TypeHint.NO_TYPEHINT,
|
||||
)
|
||||
for arg in sub_node.args.args
|
||||
],
|
||||
kwonlyargs=[
|
||||
ArgNode(
|
||||
name=arg.arg,
|
||||
type=self.clear_quotes(ast.unparse(arg.annotation).strip()) if arg.annotation else TypeHint.NO_TYPEHINT,
|
||||
)
|
||||
for arg in sub_node.args.kwonlyargs
|
||||
],
|
||||
kw_defaults=[
|
||||
ConstantNode(
|
||||
value=ast.unparse(default).strip() if default else TypeHint.NO_DEFAULT
|
||||
)
|
||||
for default in sub_node.args.kw_defaults
|
||||
],
|
||||
defaults=[
|
||||
ConstantNode(
|
||||
value=ast.unparse(default).strip() if default else TypeHint.NO_DEFAULT
|
||||
)
|
||||
for default in sub_node.args.defaults
|
||||
],
|
||||
return_=self.clear_quotes(ast.unparse(sub_node.returns).strip()) if sub_node.returns else TypeHint.NO_RETURN,
|
||||
decorators=[ast.unparse(decorator).strip() for decorator in sub_node.decorator_list],
|
||||
is_async=isinstance(sub_node, ast.AsyncFunctionDef),
|
||||
src=ast.unparse(sub_node).strip(),
|
||||
is_classmethod=True
|
||||
))
|
||||
# elif isinstance(sub_node, (ast.Assign, ast.AnnAssign)):
|
||||
# if isinstance(sub_node, ast.Assign):
|
||||
# class_node.attrs.append(AttrNode(
|
||||
# name=sub_node.targets[0].id, # type: ignore
|
||||
# type=TypeHint.NO_TYPEHINT,
|
||||
# value=ast.unparse(sub_node.value).strip()
|
||||
# ))
|
||||
# elif isinstance(sub_node, ast.AnnAssign):
|
||||
# class_node.attrs.append(AttrNode(
|
||||
# name=sub_node.target.id,
|
||||
# type=ast.unparse(sub_node.annotation).strip(),
|
||||
# value=ast.unparse(sub_node.value).strip() if sub_node.value else TypeHint.NO_DEFAULT
|
||||
# ))
|
||||
# else:
|
||||
# raise ValueError(f"Unsupported node type: {type(sub_node)}")
|
||||
|
||||
elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
# 仅打印模块级别的函数
|
||||
if not self._is_module_level_function(node):
|
||||
continue
|
||||
|
||||
self.functions.append(FunctionNode(
|
||||
name=node.name,
|
||||
docs=parse(ast.get_docstring(node)) if ast.get_docstring(node) else None,
|
||||
posonlyargs=[
|
||||
ArgNode(
|
||||
name=arg.arg,
|
||||
type=self.clear_quotes(ast.unparse(arg.annotation).strip()) if arg.annotation else TypeHint.NO_TYPEHINT,
|
||||
)
|
||||
for arg in node.args.posonlyargs
|
||||
],
|
||||
args=[
|
||||
ArgNode(
|
||||
name=arg.arg,
|
||||
type=self.clear_quotes(ast.unparse(arg.annotation).strip()) if arg.annotation else TypeHint.NO_TYPEHINT,
|
||||
)
|
||||
for arg, default in zip(node.args.args, node.args.defaults)
|
||||
],
|
||||
kwonlyargs=[
|
||||
ArgNode(
|
||||
name=arg.arg,
|
||||
type=self.clear_quotes(ast.unparse(arg.annotation).strip()) if arg.annotation else TypeHint.NO_TYPEHINT,
|
||||
)
|
||||
for arg in node.args.kwonlyargs
|
||||
],
|
||||
kw_defaults=[
|
||||
ConstantNode(
|
||||
value=ast.unparse(default).strip() if default else TypeHint.NO_DEFAULT
|
||||
)
|
||||
for default in node.args.kw_defaults
|
||||
],
|
||||
defaults=[
|
||||
ConstantNode(
|
||||
value=ast.unparse(default).strip() if default else TypeHint.NO_DEFAULT
|
||||
)
|
||||
for default in node.args.defaults
|
||||
],
|
||||
return_=self.clear_quotes(ast.unparse(node.returns).strip()) if node.returns else TypeHint.NO_RETURN,
|
||||
decorators=[ast.unparse(decorator).strip() for decorator in node.decorator_list],
|
||||
is_async=isinstance(node, ast.AsyncFunctionDef),
|
||||
src=ast.unparse(node).strip()
|
||||
))
|
||||
|
||||
elif isinstance(node, (ast.Assign, ast.AnnAssign)):
|
||||
if not self._is_module_level_variable2(node):
|
||||
continue
|
||||
else:
|
||||
pass
|
||||
lineno = node.lineno
|
||||
prev_line = self.get_line_content(lineno - 1).strip()
|
||||
curr_line = self.get_line_content(lineno).strip()
|
||||
next_line = self.get_line_content(lineno + 1).strip()
|
||||
|
||||
# 获取文档字符串,优先检测下行"""
|
||||
if next_line.startswith('"""'):
|
||||
docs = next_line[3:-3]
|
||||
elif prev_line.startswith('"""'):
|
||||
docs = prev_line[3:-3]
|
||||
else:
|
||||
curr_docs = self.match_line_docs(curr_line)
|
||||
if curr_docs:
|
||||
docs = curr_docs
|
||||
else:
|
||||
docs = None
|
||||
|
||||
# if isinstance(node, ast.Assign):
|
||||
# for target in node.targets:
|
||||
# if isinstance(target, ast.Name):
|
||||
# self.variables.append(AssignNode(
|
||||
# name=target.id,
|
||||
# value=ast.unparse(node.value).strip(),
|
||||
# type=ast.unparse(node.annotation).strip() if isinstance(node, ast.AnnAssign) else TypeHint.NO_TYPEHINT
|
||||
# ))
|
||||
if isinstance(node, ast.AnnAssign):
|
||||
self.variables.append(AssignNode(
|
||||
name=node.target.id,
|
||||
value=ast.unparse(node.value).strip() if node.value else TypeHint.NO_DEFAULT,
|
||||
type=ast.unparse(node.annotation).strip(),
|
||||
docs=docs
|
||||
))
|
||||
|
||||
def _is_module_level_function(self, node: ast.FunctionDef | ast.AsyncFunctionDef):
|
||||
for parent in ast.walk(self.tree):
|
||||
if isinstance(parent, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
if node in parent.body:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _is_module_level_class(self, node: ast.ClassDef):
|
||||
for parent in ast.walk(self.tree):
|
||||
if isinstance(parent, ast.ClassDef):
|
||||
if node in parent.body:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _is_module_level_variable(self, node: ast.Assign | ast.AnnAssign):
|
||||
"""在类方法或函数内部的变量不会被记录"""
|
||||
|
||||
# for parent in ast.walk(self.tree):
|
||||
# if isinstance(parent, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
# if node in parent.body:
|
||||
# return False
|
||||
# else:
|
||||
# for sub_node in parent.body:
|
||||
# if isinstance(sub_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
# if node in sub_node.body:
|
||||
# return False
|
||||
# return True
|
||||
# 递归检查
|
||||
def _check(_node, _parent):
|
||||
if isinstance(_parent, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
if _node in _parent.body:
|
||||
return False
|
||||
else:
|
||||
for sub_node in _parent.body:
|
||||
if isinstance(sub_node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
return _check(_node, sub_node)
|
||||
return True
|
||||
|
||||
for parent in ast.walk(self.tree):
|
||||
if not _check(node, parent):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _is_module_level_variable2(self, node: ast.Assign | ast.AnnAssign) -> bool:
|
||||
"""
|
||||
检查变量是否在模块级别定义。
|
||||
"""
|
||||
for parent in ast.walk(self.tree):
|
||||
if isinstance(parent, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
if node in parent.body:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __str__(self):
|
||||
s = ""
|
||||
for cls in self.classes:
|
||||
s += f"class {cls.name}:\n"
|
||||
for func in self.functions:
|
||||
s += f"def {func.name}:\n"
|
||||
for var in self.variables:
|
||||
s += f"{var.name} = {var.value}\n"
|
||||
return s
|
@ -1,314 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午2:14
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : node.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
from typing import Literal, Optional
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from litedoc.docstring.docstring import Docstring
|
||||
from litedoc.i18n import get_text
|
||||
|
||||
|
||||
class TypeHint:
|
||||
NO_TYPEHINT = "NO_TYPE_HINT"
|
||||
NO_DEFAULT = "NO_DEFAULT"
|
||||
NO_RETURN = "NO_RETURN"
|
||||
|
||||
|
||||
class AssignNode(BaseModel):
|
||||
"""
|
||||
AssignNode is a pydantic model that represents an assignment.
|
||||
Attributes:
|
||||
name: str
|
||||
The name of the assignment.
|
||||
type: str = ""
|
||||
The type of the assignment.
|
||||
value: str
|
||||
The value of the assignment.
|
||||
"""
|
||||
name: str
|
||||
type: str = ""
|
||||
value: str
|
||||
docs: Optional[str] = ""
|
||||
|
||||
|
||||
class ArgNode(BaseModel):
|
||||
"""
|
||||
ArgNode is a pydantic model that represents an argument.
|
||||
Attributes:
|
||||
name: str
|
||||
The name of the argument.
|
||||
type: str = ""
|
||||
The type of the argument.
|
||||
default: str = ""
|
||||
The default value of the argument.
|
||||
"""
|
||||
name: str
|
||||
type: str = TypeHint.NO_TYPEHINT
|
||||
|
||||
|
||||
class AttrNode(BaseModel):
|
||||
"""
|
||||
AttrNode is a pydantic model that represents an attribute.
|
||||
Attributes:
|
||||
name: str
|
||||
The name of the attribute.
|
||||
type: str = ""
|
||||
The type of the attribute.
|
||||
value: str = ""
|
||||
The value of the attribute
|
||||
"""
|
||||
name: str
|
||||
type: str = ""
|
||||
value: str = ""
|
||||
|
||||
|
||||
class ImportNode(BaseModel):
|
||||
"""
|
||||
ImportNode is a pydantic model that represents an import statement.
|
||||
Attributes:
|
||||
name: str
|
||||
The name of the import statement.
|
||||
as_: str = ""
|
||||
The alias of the import
|
||||
"""
|
||||
name: str
|
||||
as_: str = ""
|
||||
|
||||
|
||||
class ConstantNode(BaseModel):
|
||||
"""
|
||||
ConstantNode is a pydantic model that represents a constant.
|
||||
Attributes:
|
||||
value: str
|
||||
The value of the constant.
|
||||
"""
|
||||
value: str
|
||||
|
||||
|
||||
class FunctionNode(BaseModel):
|
||||
"""
|
||||
FunctionNode is a pydantic model that represents a function.
|
||||
Attributes:
|
||||
name: str
|
||||
The name of the function.
|
||||
docs: str = ""
|
||||
The docstring of the function.
|
||||
args: list[ArgNode] = []
|
||||
The arguments of the function.
|
||||
return_: ReturnNode = None
|
||||
The return value of the function.
|
||||
decorators: list[str] = []
|
||||
The decorators of the function.
|
||||
is_async: bool = False
|
||||
Whether the function is asynchronous.
|
||||
"""
|
||||
name: str
|
||||
docs: Optional[Docstring] = None
|
||||
|
||||
posonlyargs: list[ArgNode] = []
|
||||
args: list[ArgNode] = []
|
||||
kwonlyargs: list[ArgNode] = []
|
||||
kw_defaults: list[ConstantNode] = []
|
||||
defaults: list[ConstantNode] = []
|
||||
|
||||
return_: str = TypeHint.NO_RETURN
|
||||
decorators: list[str] = []
|
||||
src: str
|
||||
is_async: bool = False
|
||||
is_classmethod: bool = False
|
||||
|
||||
magic_methods: dict[str, str] = {
|
||||
"__add__" : "+",
|
||||
"__radd__" : "+",
|
||||
"__sub__" : "-",
|
||||
"__rsub__" : "-",
|
||||
"__mul__" : "*",
|
||||
"__rmul__" : "*",
|
||||
"__matmul__" : "@",
|
||||
"__rmatmul__": "@",
|
||||
"__mod__" : "%",
|
||||
"__truediv__": "/",
|
||||
"__rtruediv__": "/",
|
||||
"__neg__" : "-",
|
||||
} # 魔术方法, 例如运算符
|
||||
|
||||
def is_private(self):
|
||||
"""
|
||||
Check if the function or method is private.
|
||||
Returns:
|
||||
bool: True if the function or method is private, False otherwise.
|
||||
"""
|
||||
return self.name.startswith("_")
|
||||
|
||||
def is_builtin(self):
|
||||
"""
|
||||
Check if the function or method is a builtin function or method.
|
||||
Returns:
|
||||
bool: True if the function or method is a builtin function or method, False otherwise.
|
||||
"""
|
||||
return self.name.startswith("__") and self.name.endswith("__")
|
||||
|
||||
def markdown(self, lang: str, indent: int = 0) -> str:
|
||||
"""
|
||||
Args:
|
||||
indent: int
|
||||
The number of spaces to indent the markdown.
|
||||
lang: str
|
||||
The language of the
|
||||
Returns:
|
||||
markdown style document
|
||||
"""
|
||||
self.complete_default_args()
|
||||
PREFIX = "" * indent
|
||||
# if is_classmethod:
|
||||
# PREFIX = "- #"
|
||||
func_type = "func" if not self.is_classmethod else "method"
|
||||
|
||||
md = ""
|
||||
# 装饰器部分
|
||||
if len(self.decorators) > 0:
|
||||
for decorator in self.decorators:
|
||||
md += PREFIX + f"### `@{decorator}`\n"
|
||||
|
||||
if self.is_async:
|
||||
md += PREFIX + f"### *async {func_type}* "
|
||||
else:
|
||||
md += PREFIX + f"### *{func_type}* "
|
||||
|
||||
# code start
|
||||
# 配对位置参数和位置参数默认值,无默认值用TypeHint.NO_DEFAULT
|
||||
args: list[str] = [] # 可直接", ".join(args)得到位置参数部分
|
||||
arg_i = 0
|
||||
|
||||
if len(self.posonlyargs) > 0:
|
||||
for arg in self.posonlyargs:
|
||||
arg_text = f"{arg.name}"
|
||||
if arg.type != TypeHint.NO_TYPEHINT:
|
||||
arg_text += f": {arg.type}"
|
||||
arg_default = self.defaults[arg_i].value
|
||||
if arg_default != TypeHint.NO_DEFAULT:
|
||||
arg_text += f" = {arg_default}"
|
||||
args.append(arg_text)
|
||||
arg_i += 1
|
||||
# 加位置参数分割符 /
|
||||
args.append("/")
|
||||
|
||||
for arg in self.args:
|
||||
arg_text = f"{arg.name}"
|
||||
if arg.type != TypeHint.NO_TYPEHINT:
|
||||
arg_text += f": {arg.type}"
|
||||
arg_default = self.defaults[arg_i].value
|
||||
if arg_default != TypeHint.NO_DEFAULT:
|
||||
arg_text += f" = {arg_default}"
|
||||
args.append(arg_text)
|
||||
arg_i += 1
|
||||
|
||||
if len(self.kwonlyargs) > 0:
|
||||
# 加关键字参数分割符 *
|
||||
args.append("*")
|
||||
for arg, kw_default in zip(self.kwonlyargs, self.kw_defaults):
|
||||
arg_text = f"{arg.name}"
|
||||
if arg.type != TypeHint.NO_TYPEHINT:
|
||||
arg_text += f": {arg.type}"
|
||||
if kw_default.value != TypeHint.NO_DEFAULT:
|
||||
arg_text += f" = {kw_default.value}"
|
||||
args.append(arg_text)
|
||||
|
||||
"""魔法方法"""
|
||||
if self.name in self.magic_methods:
|
||||
if len(args) == 2:
|
||||
md += f"`{args[0]} {self.magic_methods[self.name]} {args[1]}"
|
||||
elif len(args) == 1:
|
||||
md += f"`{self.magic_methods[self.name]} {args[0]}"
|
||||
if self.return_ != TypeHint.NO_RETURN:
|
||||
md += f" => {self.return_}"
|
||||
else:
|
||||
md += f"`{self.name}(" # code start
|
||||
md += ", ".join(args) + ")"
|
||||
if self.return_ != TypeHint.NO_RETURN:
|
||||
md += f" -> {self.return_}"
|
||||
|
||||
md += "`\n\n" # code end
|
||||
|
||||
"""此处预留docstring"""
|
||||
if self.docs is not None:
|
||||
md += f"\n{self.docs.markdown(lang, indent)}\n"
|
||||
else:
|
||||
pass
|
||||
# 源码展示
|
||||
md += PREFIX + f"\n<details>\n<summary> <b>{get_text(lang, 'src')}</b> </summary>\n\n```python\n{self.src}\n```\n</details>\n\n"
|
||||
|
||||
return md
|
||||
|
||||
def complete_default_args(self):
|
||||
"""
|
||||
补全位置参数默认值,用无默认值插入
|
||||
Returns:
|
||||
|
||||
"""
|
||||
num = len(self.args) + len(self.posonlyargs) - len(self.defaults)
|
||||
self.defaults = [ConstantNode(value=TypeHint.NO_DEFAULT) for _ in range(num)] + self.defaults
|
||||
|
||||
def __str__(self):
|
||||
return f"def {self.name}({', '.join([f'{arg.name}: {arg.type} = {arg.default}' for arg in self.args])}) -> {self.return_}"
|
||||
|
||||
|
||||
class ClassNode(BaseModel):
|
||||
"""
|
||||
ClassNode is a pydantic model that represents a class.
|
||||
Attributes:
|
||||
name: str
|
||||
The name of the class.
|
||||
docs: str = ""
|
||||
The docstring of the class.
|
||||
attrs: list[AttrNode] = []
|
||||
The attributes of the class.
|
||||
methods: list[MethodNode] = []
|
||||
The methods of the class.
|
||||
inherits: list["ClassNode"] = []
|
||||
The classes that the class inherits from
|
||||
"""
|
||||
name: str
|
||||
docs: Optional[Docstring] = None
|
||||
attrs: list[AttrNode] = []
|
||||
methods: list[FunctionNode] = []
|
||||
inherits: list[str] = []
|
||||
|
||||
def markdown(self, lang: str) -> str:
|
||||
"""
|
||||
返回类的markdown文档
|
||||
Args:
|
||||
lang: str
|
||||
The language of the
|
||||
Returns:
|
||||
markdown style document
|
||||
"""
|
||||
hidden_methods = [
|
||||
"__str__",
|
||||
"__repr__",
|
||||
]
|
||||
md = ""
|
||||
md += f"### **class** `{self.name}"
|
||||
if len(self.inherits) > 0:
|
||||
md += f"({', '.join([cls for cls in self.inherits])})"
|
||||
md += "`\n"
|
||||
for method in self.methods:
|
||||
if method.name in hidden_methods:
|
||||
continue
|
||||
md += method.markdown(lang, 2)
|
||||
for attr in self.attrs:
|
||||
if attr.type == TypeHint.NO_TYPEHINT:
|
||||
md += f"#### ***attr*** `{attr.name} = {attr.value}`\n\n"
|
||||
else:
|
||||
md += f"#### ***attr*** `{attr.name}: {attr.type} = {attr.value}`\n\n"
|
||||
|
||||
return md
|
@ -1,47 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/29 下午12:02
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : translator.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
from translate import Translator # type: ignore
|
||||
|
||||
# 特殊映射语言
|
||||
i18n_lang2googletrans_lang = {
|
||||
"zh-Hans": "zh-cn",
|
||||
"zh-Hant": "zh-tw",
|
||||
"en" : "en",
|
||||
}
|
||||
|
||||
|
||||
def get_google_lang(lang: str) -> str:
|
||||
"""
|
||||
Get google translate language
|
||||
Args:
|
||||
lang: language
|
||||
Returns:
|
||||
google translate language
|
||||
"""
|
||||
return i18n_lang2googletrans_lang.get(lang, lang)
|
||||
|
||||
|
||||
def translate(text: str, lang: str, source_lang: str) -> str:
|
||||
"""
|
||||
Translate text to target language
|
||||
Args:
|
||||
source_lang:
|
||||
text: text
|
||||
lang: target language
|
||||
Returns:
|
||||
translated text
|
||||
"""
|
||||
if lang == source_lang:
|
||||
return text
|
||||
google_lang = get_google_lang(lang)
|
||||
return Translator(to_lang=google_lang, from_lang=source_lang).translate(text)
|
46
main.py
46
main.py
@ -1,46 +0,0 @@
|
||||
from typing import overload
|
||||
|
||||
|
||||
class Vector:
|
||||
def __init__(self, x: float, y: float, z: float):
|
||||
"""
|
||||
向量
|
||||
Args:
|
||||
x: x轴分量
|
||||
y: y轴分量
|
||||
z: z轴分量
|
||||
"""
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
@overload
|
||||
def __mul__(self, other: float) -> 'Vector':
|
||||
...
|
||||
|
||||
@overload
|
||||
def __mul__(self, other: 'Vector') -> float:
|
||||
...
|
||||
|
||||
def __mul__(self, other):
|
||||
"""
|
||||
点乘和数乘
|
||||
Args:
|
||||
other:
|
||||
|
||||
Returns:
|
||||
"""
|
||||
if isinstance(other, (float, int)):
|
||||
return Vector(self.x * other, self.y * other, self.z * other)
|
||||
elif isinstance(other, Vector):
|
||||
return self.x * other.x + self.y * other.y + self.z * other.z
|
||||
else:
|
||||
raise TypeError(f"unsupported operand type(s) for *: 'Vector' and '{type(other)}'")
|
||||
|
||||
def __rmul__(self, other: float) -> 'Vector':
|
||||
return self.__mul__(other)
|
||||
|
||||
|
||||
v: Vector = Vector(1, 2, 3) * 3.0
|
||||
v2: Vector = 3.0 * Vector(1, 2, 3)
|
||||
|
||||
print(v, v2)
|
10
make_docs.py
10
make_docs.py
@ -1,10 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午12:50
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : make_docs.py
|
||||
@Software: PyCharm
|
||||
"""
|
346
mkdoc.py
346
mkdoc.py
@ -1,346 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
MkDocs文档生成脚本
|
||||
用法 python docs/mkdoc.py
|
||||
"""
|
||||
|
||||
import ast
|
||||
import os
|
||||
import shutil
|
||||
from typing import Any
|
||||
from enum import Enum
|
||||
from pydantic import BaseModel
|
||||
|
||||
NO_TYPE_ANY = "Any"
|
||||
NO_TYPE_HINT = "NoTypeHint"
|
||||
|
||||
|
||||
class DefType(Enum):
|
||||
FUNCTION = "function"
|
||||
METHOD = "method"
|
||||
STATIC_METHOD = "staticmethod"
|
||||
CLASS_METHOD = "classmethod"
|
||||
PROPERTY = "property"
|
||||
|
||||
|
||||
class FunctionInfo(BaseModel):
|
||||
name: str
|
||||
args: list[tuple[str, str]]
|
||||
return_type: str
|
||||
docstring: str
|
||||
source_code: str = ""
|
||||
|
||||
type: DefType
|
||||
"""若为类中def,则有"""
|
||||
is_async: bool
|
||||
|
||||
|
||||
class AttributeInfo(BaseModel):
|
||||
name: str
|
||||
type: str
|
||||
value: Any = None
|
||||
docstring: str = ""
|
||||
|
||||
|
||||
class ClassInfo(BaseModel):
|
||||
name: str
|
||||
docstring: str
|
||||
methods: list[FunctionInfo]
|
||||
attributes: list[AttributeInfo]
|
||||
inherit: list[str]
|
||||
|
||||
|
||||
class ModuleInfo(BaseModel):
|
||||
module_path: str
|
||||
"""点分割模块路径 例如 liteyuki.bot"""
|
||||
|
||||
functions: list[FunctionInfo]
|
||||
classes: list[ClassInfo]
|
||||
attributes: list[AttributeInfo]
|
||||
docstring: str
|
||||
|
||||
|
||||
def get_relative_path(base_path: str, target_path: str) -> str:
|
||||
"""
|
||||
获取相对路径
|
||||
Args:
|
||||
base_path: 基础路径
|
||||
target_path: 目标路径
|
||||
"""
|
||||
return os.path.relpath(target_path, base_path)
|
||||
|
||||
|
||||
def write_to_files(file_data: dict[str, str]):
|
||||
"""
|
||||
输出文件
|
||||
Args:
|
||||
file_data: 文件数据 相对路径
|
||||
"""
|
||||
|
||||
for rp, data in file_data.items():
|
||||
|
||||
if not os.path.exists(os.path.dirname(rp)):
|
||||
os.makedirs(os.path.dirname(rp))
|
||||
with open(rp, 'w', encoding='utf-8') as f:
|
||||
f.write(data)
|
||||
|
||||
|
||||
def get_file_list(module_folder: str):
|
||||
file_list = []
|
||||
for root, dirs, files in os.walk(module_folder):
|
||||
for file in files:
|
||||
if file.endswith((".py", ".pyi")):
|
||||
file_list.append(os.path.join(root, file))
|
||||
return file_list
|
||||
|
||||
|
||||
def get_module_info_normal(file_path: str, ignore_private: bool = True) -> ModuleInfo:
|
||||
"""
|
||||
获取函数和类
|
||||
Args:
|
||||
file_path: Python 文件路径
|
||||
ignore_private: 忽略私有函数和类
|
||||
Returns:
|
||||
模块信息
|
||||
"""
|
||||
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
file_content = file.read()
|
||||
tree = ast.parse(file_content)
|
||||
|
||||
dot_sep_module_path = file_path.replace(os.sep, '.').replace(".py", "").replace(".pyi", "")
|
||||
module_docstring = ast.get_docstring(tree)
|
||||
|
||||
module_info = ModuleInfo(
|
||||
module_path=dot_sep_module_path,
|
||||
functions=[],
|
||||
classes=[],
|
||||
attributes=[],
|
||||
docstring=module_docstring if module_docstring else ""
|
||||
)
|
||||
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
||||
# 模块函数 且不在类中 若ignore_private=True则忽略私有函数
|
||||
if not any(isinstance(parent, ast.ClassDef) for parent in ast.iter_child_nodes(node)) and (not ignore_private or not node.name.startswith('_')):
|
||||
|
||||
# 判断第一个参数是否为self或cls,后期用其他办法优化
|
||||
if node.args.args:
|
||||
first_arg = node.args.args[0]
|
||||
if first_arg.arg in ("self", "cls"):
|
||||
continue
|
||||
|
||||
function_docstring = ast.get_docstring(node)
|
||||
|
||||
func_info = FunctionInfo(
|
||||
name=node.name,
|
||||
args=[(arg.arg, ast.unparse(arg.annotation) if arg.annotation else NO_TYPE_ANY) for arg in node.args.args],
|
||||
return_type=ast.unparse(node.returns) if node.returns else "None",
|
||||
docstring=function_docstring if function_docstring else "",
|
||||
type=DefType.FUNCTION,
|
||||
is_async=isinstance(node, ast.AsyncFunctionDef),
|
||||
source_code=ast.unparse(node)
|
||||
)
|
||||
module_info.functions.append(func_info)
|
||||
|
||||
elif isinstance(node, ast.ClassDef):
|
||||
# 模块类
|
||||
class_docstring = ast.get_docstring(node)
|
||||
|
||||
class_info = ClassInfo(
|
||||
name=node.name,
|
||||
docstring=class_docstring if class_docstring else "",
|
||||
methods=[],
|
||||
attributes=[],
|
||||
inherit=[ast.unparse(base) for base in node.bases]
|
||||
)
|
||||
|
||||
for class_node in node.body:
|
||||
# methods [instance, static, class, property],保留__init__方法
|
||||
if isinstance(class_node, ast.FunctionDef) and (not ignore_private or not class_node.name.startswith('_') or class_node.name == "__init__"):
|
||||
method_docstring = ast.get_docstring(class_node)
|
||||
def_type = DefType.METHOD
|
||||
if class_node.decorator_list:
|
||||
if any(isinstance(decorator, ast.Name) and decorator.id == "staticmethod" for decorator in class_node.decorator_list):
|
||||
def_type = DefType.STATIC_METHOD
|
||||
elif any(isinstance(decorator, ast.Name) and decorator.id == "classmethod" for decorator in class_node.decorator_list):
|
||||
def_type = DefType.CLASS_METHOD
|
||||
elif any(isinstance(decorator, ast.Name) and decorator.id == "property" for decorator in class_node.decorator_list):
|
||||
def_type = DefType.PROPERTY
|
||||
class_info.methods.append(FunctionInfo(
|
||||
name=class_node.name,
|
||||
args=[(arg.arg, ast.unparse(arg.annotation) if arg.annotation else NO_TYPE_ANY) for arg in class_node.args.args],
|
||||
return_type=ast.unparse(class_node.returns) if class_node.returns else "None",
|
||||
docstring=method_docstring if method_docstring else "",
|
||||
type=def_type,
|
||||
is_async=isinstance(class_node, ast.AsyncFunctionDef),
|
||||
source_code=ast.unparse(class_node)
|
||||
))
|
||||
# attributes
|
||||
elif isinstance(class_node, ast.Assign):
|
||||
for target in class_node.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
class_info.attributes.append(AttributeInfo(
|
||||
name=target.id,
|
||||
type=ast.unparse(class_node.value)
|
||||
))
|
||||
module_info.classes.append(class_info)
|
||||
|
||||
elif isinstance(node, ast.Assign):
|
||||
# 检查是否在类或函数中
|
||||
if not any(isinstance(parent, (ast.ClassDef, ast.FunctionDef)) for parent in ast.iter_child_nodes(node)):
|
||||
# 模块属性变量
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Name) and (not ignore_private or not target.id.startswith('_')):
|
||||
attr_type = NO_TYPE_HINT
|
||||
if isinstance(node.value, ast.AnnAssign) and node.value.annotation:
|
||||
attr_type = ast.unparse(node.value.annotation)
|
||||
module_info.attributes.append(AttributeInfo(
|
||||
name=target.id,
|
||||
type=attr_type,
|
||||
value=ast.unparse(node.value) if node.value else None
|
||||
))
|
||||
|
||||
return module_info
|
||||
|
||||
|
||||
def generate_markdown(module_info: ModuleInfo, front_matter=None, lang: str = "zh-CN") -> str:
|
||||
"""
|
||||
生成模块的Markdown
|
||||
你可在此自定义生成的Markdown格式
|
||||
Args:
|
||||
module_info: 模块信息
|
||||
front_matter: 自定义选项title, index, icon, category
|
||||
lang: 语言
|
||||
Returns:
|
||||
Markdown 字符串
|
||||
"""
|
||||
|
||||
content = ""
|
||||
|
||||
front_matter = "---\n" + "\n".join([f"{k}: {v}" for k, v in front_matter.items()]) + "\n---\n\n"
|
||||
|
||||
content += front_matter
|
||||
|
||||
# 模块函数
|
||||
for func in module_info.functions:
|
||||
args_with_type = [f"{arg[0]}: {arg[1]}" if arg[1] else arg[0] for arg in func.args]
|
||||
content += f"### ***{'async ' if func.is_async else ''}def*** `{func.name}({', '.join(args_with_type)}) -> {func.return_type}`\n\n"
|
||||
|
||||
func.docstring = func.docstring.replace("\n", "\n\n")
|
||||
content += f"{func.docstring}\n\n"
|
||||
|
||||
# 函数源代码可展开区域
|
||||
content += f"<details>\n<summary>源代码</summary>\n\n```python\n{func.source_code}\n```\n</details>\n\n"
|
||||
|
||||
# 类
|
||||
for cls in module_info.classes:
|
||||
if cls.inherit:
|
||||
inherit = f"({', '.join(cls.inherit)})" if cls.inherit else ""
|
||||
content += f"### ***class*** `{cls.name}{inherit}`\n\n"
|
||||
else:
|
||||
content += f"### ***class*** `{cls.name}`\n\n"
|
||||
|
||||
cls.docstring = cls.docstring.replace("\n", "\n\n")
|
||||
content += f"{cls.docstring}\n\n"
|
||||
for method in cls.methods:
|
||||
# 类函数
|
||||
|
||||
if method.type != DefType.METHOD:
|
||||
args_with_type = [f"{arg[0]}: {arg[1]}" if arg[1] else arg[0] for arg in method.args]
|
||||
content += f"###   ***@{method.type.value}***\n"
|
||||
else:
|
||||
# self不加类型提示
|
||||
args_with_type = [f"{arg[0]}: {arg[1]}" if arg[1] and arg[0] != "self" else arg[0] for arg in method.args]
|
||||
content += f"###   ***{'async ' if method.is_async else ''}def*** `{method.name}({', '.join(args_with_type)}) -> {method.return_type}`\n\n"
|
||||
|
||||
method.docstring = method.docstring.replace("\n", "\n\n")
|
||||
content += f" {method.docstring}\n\n"
|
||||
# 函数源代码可展开区域
|
||||
|
||||
if lang == "zh-CN":
|
||||
TEXT_SOURCE_CODE = "源代码"
|
||||
else:
|
||||
TEXT_SOURCE_CODE = "Source Code"
|
||||
|
||||
content += f"<details>\n<summary>{TEXT_SOURCE_CODE}</summary>\n\n```python\n{method.source_code}\n```\n</details>\n\n"
|
||||
for attr in cls.attributes:
|
||||
content += f"###   ***attr*** `{attr.name}: {attr.type}`\n\n"
|
||||
|
||||
# 模块属性
|
||||
for attr in module_info.attributes:
|
||||
if attr.type == NO_TYPE_HINT:
|
||||
content += f"### ***var*** `{attr.name} = {attr.value}`\n\n"
|
||||
else:
|
||||
content += f"### ***var*** `{attr.name}: {attr.type} = {attr.value}`\n\n"
|
||||
|
||||
attr.docstring = attr.docstring.replace("\n", "\n\n")
|
||||
content += f"{attr.docstring}\n\n"
|
||||
|
||||
return content
|
||||
|
||||
|
||||
def generate_docs(module_folder: str, output_dir: str, with_top: bool = False, lang: str = "zh-CN", ignored_paths=None):
|
||||
"""
|
||||
生成文档
|
||||
Args:
|
||||
module_folder: 模块文件夹
|
||||
output_dir: 输出文件夹
|
||||
with_top: 是否包含顶层文件夹 False时例如docs/api/module_a, docs/api/module_b, True时例如docs/api/module/module_a.md, docs/api/module/module_b.md
|
||||
ignored_paths: 忽略的路径
|
||||
lang: 语言
|
||||
"""
|
||||
if ignored_paths is None:
|
||||
ignored_paths = []
|
||||
file_data: dict[str, str] = {} # 路径 -> 字串
|
||||
|
||||
file_list = get_file_list(module_folder)
|
||||
|
||||
# 清理输出目录
|
||||
shutil.rmtree(output_dir, ignore_errors=True)
|
||||
os.mkdir(output_dir)
|
||||
|
||||
replace_data = {
|
||||
"__init__": "index",
|
||||
".py" : ".md",
|
||||
}
|
||||
|
||||
for pyfile_path in file_list:
|
||||
if any(ignored_path.replace("\\", "/") in pyfile_path.replace("\\", "/") for ignored_path in ignored_paths):
|
||||
continue
|
||||
|
||||
no_module_name_pyfile_path = get_relative_path(module_folder, pyfile_path) # 去头路径
|
||||
|
||||
# markdown相对路径
|
||||
rel_md_path = pyfile_path if with_top else no_module_name_pyfile_path
|
||||
for rk, rv in replace_data.items():
|
||||
rel_md_path = rel_md_path.replace(rk, rv)
|
||||
|
||||
abs_md_path = os.path.join(output_dir, rel_md_path)
|
||||
|
||||
# 获取模块信息
|
||||
module_info = get_module_info_normal(pyfile_path)
|
||||
|
||||
# 生成markdown
|
||||
|
||||
if "index" in abs_md_path:
|
||||
front_matter = {
|
||||
"title" : module_info.module_path.replace(".__init__", ""),
|
||||
}
|
||||
else:
|
||||
front_matter = {
|
||||
"title" : module_info.module_path
|
||||
}
|
||||
|
||||
md_content = generate_markdown(module_info, front_matter)
|
||||
print(f"Generate {pyfile_path} -> {abs_md_path}")
|
||||
file_data[abs_md_path] = md_content
|
||||
|
||||
write_to_files(file_data)
|
||||
|
||||
|
||||
# 入口脚本
|
||||
if __name__ == '__main__':
|
||||
# 这里填入你的模块路径
|
||||
generate_docs('mbcp', 'docs/api', with_top=False, ignored_paths=["liteyuki/plugins"], lang="zh-CN")
|
||||
# generate_docs('mbcp', 'docs/en/api', with_top=False, ignored_paths=["liteyuki/plugins"], lang="en")
|
@ -26,3 +26,7 @@ distribution = true
|
||||
dev = [
|
||||
"translate>=3.6.1",
|
||||
]
|
||||
[[tool.pdm.source]]
|
||||
name = "pypi"
|
||||
url = "https://pypi.org/simple"
|
||||
include_packages = ["litedoc"]
|
Loading…
Reference in New Issue
Block a user