📝 测试文档部署

This commit is contained in:
远野千束 2024-08-28 12:02:30 +08:00
parent f5d91cafd5
commit e0a3ab605d
39 changed files with 2811 additions and 819 deletions

View File

@ -13,7 +13,7 @@ on:
# 设置 GITHUB_TOKEN 的权限,以允许部署到 GitHub Pages # 设置 GITHUB_TOKEN 的权限,以允许部署到 GitHub Pages
permissions: permissions:
contents: read contents: write
pages: write pages: write
id-token: write id-token: write
@ -42,7 +42,9 @@ jobs:
- name: Setup API markdown - name: Setup API markdown
run: |- run: |-
python -m pip install pydantic python -m pip install pydantic
python docs/mkdoc.py python liteyuki_autodoc mbcp -o docs/api -l zh-Hans
python liteyuki_autodoc mbcp -o docs/en/api -l en
python liteyuki_autodoc mbcp -o docs/ja/api -l ja
- name: 安装 pnpm - name: 安装 pnpm
uses: pnpm/action-setup@v2 uses: pnpm/action-setup@v2
@ -67,5 +69,5 @@ jobs:
uses: JamesIves/github-pages-deploy-action@v4 uses: JamesIves/github-pages-deploy-action@v4
with: with:
# 这是文档部署到的分支名称 # 这是文档部署到的分支名称
branch: gh-pages branch: docs
folder: docs/.vitepress/dist folder: docs/.vitepress/dist

View File

@ -10,5 +10,4 @@ A Minecraft particle production library
## 示例 ## 示例
- [【特效红石音乐】童话镇~「总有一条蜿蜒在童话镇里...」](https://www.bilibili.com/video/BV1xE4m1d72j) - [【特效红石音乐】童话镇~「总有一条蜿蜒在童话镇里...」](https://www.bilibili.com/video/BV1xE4m1d72j)
- [【特效红石音乐】使一颗心免于哀伤 If I Can Stop One Heart From Breaking「崩坏星穹铁道 EP」](https://www.bilibili.com/video/BV1B1421t7i3) - [【特效红石音乐】使一颗心免于哀伤 If I Can Stop One Heart From Breaking「崩坏星穹铁道 EP」](https://www.bilibili.com/video/BV1B1421t7i3)

View File

@ -1,39 +0,0 @@
import { defineConfig } from 'vitepress'
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "MBCP docs",
description: "MBCP library docs",
locales: {
root: {
label: '简体中文',
lang: 'zh-CN'
},
en: {
label: 'English',
lang: 'en-US'
}
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: 'Home', link: '/' },
{ text: 'Examples', link: '/markdown-examples' }
],
sidebar: [
{
text: 'Examples',
items: [
{ text: 'Markdown Examples', link: '/markdown-examples' },
{ text: 'Runtime API Examples', link: '/api-examples' }
]
}
],
socialLinks: [
{ icon: 'github', link: 'https://github.com/snowykami/mbcp' }
]
},
srcDir: '.'
})

View File

@ -1,8 +1,23 @@
import {defineConfig} from 'vitepress' import {defineConfig} from 'vitepress'
import AutoSidebarPlugin from 'vitepress-auto-sidebar-plugin'
export const common = defineConfig({ export const common = defineConfig({
title: "MBCP docs", title: "MBCP docs",
description: "MBCP library docs", description: "MBCP library docs",
vite: {
plugins: [
AutoSidebarPlugin({
// 如果不指定 `srcDir`,则默认使用 `vitepress` 的 `srcDir`
ignoreList: [
'README.md'
],
title: {
mode: text => text.toLowerCase()
}
}),
],
},
themeConfig: { themeConfig: {
// https://vitepress.dev/reference/default-theme-config // https://vitepress.dev/reference/default-theme-config
socialLinks: [ socialLinks: [

View File

@ -1,10 +1,21 @@
import {defineConfig} from 'vitepress' import {defineConfig} from 'vitepress'
export const zh = defineConfig({ export const zh = defineConfig({
lang: "zh-Hans", lang: "zh-Hans",
description: "一个用于Minecraft粒子计算和生成的库", description: "一个用于Minecraft粒子计算和生成的库",
themeConfig: { themeConfig: {
nav: [
{text: '快速开始', link: '/guide'},
{text: 'API文档', link: '/api/'},
{text: '实例', link: '/demo/'},
],
// sidebar: {
// '/api/': {
// base: '/api/',
// items: [
// ]
// }
// }
}, },
}) })

View File

@ -1,6 +1,3 @@
--- ---
title: mbcp.\n\ninit\n\n title: mbcp
order: 1 ---
icon: laptop-code
category: API
---

View File

@ -1,26 +1,25 @@
--- ---
title: mbcp.mp\nmath.angle title: mbcp.mp_math.angle
order: 1
icon: laptop-code
category: API
--- ---
### ***class*** `Angle`
### ***class*** `AnyAngle` ### ***class*** `AnyAngle`
- #### *def* `__init__(self, value: float, is_radian: bool = False)`
###   ***def*** `__init__(self, value: float, is_radian: bool) -> None` 任意角度。
 任意角度。 参数:
Args: value: 角度或弧度值
value: 角度或弧度值 is_radian: 是否为弧度,默认为否
is_radian: 是否为弧度,默认为否
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def __init__(self, value: float, is_radian: bool=False): def __init__(self, value: float, is_radian: bool=False):
@ -37,17 +36,20 @@ def __init__(self, value: float, is_radian: bool=False):
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `complementary(self: Any) -> 'AnyAngle'` - #### *def* `complementary(self)`
&emsp;余角两角的和为90°。
Returns: 余角两角的和为90°。
余角 返回:
余角
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -61,17 +63,20 @@ def complementary(self) -> 'AnyAngle':
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `supplementary(self: Any) -> 'AnyAngle'` - #### *def* `supplementary(self)`
&emsp;补角两角的和为180°。
Returns: 补角两角的和为180°。
补角 返回:
补角
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -85,17 +90,20 @@ def supplementary(self) -> 'AnyAngle':
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `degree(self: Any) -> float` - #### *def* `degree(self)`
&emsp;角度。
Returns: 角度。
弧度 返回:
弧度
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -109,17 +117,20 @@ def degree(self) -> float:
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `minimum_positive(self: Any) -> 'AnyAngle'` - #### *def* `minimum_positive(self)`
&emsp;最小正角。
Returns: 最小正角。
最小正角度 返回:
最小正角度
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -133,17 +144,20 @@ def minimum_positive(self) -> 'AnyAngle':
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `maximum_negative(self: Any) -> 'AnyAngle'` - #### *def* `maximum_negative(self)`
&emsp;最大负角。
Returns: 最大负角。
最大负角度 返回:
最大负角度
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -157,17 +171,20 @@ def maximum_negative(self) -> 'AnyAngle':
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `sin(self: Any) -> float` - #### *def* `sin(self)`
&emsp;正弦值。
Returns: 正弦值。
正弦值 返回:
正弦值
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -181,17 +198,20 @@ def sin(self) -> float:
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `cos(self: Any) -> float` - #### *def* `cos(self)`
&emsp;余弦值。
Returns: 余弦值。
余弦值 返回:
余弦值
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -205,17 +225,20 @@ def cos(self) -> float:
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `tan(self: Any) -> float` - #### *def* `tan(self)`
&emsp;正切值。
Returns: 正切值。
正切值 返回:
正切值
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -229,17 +252,20 @@ def tan(self) -> float:
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `cot(self: Any) -> float` - #### *def* `cot(self)`
&emsp;余切值。
Returns: 余切值。
余切值 返回:
余切值
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -253,17 +279,20 @@ def cot(self) -> float:
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `sec(self: Any) -> float` - #### *def* `sec(self)`
&emsp;正割值。
Returns: 正割值。
正割值 返回:
正割值
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -277,17 +306,20 @@ def sec(self) -> float:
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `csc(self: Any) -> float` - #### *def* `csc(self)`
&emsp;余割值。
Returns: 余割值。
余割值 返回:
余割值
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -301,3 +333,117 @@ def csc(self) -> float:
``` ```
</details> </details>
- #### *def* `__add__(self, other: 'AnyAngle')`
- #
<details>
<summary>源码</summary>
```python
def __add__(self, other: 'AnyAngle') -> 'AnyAngle':
return AnyAngle(self.radian + other.radian, is_radian=True)
```
</details>
- #### *def* `__eq__(self, other)`
- #
<details>
<summary>源码</summary>
```python
def __eq__(self, other):
return approx(self.radian, other.radian)
```
</details>
- #### *def* `__sub__(self, other: 'AnyAngle')`
- #
<details>
<summary>源码</summary>
```python
def __sub__(self, other: 'AnyAngle') -> 'AnyAngle':
return AnyAngle(self.radian - other.radian, is_radian=True)
```
</details>
- #### *def* `__mul__(self, other: float)`
- #
<details>
<summary>源码</summary>
```python
def __mul__(self, other: float) -> 'AnyAngle':
return AnyAngle(self.radian * other, is_radian=True)
```
</details>
- #### *def* `__repr__(self)`
- #
<details>
<summary>源码</summary>
```python
def __repr__(self):
return f'AnyAngle({self.radian}, is_radian=True)'
```
</details>
- #### *def* `__str__(self)`
- #
<details>
<summary>源码</summary>
```python
def __str__(self):
return f'AnyAngle({self.degree}° or {self.radian} rad)'
```
</details>
- #### `@overload`
- #### *def* `__truediv__(self, other: float)`
- #
<details>
<summary>源码</summary>
```python
@overload
def __truediv__(self, other: float) -> 'AnyAngle':
...
```
</details>
- #### `@overload`
- #### *def* `__truediv__(self, other: 'AnyAngle')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __truediv__(self, other: 'AnyAngle') -> float:
...
```
</details>
- #### *def* `__truediv__(self, other)`
- #
<details>
<summary>源码</summary>
```python
def __truediv__(self, other):
if isinstance(other, AnyAngle):
return self.radian / other.radian
return AnyAngle(self.radian / other, is_radian=True)
```
</details>

View File

@ -1,31 +1,15 @@
--- ---
title: mbcp.mp\nmath.const title: mbcp.mp_math.const
order: 1
icon: laptop-code
category: API
--- ---
### ***var*** `PI = math.pi` ### ***var*** `PI = math.pi`
### ***var*** `E = math.e` ### ***var*** `E = math.e`
### ***var*** `GOLDEN_RATIO = (1 + math.sqrt(5)) / 2` ### ***var*** `GOLDEN_RATIO = (1 + math.sqrt(5)) / 2`
### ***var*** `GAMMA = 0.5772156649015329` ### ***var*** `GAMMA = 0.5772156649015329`
### ***var*** `EPSILON = 0.0001` ### ***var*** `EPSILON = 0.0001`
### ***var*** `APPROX = 0.001` ### ***var*** `APPROX = 0.001`

View File

@ -1,32 +1,25 @@
--- ---
title: mbcp.mp\nmath.equation title: mbcp.mp_math.equation
order: 1
icon: laptop-code
category: API
--- ---
### ***var*** `result_func = get_partial_derivative_func(result_func, v, epsilon)`
### *def* `get_partial_derivative_func(func: MultiVarsFunc = EPSILON)`
### ***def*** `get_partial_derivative_func(func: MultiVarsFunc, var: int | tuple[int, ...], epsilon: Number) -> MultiVarsFunc`
求N元函数一阶偏导函数。这玩意不太稳定慎用。 求N元函数一阶偏导函数。这玩意不太稳定慎用。
Args: 参数:
func: 函数 func: 函数
var: 变量位置,可为整数(一阶偏导)或整数元组(高阶偏导) var: 变量位置,可为整数(一阶偏导)或整数元组(高阶偏导)
epsilon: 偏移量 epsilon: 偏移量
Returns:
偏导函数
Raises:
ValueError: 无效变量类型
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def get_partial_derivative_func(func: MultiVarsFunc, var: int | tuple[int, ...], epsilon: Number=EPSILON) -> MultiVarsFunc: def get_partial_derivative_func(func: MultiVarsFunc, var: int | tuple[int, ...], epsilon: Number=EPSILON) -> MultiVarsFunc:
@ -63,12 +56,11 @@ def get_partial_derivative_func(func: MultiVarsFunc, var: int | tuple[int, ...],
``` ```
</details> </details>
### ***def*** `partial_derivative_func() -> Var` ### *def* `partial_derivative_func()`
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def partial_derivative_func(*args: Var) -> Var: def partial_derivative_func(*args: Var) -> Var:
@ -80,12 +72,11 @@ def partial_derivative_func(*args: Var) -> Var:
``` ```
</details> </details>
### ***def*** `high_order_partial_derivative_func() -> Var` ### *def* `high_order_partial_derivative_func()`
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def high_order_partial_derivative_func(*args: Var) -> Var: def high_order_partial_derivative_func(*args: Var) -> Var:
@ -98,28 +89,32 @@ def high_order_partial_derivative_func(*args: Var) -> Var:
### ***class*** `CurveEquation` ### ***class*** `CurveEquation`
- #### *def* `__init__(self, x_func: OneVarFunc, y_func: OneVarFunc, z_func: OneVarFunc)`
### &emsp; ***def*** `__init__(self, x_func: OneVarFunc, y_func: OneVarFunc, z_func: OneVarFunc) -> None` 曲线方程。
&emsp;曲线方程。 参数:
:param x_func: x_func: x函数
:param y_func: y_func: y函数
:param z_func: z_func: z函数
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
def __init__(self, x_func: OneVarFunc, y_func: OneVarFunc, z_func: OneVarFunc): def __init__(self, x_func: OneVarFunc, y_func: OneVarFunc, z_func: OneVarFunc):
""" """
曲线方程。 曲线方程。
:param x_func: Args:
:param y_func: x_func: x函数
:param z_func: y_func: y函数
z_func: z函数
""" """
self.x_func = x_func self.x_func = x_func
self.y_func = y_func self.y_func = y_func
@ -127,19 +122,48 @@ def __init__(self, x_func: OneVarFunc, y_func: OneVarFunc, z_func: OneVarFunc):
``` ```
</details> </details>
### ***var*** `args_list_plus = list(args)` - #### *def* `__call__(self)`
计算曲线上的点。
### ***var*** `args_list_minus = list(args)` 参数:
*t:
参数:
- #
<details>
<summary>源码</summary>
### ***var*** `result_func = func` ```python
def __call__(self, *t: Var) -> Point3 | tuple[Point3, ...]:
"""
计算曲线上的点。
Args:
*t:
参数
Returns:
"""
if len(t) == 1:
return Point3(self.x_func(t[0]), self.y_func(t[0]), self.z_func(t[0]))
else:
return tuple([Point3(x, y, z) for x, y, z in zip(self.x_func(t), self.y_func(t), self.z_func(t))])
```
</details>
- #### *def* `__str__(self)`
### ***var*** `result_func = get_partial_derivative_func(result_func, v, epsilon)` - #
<details>
<summary>源码</summary>
```python
def __str__(self):
return 'CurveEquation()'
```
</details>

View File

@ -1,7 +1,3 @@
--- ---
title: mbcp.mp\nmath.\n\ninit\n\n title: mbcp.mp_math
order: 1
icon: laptop-code
category: API
--- ---

View File

@ -1,26 +1,23 @@
--- ---
title: mbcp.mp\nmath.line title: mbcp.mp_math.line
order: 1
icon: laptop-code
category: API
--- ---
### ***class*** `Line3` ### ***class*** `Line3`
- #### *def* `__init__(self, point: 'Point3', direction: 'Vector3')`
### &emsp; ***def*** `__init__(self, point: 'Point3', direction: 'Vector3') -> None` 三维空间中的直线。由一个点和一个方向向量确定。
&emsp;三维空间中的直线。由一个点和一个方向向量确定。 参数:
Args: point: 直线上的一点
point: 直线上的一点 direction: 直线的方向向量
direction: 直线的方向向量
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def __init__(self, point: 'Point3', direction: 'Vector3'): def __init__(self, point: 'Point3', direction: 'Vector3'):
@ -35,22 +32,21 @@ def __init__(self, point: 'Point3', direction: 'Vector3'):
``` ```
</details> </details>
### &emsp; ***def*** `approx(self, other: 'Line3', epsilon: float) -> bool` - #### *def* `approx(self, other: 'Line3', epsilon: float = APPROX)`
&emsp;判断两条直线是否近似相等。
Args: 判断两条直线是否近似相等。
other: 另一条直线 参数:
epsilon: 误差 other: 另一条直线
Returns: epsilon: 误差
是否近似相等
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def approx(self, other: 'Line3', epsilon: float=APPROX) -> bool: def approx(self, other: 'Line3', epsilon: float=APPROX) -> bool:
@ -66,24 +62,19 @@ def approx(self, other: 'Line3', epsilon: float=APPROX) -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `cal_angle(self, other: 'Line3') -> 'AnyAngle'` - #### *def* `cal_angle(self, other: 'Line3')`
&emsp;计算直线和直线之间的夹角。
Args: 计算直线和直线之间的夹角。
other: 另一条直线 参数:
Returns: other: 另一条直线
夹角弧度
Raises:
TypeError: 不支持的类型
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_angle(self, other: 'Line3') -> 'AnyAngle': def cal_angle(self, other: 'Line3') -> 'AnyAngle':
@ -100,26 +91,19 @@ def cal_angle(self, other: 'Line3') -> 'AnyAngle':
``` ```
</details> </details>
### &emsp; ***def*** `cal_distance(self, other: 'Line3 | Point3') -> float` - #### *def* `cal_distance(self, other: 'Line3 | Point3')`
&emsp;计算直线和直线或点之间的距离。
Args:
other: 平行直线或点
计算直线和直线或点之间的距离。
Returns: 参数:
距离 other: 平行直线或点
Raises:
TypeError: 不支持的类型
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_distance(self, other: 'Line3 | Point3') -> float: def cal_distance(self, other: 'Line3 | Point3') -> float:
@ -149,26 +133,19 @@ def cal_distance(self, other: 'Line3 | Point3') -> float:
``` ```
</details> </details>
### &emsp; ***def*** `cal_intersection(self, other: 'Line3') -> 'Point3'` - #### *def* `cal_intersection(self, other: 'Line3')`
&emsp;计算两条直线的交点。
Args: 计算两条直线的交点。
other: 另一条直线 参数:
Returns: other: 另一条直线
交点
Raises:
ValueError: 直线平行
ValueError: 直线不共面
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_intersection(self, other: 'Line3') -> 'Point3': def cal_intersection(self, other: 'Line3') -> 'Point3':
@ -190,20 +167,19 @@ def cal_intersection(self, other: 'Line3') -> 'Point3':
``` ```
</details> </details>
### &emsp; ***def*** `cal_perpendicular(self, point: 'Point3') -> 'Line3'` - #### *def* `cal_perpendicular(self, point: 'Point3')`
&emsp;计算直线经过指定点p的垂线。
Args: 计算直线经过指定点p的垂线。
point: 指定点 参数:
Returns: point: 指定点
垂线
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_perpendicular(self, point: 'Point3') -> 'Line3': def cal_perpendicular(self, point: 'Point3') -> 'Line3':
@ -218,20 +194,19 @@ def cal_perpendicular(self, point: 'Point3') -> 'Line3':
``` ```
</details> </details>
### &emsp; ***def*** `get_point(self, t: RealNumber) -> 'Point3'` - #### *def* `get_point(self, t: RealNumber)`
&emsp;获取直线上的点。同一条直线但起始点和方向向量不同则同一个t对应的点不同。
Args: 获取直线上的点。同一条直线但起始点和方向向量不同则同一个t对应的点不同。
t: 参数t 参数:
Returns: t: 参数t
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def get_point(self, t: RealNumber) -> 'Point3': def get_point(self, t: RealNumber) -> 'Point3':
@ -246,16 +221,19 @@ def get_point(self, t: RealNumber) -> 'Point3':
``` ```
</details> </details>
### &emsp; ***def*** `get_parametric_equations(self) -> tuple[OneSingleVarFunc, OneSingleVarFunc, OneSingleVarFunc]` - #### *def* `get_parametric_equations(self)`
&emsp;获取直线的参数方程。
Returns: 获取直线的参数方程。
x(t), y(t), z(t) 返回:
x(t), y(t), z(t)
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
def get_parametric_equations(self) -> tuple[OneSingleVarFunc, OneSingleVarFunc, OneSingleVarFunc]: def get_parametric_equations(self) -> tuple[OneSingleVarFunc, OneSingleVarFunc, OneSingleVarFunc]:
@ -268,22 +246,21 @@ def get_parametric_equations(self) -> tuple[OneSingleVarFunc, OneSingleVarFunc,
``` ```
</details> </details>
### &emsp; ***def*** `is_approx_parallel(self, other: 'Line3', epsilon: float) -> bool` - #### *def* `is_approx_parallel(self, other: 'Line3', epsilon: float = 1e-06)`
&emsp;判断两条直线是否近似平行。
Args: 判断两条直线是否近似平行。
other: 另一条直线 参数:
epsilon: 误差 other: 另一条直线
Returns: epsilon: 误差
是否近似平行
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def is_approx_parallel(self, other: 'Line3', epsilon: float=1e-06) -> bool: def is_approx_parallel(self, other: 'Line3', epsilon: float=1e-06) -> bool:
@ -299,20 +276,19 @@ def is_approx_parallel(self, other: 'Line3', epsilon: float=1e-06) -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `is_parallel(self, other: 'Line3') -> bool` - #### *def* `is_parallel(self, other: 'Line3')`
&emsp;判断两条直线是否平行。
Args: 判断两条直线是否平行。
other: 另一条直线 参数:
Returns: other: 另一条直线
是否平行
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def is_parallel(self, other: 'Line3') -> bool: def is_parallel(self, other: 'Line3') -> bool:
@ -327,20 +303,19 @@ def is_parallel(self, other: 'Line3') -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `is_collinear(self, other: 'Line3') -> bool` - #### *def* `is_collinear(self, other: 'Line3')`
&emsp;判断两条直线是否共线。
Args: 判断两条直线是否共线。
other: 另一条直线 参数:
Returns: other: 另一条直线
是否共线
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def is_collinear(self, other: 'Line3') -> bool: def is_collinear(self, other: 'Line3') -> bool:
@ -355,20 +330,19 @@ def is_collinear(self, other: 'Line3') -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `is_point_on(self, point: 'Point3') -> bool` - #### *def* `is_point_on(self, point: 'Point3')`
&emsp;判断点是否在直线上。
Args: 判断点是否在直线上。
point: 点 参数:
Returns: point: 点
是否在直线上
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def is_point_on(self, point: 'Point3') -> bool: def is_point_on(self, point: 'Point3') -> bool:
@ -383,22 +357,20 @@ def is_point_on(self, point: 'Point3') -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `is_coplanar(self, other: 'Line3') -> bool` - #### *def* `is_coplanar(self, other: 'Line3')`
&emsp;判断两条直线是否共面。
判断两条直线是否共面。
充要条件两直线方向向量的叉乘与两直线上任意一点的向量的点积为0。 充要条件两直线方向向量的叉乘与两直线上任意一点的向量的点积为0。
Args: 参数:
other: 另一条直线 other: 另一条直线
Returns:
是否共面
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def is_coplanar(self, other: 'Line3') -> bool: def is_coplanar(self, other: 'Line3') -> bool:
@ -414,18 +386,18 @@ def is_coplanar(self, other: 'Line3') -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `simplify(self) -> None` - #### *def* `simplify(self)`
&emsp;简化直线方程,等价相等。
简化直线方程,等价相等。
自体简化,不返回值。 自体简化,不返回值。
按照可行性一次对x y z 化 0 处理,并对向量单位化 按照可行性一次对x y z 化 0 处理,并对向量单位化
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
def simplify(self): def simplify(self):
@ -445,23 +417,22 @@ def simplify(self):
``` ```
</details> </details>
### &emsp; ***@classmethod*** - #### `@classmethod`
### &emsp; ***def*** `from_two_points(cls: Any, p1: 'Point3', p2: 'Point3') -> 'Line3'` - #### *def* `from_two_points(cls, p1: 'Point3', p2: 'Point3')`
&emsp;工厂函数 由两点构造直线。
Args: 工厂函数 由两点构造直线。
p1: 点1 参数:
p2: 点2 p1: 点1
Returns: p2: 点2
直线
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
@classmethod @classmethod
@ -479,11 +450,107 @@ def from_two_points(cls, p1: 'Point3', p2: 'Point3') -> 'Line3':
``` ```
</details> </details>
### ***var*** `direction = p2 - p1` - #### *def* `__and__(self, other: 'Line3')`
计算两条直线点集合的交集。重合线返回自身平行线返回None交线返回交点。
参数:
other: 另一条直线
- #
<details>
<summary>源码</summary>
```python
def __and__(self, other: 'Line3') -> 'Line3 | Point3 | None':
"""
计算两条直线点集合的交集。重合线返回自身平行线返回None交线返回交点。
Args:
other: 另一条直线
Returns:
交点
"""
if self.is_collinear(other):
return self
elif self.is_parallel(other) or not self.is_coplanar(other):
return None
else:
return self.cal_intersection(other)
```
</details>
- #### *def* `__eq__(self, other)`
判断两条直线是否等价。
v1 // v2 ∧ (p1 - p2) // v1
参数:
other:
- #
<details>
<summary>源码</summary>
```python
def __eq__(self, other) -> bool:
"""
判断两条直线是否等价。
v1 // v2 ∧ (p1 - p2) // v1
Args:
other:
Returns:
"""
return self.direction.is_parallel(other.direction) and (self.point - other.point).is_parallel(self.direction)
```
</details>
- #### *def* `__str__(self)`
### ***var*** `s = 'Line3: '`
- #
<details>
<summary>源码</summary>
```python
def __str__(self):
"""
返回点向式x-x0
Returns:
"""
s = 'Line3: '
if self.direction.x != 0:
s += f'(x{sign_format(-self.point.x)})/{self.direction.x}'
if self.direction.y != 0:
s += f' = (y{sign_format(-self.point.y)})/{self.direction.y}'
if self.direction.z != 0:
s += f' = (z{sign_format(-self.point.z)})/{self.direction.z}'
return s
```
</details>
- #### *def* `__repr__(self)`
- #
<details>
<summary>源码</summary>
```python
def __repr__(self):
return f'Line3({self.point}, {self.direction})'
```
</details>

View File

@ -1,15 +1,37 @@
--- ---
title: mbcp.mp\nmath.mp\nmath\ntyping title: mbcp.mp_math.mp_math_typing
order: 1
icon: laptop-code
category: API
--- ---
### ***var*** `RealNumber: TypeAlias = int | float`
### ***var*** `Number: TypeAlias = RealNumber | complex`
### ***var*** `SingleVar = TypeVar('SingleVar', bound=Number)` ### ***var*** `SingleVar = TypeVar('SingleVar', bound=Number)`
### ***var*** `ArrayVar = TypeVar('ArrayVar', bound=Iterable[Number])` ### ***var*** `ArrayVar = TypeVar('ArrayVar', bound=Iterable[Number])`
### ***var*** `Var: TypeAlias = SingleVar | ArrayVar`
### ***var*** `OneSingleVarFunc: TypeAlias = Callable[[SingleVar], SingleVar]`
### ***var*** `OneArrayFunc: TypeAlias = Callable[[ArrayVar], ArrayVar]`
### ***var*** `OneVarFunc: TypeAlias = OneSingleVarFunc | OneArrayFunc`
### ***var*** `TwoSingleVarsFunc: TypeAlias = Callable[[SingleVar, SingleVar], SingleVar]`
### ***var*** `TwoArraysFunc: TypeAlias = Callable[[ArrayVar, ArrayVar], ArrayVar]`
### ***var*** `TwoVarsFunc: TypeAlias = TwoSingleVarsFunc | TwoArraysFunc`
### ***var*** `ThreeSingleVarsFunc: TypeAlias = Callable[[SingleVar, SingleVar, SingleVar], SingleVar]`
### ***var*** `ThreeArraysFunc: TypeAlias = Callable[[ArrayVar, ArrayVar, ArrayVar], ArrayVar]`
### ***var*** `ThreeVarsFunc: TypeAlias = ThreeSingleVarsFunc | ThreeArraysFunc`
### ***var*** `MultiSingleVarsFunc: TypeAlias = Callable[..., SingleVar]`
### ***var*** `MultiArraysFunc: TypeAlias = Callable[..., ArrayVar]`
### ***var*** `MultiVarsFunc: TypeAlias = MultiSingleVarsFunc | MultiArraysFunc`

View File

@ -1,30 +1,47 @@
--- ---
title: mbcp.mp\nmath.plane title: mbcp.mp_math.plane
order: 1
icon: laptop-code
category: API
--- ---
### ***var*** `k = other.a / self.a`
### ***var*** `A = np.array([[self.b, self.c], [other.b, other.c]])`
### ***var*** `B = np.array([-self.d, -other.d])`
### ***var*** `v2 = l2.get_point(1) - l1.point`
### ***var*** `k = other.b / self.b`
### ***var*** `A = np.array([[self.a, self.c], [other.a, other.c]])`
### ***var*** `B = np.array([-self.d, -other.d])`
### ***var*** `k = other.c / self.c`
### ***var*** `A = np.array([[self.a, self.b], [other.a, other.b]])`
### ***var*** `B = np.array([-self.d, -other.d])`
### ***class*** `Plane3` ### ***class*** `Plane3`
- #### *def* `__init__(self, a: float, b: float, c: float, d: float)`
### &emsp; ***def*** `__init__(self, a: float, b: float, c: float, d: float) -> None` 平面方程ax + by + cz + d = 0
&emsp;平面方程ax + by + cz + d = 0 参数:
Args: a:
a: b:
b: c:
c: d:
d:
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def __init__(self, a: float, b: float, c: float, d: float): def __init__(self, a: float, b: float, c: float, d: float):
@ -43,32 +60,26 @@ def __init__(self, a: float, b: float, c: float, d: float):
``` ```
</details> </details>
### &emsp; ***def*** `approx(self, other: 'Plane3', epsilon: float) -> bool` - #### *def* `approx(self, other: 'Plane3')`
&emsp;判断两个平面是否近似相等。
Args:
other:
epsilon:
判断两个平面是否近似相等。
Returns: 参数:
是否近似相等 other:
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
def approx(self, other: 'Plane3', epsilon: float=APPROX) -> bool: def approx(self, other: 'Plane3') -> bool:
""" """
判断两个平面是否近似相等。 判断两个平面是否近似相等。
Args: Args:
other: other:
epsilon:
Returns: Returns:
是否近似相等 是否近似相等
@ -87,24 +98,19 @@ def approx(self, other: 'Plane3', epsilon: float=APPROX) -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `cal_angle(self, other: 'Line3 | Plane3') -> 'AnyAngle'` - #### *def* `cal_angle(self, other: 'Line3 | Plane3')`
&emsp;计算平面与平面之间的夹角。
Args: 计算平面与平面之间的夹角。
other: 另一个平面 参数:
Returns: other: 另一个平面
夹角弧度
Raises:
TypeError: 不支持的类型
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_angle(self, other: 'Line3 | Plane3') -> 'AnyAngle': def cal_angle(self, other: 'Line3 | Plane3') -> 'AnyAngle':
@ -126,24 +132,19 @@ def cal_angle(self, other: 'Line3 | Plane3') -> 'AnyAngle':
``` ```
</details> </details>
### &emsp; ***def*** `cal_distance(self, other: 'Plane3 | Point3') -> float` - #### *def* `cal_distance(self, other: 'Plane3 | Point3')`
&emsp;计算平面与平面或点之间的距离。
Args: 计算平面与平面或点之间的距离。
other: 另一个平面或点 参数:
Returns: other: 另一个平面或点
距离
Raises:
TypeError: 不支持的类型
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_distance(self, other: 'Plane3 | Point3') -> float: def cal_distance(self, other: 'Plane3 | Point3') -> float:
@ -165,22 +166,19 @@ def cal_distance(self, other: 'Plane3 | Point3') -> float:
``` ```
</details> </details>
### &emsp; ***def*** `cal_intersection_line3(self, other: 'Plane3') -> 'Line3'` - #### *def* `cal_intersection_line3(self, other: 'Plane3')`
&emsp;计算两平面的交线。该方法有问题,待修复。
Args: 计算两平面的交线。该方法有问题,待修复。
other: 另一个平面 参数:
Returns: other: 另一个平面
交线
Raises:
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_intersection_line3(self, other: 'Plane3') -> 'Line3': def cal_intersection_line3(self, other: 'Plane3') -> 'Line3':
@ -212,24 +210,19 @@ def cal_intersection_line3(self, other: 'Plane3') -> 'Line3':
``` ```
</details> </details>
### &emsp; ***def*** `cal_intersection_point3(self, other: 'Line3') -> 'Point3'` - #### *def* `cal_intersection_point3(self, other: 'Line3')`
&emsp;计算平面与直线的交点。
Args: 计算平面与直线的交点。
other: 不与平面平行或在平面上的直线 参数:
Returns: other: 不与平面平行或在平面上的直线
交点
Raises:
ValueError: 平面与直线平行或重合
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_intersection_point3(self, other: 'Line3') -> 'Point3': def cal_intersection_point3(self, other: 'Line3') -> 'Point3':
@ -250,20 +243,19 @@ def cal_intersection_point3(self, other: 'Line3') -> 'Point3':
``` ```
</details> </details>
### &emsp; ***def*** `cal_parallel_plane3(self, point: 'Point3') -> 'Plane3'` - #### *def* `cal_parallel_plane3(self, point: 'Point3')`
&emsp;计算平行于该平面且过指定点的平面。
Args: 计算平行于该平面且过指定点的平面。
point: 指定点 参数:
Returns: point: 指定点
平面
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_parallel_plane3(self, point: 'Point3') -> 'Plane3': def cal_parallel_plane3(self, point: 'Point3') -> 'Plane3':
@ -278,20 +270,19 @@ def cal_parallel_plane3(self, point: 'Point3') -> 'Plane3':
``` ```
</details> </details>
### &emsp; ***def*** `is_parallel(self, other: 'Plane3') -> bool` - #### *def* `is_parallel(self, other: 'Plane3')`
&emsp;判断两个平面是否平行。
Args: 判断两个平面是否平行。
other: 另一个平面 参数:
Returns: other: 另一个平面
是否平行
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def is_parallel(self, other: 'Plane3') -> bool: def is_parallel(self, other: 'Plane3') -> bool:
@ -306,17 +297,20 @@ def is_parallel(self, other: 'Plane3') -> bool:
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `normal(self: Any) -> 'Vector3'` - #### *def* `normal(self)`
&emsp;平面的法向量。
Returns: 平面的法向量。
法向量 返回:
法向量
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -330,23 +324,22 @@ def normal(self) -> 'Vector3':
``` ```
</details> </details>
### &emsp; ***@classmethod*** - #### `@classmethod`
### &emsp; ***def*** `from_point_and_normal(cls: Any, point: 'Point3', normal: 'Vector3') -> 'Plane3'` - #### *def* `from_point_and_normal(cls, point: 'Point3', normal: 'Vector3')`
&emsp;工厂函数 由点和法向量构造平面(点法式构造)。
Args: 工厂函数 由点和法向量构造平面(点法式构造)。
point: 平面上的一点 参数:
normal: 法向量 point: 平面上的一点
Returns: normal: 法向量
平面
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
@classmethod @classmethod
@ -365,25 +358,24 @@ def from_point_and_normal(cls, point: 'Point3', normal: 'Vector3') -> 'Plane3':
``` ```
</details> </details>
### &emsp; ***@classmethod*** - #### `@classmethod`
### &emsp; ***def*** `from_three_points(cls: Any, p1: 'Point3', p2: 'Point3', p3: 'Point3') -> 'Plane3'` - #### *def* `from_three_points(cls, p1: 'Point3', p2: 'Point3', p3: 'Point3')`
&emsp;工厂函数 由三点构造平面。
Args: 工厂函数 由三点构造平面。
p1: 点1 参数:
p2: 点2 p1: 点1
p3: 点3 p2: 点2
Returns: p3: 点3
平面
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
@classmethod @classmethod
@ -404,23 +396,22 @@ def from_three_points(cls, p1: 'Point3', p2: 'Point3', p3: 'Point3') -> 'Plane3'
``` ```
</details> </details>
### &emsp; ***@classmethod*** - #### `@classmethod`
### &emsp; ***def*** `from_two_lines(cls: Any, l1: 'Line3', l2: 'Line3') -> 'Plane3'` - #### *def* `from_two_lines(cls, l1: 'Line3', l2: 'Line3')`
&emsp;工厂函数 由两直线构造平面。
Args: 工厂函数 由两直线构造平面。
l1: 直线1 参数:
l2: 直线2 l1: 直线1
Returns: l2: 直线2
平面
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
@classmethod @classmethod
@ -441,23 +432,22 @@ def from_two_lines(cls, l1: 'Line3', l2: 'Line3') -> 'Plane3':
``` ```
</details> </details>
### &emsp; ***@classmethod*** - #### `@classmethod`
### &emsp; ***def*** `from_point_and_line(cls: Any, point: 'Point3', line: 'Line3') -> 'Plane3'` - #### *def* `from_point_and_line(cls, point: 'Point3', line: 'Line3')`
&emsp;工厂函数 由点和直线构造平面。
Args: 工厂函数 由点和直线构造平面。
point: 面上一点 参数:
line: 面上直线,不包含点 point: 面上一点
Returns: line: 面上直线,不包含点
平面
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
@classmethod @classmethod
@ -474,79 +464,124 @@ def from_point_and_line(cls, point: 'Point3', line: 'Line3') -> 'Plane3':
``` ```
</details> </details>
### ***var*** `direction = self.normal.cross(other.normal)` - #### *def* `__repr__(self)`
- #
<details>
<summary>源码</summary>
```python
def __repr__(self):
return f'Plane3({self.a}, {self.b}, {self.c}, {self.d})'
```
</details>
- #### *def* `__str__(self)`
- #
<details>
<summary>源码</summary>
```python
def __str__(self):
s = 'Plane3: '
if self.a != 0:
s += f'{sign(self.a, only_neg=True)}{abs(self.a)}x'
if self.b != 0:
s += f' {sign(self.b)} {abs(self.b)}y'
if self.c != 0:
s += f' {sign(self.c)} {abs(self.c)}z'
if self.d != 0:
s += f' {sign(self.d)} {abs(self.d)}'
return s + ' = 0'
```
</details>
- #### `@overload`
- #### *def* `__and__(self, other: 'Line3')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __and__(self, other: 'Line3') -> 'Point3 | None':
...
```
</details>
- #### `@overload`
- #### *def* `__and__(self, other: 'Plane3')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __and__(self, other: 'Plane3') -> 'Line3 | None':
...
```
</details>
- #### *def* `__and__(self, other)`
取两平面的交集(人话:交线)
### ***var*** `t = -(self.a * other.point.x + self.b * other.point.y + self.c * other.point.z + self.d) / (self.a * other.direction.x + self.b * other.direction.y + self.c * other.direction.z)` 参数:
other:
- #
<details>
<summary>源码</summary>
### ***var*** `d = -a * point.x - b * point.y - c * point.z` ```python
def __and__(self, other):
"""
取两平面的交集(人话:交线)
Args:
other:
Returns:
不平行平面的交线平面平行返回None
"""
if isinstance(other, Plane3):
if self.normal.is_parallel(other.normal):
return None
return self.cal_intersection_line3(other)
elif isinstance(other, Line3):
if self.normal @ other.direction == 0:
return None
return self.cal_intersection_point3(other)
else:
raise TypeError(f"unsupported operand type(s) for &: 'Plane3' and '{type(other)}'")
```
</details>
- #### *def* `__eq__(self, other)`
- #
<details>
<summary>源码</summary>
### ***var*** `v1 = p2 - p1` ```python
def __eq__(self, other) -> bool:
return self.approx(other)
```
</details>
- #### *def* `__rand__(self, other: 'Line3')`
- #
<details>
<summary>源码</summary>
### ***var*** `v2 = p3 - p1` ```python
def __rand__(self, other: 'Line3') -> 'Point3':
return self.cal_intersection_point3(other)
```
### ***var*** `normal = v1.cross(v2)` </details>
### ***var*** `v1 = l1.direction`
### ***var*** `v2 = l2.point - l1.point`
### ***var*** `s = 'Plane3: '`
### ***var*** `k = other.a / self.a`
### ***var*** `A = np.array([[self.b, self.c], [other.b, other.c]])`
### ***var*** `B = np.array([-self.d, -other.d])`
### ***var*** `v2 = l2.get_point(1) - l1.point`
### ***var*** `k = other.b / self.b`
### ***var*** `A = np.array([[self.a, self.c], [other.a, other.c]])`
### ***var*** `B = np.array([-self.d, -other.d])`
### ***var*** `k = other.c / self.c`
### ***var*** `A = np.array([[self.a, self.b], [other.a, other.b]])`
### ***var*** `B = np.array([-self.d, -other.d])`

View File

@ -1,28 +1,25 @@
--- ---
title: mbcp.mp\nmath.point title: mbcp.mp_math.point
order: 1
icon: laptop-code
category: API
--- ---
### ***class*** `Point3` ### ***class*** `Point3`
- #### *def* `__init__(self, x: float, y: float, z: float)`
### &emsp; ***def*** `__init__(self, x: float, y: float, z: float) -> None` 笛卡尔坐标系中的点。
&emsp;笛卡尔坐标系中的点。 参数:
Args: x: x 坐标
x: x 坐标 y: y 坐标
y: y 坐标 z: z 坐标
z: z 坐标
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def __init__(self, x: float, y: float, z: float): def __init__(self, x: float, y: float, z: float):
@ -39,24 +36,21 @@ def __init__(self, x: float, y: float, z: float):
``` ```
</details> </details>
### &emsp; ***def*** `approx(self, other: 'Point3', epsilon: float) -> bool` - #### *def* `approx(self, other: 'Point3', epsilon: float = APPROX)`
&emsp;判断两个点是否近似相等。
Args:
other:
epsilon:
判断两个点是否近似相等。
Returns: 参数:
是否近似相等 other:
epsilon:
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
def approx(self, other: 'Point3', epsilon: float=APPROX) -> bool: def approx(self, other: 'Point3', epsilon: float=APPROX) -> bool:
@ -73,3 +67,97 @@ def approx(self, other: 'Point3', epsilon: float=APPROX) -> bool:
``` ```
</details> </details>
- #### *def* `__str__(self)`
- #
<details>
<summary>源码</summary>
```python
def __str__(self):
return f'Point3({self.x}, {self.y}, {self.z})'
```
</details>
- #### `@overload`
- #### *def* `__add__(self, other: 'Vector3')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __add__(self, other: 'Vector3') -> 'Point3':
...
```
</details>
- #### `@overload`
- #### *def* `__add__(self, other: 'Point3')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __add__(self, other: 'Point3') -> 'Point3':
...
```
</details>
- #### *def* `__add__(self, other)`
P + V -> P
P + P -> P
参数:
other:
- #
<details>
<summary>源码</summary>
```python
def __add__(self, other):
"""
P + V -> P
P + P -> P
Args:
other:
Returns:
"""
return Point3(self.x + other.x, self.y + other.y, self.z + other.z)
```
</details>
- #### *def* `__eq__(self, other)`
判断两个点是否相等。
参数:
other:
- #
<details>
<summary>源码</summary>
```python
def __eq__(self, other):
"""
判断两个点是否相等。
Args:
other:
Returns:
"""
return approx(self.x, other.x) and approx(self.y, other.y) and approx(self.z, other.z)
```
</details>

View File

@ -1,24 +1,19 @@
--- ---
title: mbcp.mp\nmath.segment title: mbcp.mp_math.segment
order: 1
icon: laptop-code
category: API
--- ---
### ***class*** `Segment3` ### ***class*** `Segment3`
- #### *def* `__init__(self, p1: 'Point3', p2: 'Point3')`
### &emsp; ***def*** `__init__(self, p1: 'Point3', p2: 'Point3') -> None` 三维空间中的线段。
&emsp;三维空间中的线段。
:param p1: :param p1:
:param p2: :param p2:
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
def __init__(self, p1: 'Point3', p2: 'Point3'): def __init__(self, p1: 'Point3', p2: 'Point3'):
@ -38,3 +33,27 @@ def __init__(self, p1: 'Point3', p2: 'Point3'):
``` ```
</details> </details>
- #### *def* `__repr__(self)`
- #
<details>
<summary>源码</summary>
```python
def __repr__(self):
return f'Segment3({self.p1}, {self.p2})'
```
</details>
- #### *def* `__str__(self)`
- #
<details>
<summary>源码</summary>
```python
def __str__(self):
return f'Segment3({self.p1} -> {self.p2})'
```
</details>

View File

@ -1,30 +1,23 @@
--- ---
title: mbcp.mp\nmath.utils title: mbcp.mp_math.utils
order: 1
icon: laptop-code
category: API
--- ---
### *def* `clamp()`
### ***def*** `clamp(x: float, min_: float, max_: float) -> float`
区间截断函数。 区间截断函数。
Args: 参数:
x: x:
min_: min_:
max_: max_:
Returns:
限制后的值
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def clamp(x: float, min_: float, max_: float) -> float: def clamp(x: float, min_: float, max_: float) -> float:
@ -42,26 +35,23 @@ def clamp(x: float, min_: float, max_: float) -> float:
``` ```
</details> </details>
### ***def*** `approx(x: float, y: float, epsilon: float) -> bool` ### *def* `approx(x: float = 0.0, y: float = APPROX)`
判断两个数是否近似相等。或包装一个实数用于判断是否近似于0。 判断两个数是否近似相等。或包装一个实数用于判断是否近似于0。
Args: 参数:
x: x:
y: y:
epsilon: epsilon:
Returns:
是否近似相等
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def approx(x: float, y: float=0.0, epsilon: float=APPROX) -> bool: def approx(x: float, y: float=0.0, epsilon: float=APPROX) -> bool:
@ -79,22 +69,21 @@ def approx(x: float, y: float=0.0, epsilon: float=APPROX) -> bool:
``` ```
</details> </details>
### ***def*** `sign(x: float, only_neg: bool) -> str` ### *def* `sign(x: float = False)`
获取数的符号。 获取数的符号。
Args: 参数:
x: 数 x: 数
only_neg: 是否只返回负数的符号 only_neg: 是否只返回负数的符号
Returns:
符号 + - ""
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def sign(x: float, only_neg: bool=False) -> str: def sign(x: float, only_neg: bool=False) -> str:
@ -114,28 +103,24 @@ def sign(x: float, only_neg: bool=False) -> str:
``` ```
</details> </details>
### ***def*** `sign_format(x: float, only_neg: bool) -> str` ### *def* `sign_format(x: float = False)`
格式化符号数 格式化符号数
-1 -> -1 -1 -> -1
1 -> +1 1 -> +1
0 -> "" 0 -> ""
Args: 参数:
x: 数 x: 数
only_neg: 是否只返回负数的符号 only_neg: 是否只返回负数的符号
Returns:
符号 + - ""
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def sign_format(x: float, only_neg: bool=False) -> str: def sign_format(x: float, only_neg: bool=False) -> str:
@ -160,18 +145,11 @@ def sign_format(x: float, only_neg: bool=False) -> str:
### ***class*** `Approx` ### ***class*** `Approx`
用于近似比较对象 - #### *def* `__init__(self, value: RealNumber)`
已实现对象 实数 Vector3 Point3 Plane3 Line3
### &emsp; ***def*** `__init__(self, value: RealNumber) -> None`
&emsp;
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def __init__(self, value: RealNumber): def __init__(self, value: RealNumber):
@ -179,12 +157,32 @@ def __init__(self, value: RealNumber):
``` ```
</details> </details>
### &emsp; ***def*** `raise_type_error(self, other: Any) -> None` - #### *def* `__eq__(self, other)`
&emsp;
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python
def __eq__(self, other):
if isinstance(self.value, (float, int)):
if isinstance(other, (float, int)):
return abs(self.value - other) < APPROX
else:
self.raise_type_error(other)
elif isinstance(self.value, Vector3):
if isinstance(other, (Vector3, Point3, Plane3, Line3)):
return all([approx(self.value.x, other.x), approx(self.value.y, other.y), approx(self.value.z, other.z)])
else:
self.raise_type_error(other)
```
</details>
- #### *def* `raise_type_error(self, other)`
- #
<details>
<summary>源码</summary>
```python ```python
def raise_type_error(self, other): def raise_type_error(self, other):
@ -192,3 +190,15 @@ def raise_type_error(self, other):
``` ```
</details> </details>
- #### *def* `__ne__(self, other)`
- #
<details>
<summary>源码</summary>
```python
def __ne__(self, other):
return not self.__eq__(other)
```
</details>

View File

@ -1,28 +1,33 @@
--- ---
title: mbcp.mp\nmath.vector title: mbcp.mp_math.vector
order: 1
icon: laptop-code
category: API
--- ---
### ***var*** `zero_vector3 = Vector3(0, 0, 0)`
### ***var*** `x_axis = Vector3(1, 0, 0)`
### ***var*** `y_axis = Vector3(0, 1, 0)`
### ***var*** `z_axis = Vector3(0, 0, 1)`
### ***class*** `Vector3` ### ***class*** `Vector3`
- #### *def* `__init__(self, x: float, y: float, z: float)`
### &emsp; ***def*** `__init__(self, x: float, y: float, z: float) -> None` 3维向量
&emsp;3维向量 参数:
Args: x: x轴分量
x: x轴分量 y: y轴分量
y: y轴分量 z: z轴分量
z: z轴分量
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def __init__(self, x: float, y: float, z: float): def __init__(self, x: float, y: float, z: float):
@ -39,24 +44,21 @@ def __init__(self, x: float, y: float, z: float):
``` ```
</details> </details>
### &emsp; ***def*** `approx(self, other: 'Vector3', epsilon: float) -> bool` - #### *def* `approx(self, other: 'Vector3', epsilon: float = APPROX)`
&emsp;判断两个向量是否近似相等。
Args:
other:
epsilon:
判断两个向量是否近似相等。
Returns: 参数:
是否近似相等 other:
epsilon:
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
def approx(self, other: 'Vector3', epsilon: float=APPROX) -> bool: def approx(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
@ -73,20 +75,19 @@ def approx(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `cal_angle(self, other: 'Vector3') -> 'AnyAngle'` - #### *def* `cal_angle(self, other: 'Vector3')`
&emsp;计算两个向量之间的夹角。
Args: 计算两个向量之间的夹角。
other: 另一个向量 参数:
Returns: other: 另一个向量
夹角
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cal_angle(self, other: 'Vector3') -> 'AnyAngle': def cal_angle(self, other: 'Vector3') -> 'AnyAngle':
@ -101,44 +102,19 @@ def cal_angle(self, other: 'Vector3') -> 'AnyAngle':
``` ```
</details> </details>
### &emsp; ***def*** `cross(self, other: 'Vector3') -> 'Vector3'` - #### *def* `cross(self, other: 'Vector3')`
&emsp;向量积 叉乘v1 cross v2 -> v3
向量积 叉乘v1 cross v2 -> v3
叉乘为0则两向量平行。 叉乘为0则两向量平行。
其余结果的模为平行四边形的面积。 其余结果的模为平行四边形的面积。
返回如下行列式的结果: - #
``i j k``
``x1 y1 z1``
``x2 y2 z2``
Args:
other:
Returns:
行列式的结果
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def cross(self, other: 'Vector3') -> 'Vector3': def cross(self, other: 'Vector3') -> 'Vector3':
@ -165,22 +141,21 @@ def cross(self, other: 'Vector3') -> 'Vector3':
``` ```
</details> </details>
### &emsp; ***def*** `is_approx_parallel(self, other: 'Vector3', epsilon: float) -> bool` - #### *def* `is_approx_parallel(self, other: 'Vector3', epsilon: float = APPROX)`
&emsp;判断两个向量是否近似平行。
Args: 判断两个向量是否近似平行。
other: 另一个向量 参数:
epsilon: 允许的误差 other: 另一个向量
Returns: epsilon: 允许的误差
是否近似平行
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def is_approx_parallel(self, other: 'Vector3', epsilon: float=APPROX) -> bool: def is_approx_parallel(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
@ -196,20 +171,19 @@ def is_approx_parallel(self, other: 'Vector3', epsilon: float=APPROX) -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `is_parallel(self, other: 'Vector3') -> bool` - #### *def* `is_parallel(self, other: 'Vector3')`
&emsp;判断两个向量是否平行。
Args: 判断两个向量是否平行。
other: 另一个向量 参数:
Returns: other: 另一个向量
是否平行
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
def is_parallel(self, other: 'Vector3') -> bool: def is_parallel(self, other: 'Vector3') -> bool:
@ -224,16 +198,17 @@ def is_parallel(self, other: 'Vector3') -> bool:
``` ```
</details> </details>
### &emsp; ***def*** `normalize(self) -> None` - #### *def* `normalize(self)`
&emsp;将向量归一化。
将向量归一化。
自体归一化,不返回值。 自体归一化,不返回值。
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
def normalize(self): def normalize(self):
@ -249,15 +224,16 @@ def normalize(self):
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `np_array(self: Any) -> 'np.ndarray'` - #### *def* `np_array(self)`
&emsp;返回numpy数组
Returns:
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -270,17 +246,20 @@ def np_array(self) -> 'np.ndarray':
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `length(self: Any) -> float` - #### *def* `length(self)`
&emsp;向量的模。
Returns: 向量的模。
返回:
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -294,17 +273,20 @@ def length(self) -> float:
``` ```
</details> </details>
### &emsp; ***@property*** - #### `@property`
### &emsp; ***def*** `unit(self: Any) -> 'Vector3'` - #### *def* `unit(self)`
&emsp;获取该向量的单位向量。
Returns: 获取该向量的单位向量。
单位向量 返回:
单位向量
- #
<details> <details>
<summary>源代码</summary> <summary>源码</summary>
```python ```python
@property @property
@ -318,23 +300,372 @@ def unit(self) -> 'Vector3':
``` ```
</details> </details>
### ***var*** `zero_vector3 = Vector3(0, 0, 0)` - #### *def* `__abs__(self)`
- #
<details>
<summary>源码</summary>
```python
def __abs__(self):
return self.length
```
</details>
- #### `@overload`
- #### *def* `__add__(self, other: 'Vector3')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __add__(self, other: 'Vector3') -> 'Vector3':
...
```
</details>
- #### `@overload`
- #### *def* `__add__(self, other: 'Point3')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __add__(self, other: 'Point3') -> 'Point3':
...
```
</details>
- #### *def* `__add__(self, other)`
V + P -> P
### ***var*** `x_axis = Vector3(1, 0, 0)` V + V -> V
参数:
other:
- #
<details>
<summary>源码</summary>
### ***var*** `y_axis = Vector3(0, 1, 0)` ```python
def __add__(self, other):
"""
V + P -> P
V + V -> V
Args:
other:
Returns:
"""
if isinstance(other, Vector3):
return Vector3(self.x + other.x, self.y + other.y, self.z + other.z)
elif isinstance(other, Point3):
return Point3(self.x + other.x, self.y + other.y, self.z + other.z)
else:
raise TypeError(f"unsupported operand type(s) for +: 'Vector3' and '{type(other)}'")
```
</details>
- #### *def* `__eq__(self, other)`
判断两个向量是否相等。
### ***var*** `z_axis = Vector3(0, 0, 1)` 参数:
other:
- #
<details>
<summary>源码</summary>
### ***var*** `length = self.length` ```python
def __eq__(self, other):
"""
判断两个向量是否相等。
Args:
other:
Returns:
是否相等
"""
return approx(self.x, other.x) and approx(self.y, other.y) and approx(self.z, other.z)
```
</details>
- #### *def* `__radd__(self, other: 'Point3')`
P + V -> P
别去点那边实现了。
:param other:
:return:
- #
<details>
<summary>源码</summary>
```python
def __radd__(self, other: 'Point3') -> 'Point3':
"""
P + V -> P
别去点那边实现了。
:param other:
:return:
"""
return Point3(self.x + other.x, self.y + other.y, self.z + other.z)
```
</details>
- #### `@overload`
- #### *def* `__sub__(self, other: 'Vector3')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __sub__(self, other: 'Vector3') -> 'Vector3':
...
```
</details>
- #### `@overload`
- #### *def* `__sub__(self, other: 'Point3')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __sub__(self, other: 'Point3') -> 'Point3':
...
```
</details>
- #### *def* `__sub__(self, other)`
V - P -> P
V - V -> V
参数:
other:
- #
<details>
<summary>源码</summary>
```python
def __sub__(self, other):
"""
V - P -> P
V - V -> V
Args:
other:
Returns:
"""
if isinstance(other, Vector3):
return Vector3(self.x - other.x, self.y - other.y, self.z - other.z)
elif isinstance(other, Point3):
return Point3(self.x - other.x, self.y - other.y, self.z - other.z)
else:
raise TypeError(f'unsupported operand type(s) for -: "Vector3" and "{type(other)}"')
```
</details>
- #### *def* `__rsub__(self, other: 'Point3')`
P - V -> P
参数:
other:
- #
<details>
<summary>源码</summary>
```python
def __rsub__(self, other: 'Point3'):
"""
P - V -> P
Args:
other:
Returns:
"""
if isinstance(other, Point3):
return Point3(other.x - self.x, other.y - self.y, other.z - self.z)
else:
raise TypeError(f"unsupported operand type(s) for -: '{type(other)}' and 'Vector3'")
```
</details>
- #### `@overload`
- #### *def* `__mul__(self, other: 'Vector3')`
- #
<details>
<summary>源码</summary>
```python
@overload
def __mul__(self, other: 'Vector3') -> 'Vector3':
...
```
</details>
- #### `@overload`
- #### *def* `__mul__(self, other: RealNumber)`
- #
<details>
<summary>源码</summary>
```python
@overload
def __mul__(self, other: RealNumber) -> 'Vector3':
...
```
</details>
- #### *def* `__mul__(self, other: 'int | float | Vector3')`
数组运算 非点乘。点乘使用@叉乘使用cross。
参数:
other:
- #
<details>
<summary>源码</summary>
```python
def __mul__(self, other: 'int | float | Vector3') -> 'Vector3':
"""
数组运算 非点乘。点乘使用@叉乘使用cross。
Args:
other:
Returns:
"""
if isinstance(other, Vector3):
return Vector3(self.x * other.x, self.y * other.y, self.z * other.z)
elif isinstance(other, (float, int)):
return Vector3(self.x * other, self.y * other, self.z * other)
else:
raise TypeError(f"unsupported operand type(s) for *: 'Vector3' and '{type(other)}'")
```
</details>
- #### *def* `__rmul__(self, other: 'RealNumber')`
- #
<details>
<summary>源码</summary>
```python
def __rmul__(self, other: 'RealNumber') -> 'Vector3':
return self.__mul__(other)
```
</details>
- #### *def* `__matmul__(self, other: 'Vector3')`
点乘。
参数:
other:
- #
<details>
<summary>源码</summary>
```python
def __matmul__(self, other: 'Vector3') -> 'RealNumber':
"""
点乘。
Args:
other:
Returns:
"""
return self.x * other.x + self.y * other.y + self.z * other.z
```
</details>
- #### *def* `__truediv__(self, other: RealNumber)`
- #
<details>
<summary>源码</summary>
```python
def __truediv__(self, other: RealNumber) -> 'Vector3':
return Vector3(self.x / other, self.y / other, self.z / other)
```
</details>
- #### *def* `__neg__(self)`
- #
<details>
<summary>源码</summary>
```python
def __neg__(self):
return Vector3(-self.x, -self.y, -self.z)
```
</details>
- #### *def* `__repr__(self)`
- #
<details>
<summary>源码</summary>
```python
def __repr__(self):
return f'Vector3({self.x}, {self.y}, {self.z})'
```
</details>
- #### *def* `__str__(self)`
- #
<details>
<summary>源码</summary>
```python
def __str__(self):
return f'Vector3({self.x}, {self.y}, {self.z})'
```
</details>

View File

@ -1,7 +1,3 @@
--- ---
title: mbcp.particle.\n\ninit\n\n title: mbcp.particle
order: 1
icon: laptop-code
category: API
--- ---

View File

@ -1,7 +1,3 @@
--- ---
title: mbcp.presets.\n\ninit\n\n title: mbcp.presets
order: 1
icon: laptop-code
category: API
--- ---

View File

@ -1,26 +1,24 @@
--- ---
title: mbcp.presets.model.\n\ninit\n\n title: mbcp.presets.model
order: 1
icon: laptop-code
category: API
--- ---
### ***class*** `GeometricModels`
- #### `@staticmethod`
- #### *def* `sphere(radius: float, density: float)`
### ***def*** `sphere(radius: float, density: float) -> None`
生成球体上的点集。 生成球体上的点集。
Args: 参数:
radius: radius:
density: density:
Returns:
List[Point3]: 球体上的点集。
- #
<details> <details>
<summary></summary> <summary>源码</summary>
```python ```python
@staticmethod @staticmethod
@ -44,75 +42,3 @@ def sphere(radius: float, density: float):
``` ```
</details> </details>
### ***class*** `GeometricModels`
### &emsp; ***@staticmethod***
### &emsp; ***def*** `sphere(radius: float, density: float) -> None`
&emsp;生成球体上的点集。
Args:
radius:
density:
Returns:
List[Point3]: 球体上的点集。
<details>
<summary>源代码</summary>
```python
@staticmethod
def sphere(radius: float, density: float):
"""
生成球体上的点集。
Args:
radius:
density:
Returns:
List[Point3]: 球体上的点集。
"""
area = 4 * np.pi * radius ** 2
num = int(area * density)
phi_list = np.arccos([clamp(-1 + (2.0 * _ - 1.0) / num, -1, 1) for _ in range(num)])
theta_list = np.sqrt(num * np.pi) * phi_list
x_array = radius * np.sin(phi_list) * np.cos(theta_list)
y_array = radius * np.sin(phi_list) * np.sin(theta_list)
z_array = radius * np.cos(phi_list)
return [Point3(x_array[i], y_array[i], z_array[i]) for i in range(num)]
```
</details>
### ***var*** `area = 4 * np.pi * radius ** 2`
### ***var*** `num = int(area * density)`
### ***var*** `phi_list = np.arccos([clamp(-1 + (2.0 * _ - 1.0) / num, -1, 1) for _ in range(num)])`
### ***var*** `theta_list = np.sqrt(num * np.pi) * phi_list`
### ***var*** `x_array = radius * np.sin(phi_list) * np.cos(theta_list)`
### ***var*** `y_array = radius * np.sin(phi_list) * np.sin(theta_list)`
### ***var*** `z_array = radius * np.cos(phi_list)`

View File

@ -1,6 +1,7 @@
{ {
"devDependencies": { "devDependencies": {
"vitepress": "^1.3.4" "vitepress": "^1.3.4",
"vitepress-auto-sidebar-plugin": "^0.2.4"
}, },
"scripts": { "scripts": {
"docs:dev": "vitepress dev", "docs:dev": "vitepress dev",

View File

@ -8,6 +8,9 @@ devDependencies:
vitepress: vitepress:
specifier: ^1.3.4 specifier: ^1.3.4
version: 1.3.4(@algolia/client-search@5.1.1)(search-insights@2.17.0) version: 1.3.4(@algolia/client-search@5.1.1)(search-insights@2.17.0)
vitepress-auto-sidebar-plugin:
specifier: ^0.2.4
version: 0.2.4(vite@5.4.2)(vitepress@1.3.4)
packages: packages:
@ -470,6 +473,27 @@ packages:
resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
dev: true dev: true
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
dev: true
/@nodelib/fs.stat@2.0.5:
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
dev: true
/@nodelib/fs.walk@1.2.8:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
dev: true
/@rollup/rollup-android-arm-eabi@4.21.1: /@rollup/rollup-android-arm-eabi@4.21.1:
resolution: {integrity: sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==} resolution: {integrity: sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==}
cpu: [arm] cpu: [arm]
@ -856,10 +880,28 @@ packages:
'@algolia/transporter': 4.24.0 '@algolia/transporter': 4.24.0
dev: true dev: true
/argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
dependencies:
sprintf-js: 1.0.3
dev: true
/birpc@0.2.17: /birpc@0.2.17:
resolution: {integrity: sha512-+hkTxhot+dWsLpp3gia5AkVHIsKlZybNT5gIYiDlNzJrmYPcTM9k5/w2uaj3IPpd7LlEYpmCj4Jj1nC41VhDFg==} resolution: {integrity: sha512-+hkTxhot+dWsLpp3gia5AkVHIsKlZybNT5gIYiDlNzJrmYPcTM9k5/w2uaj3IPpd7LlEYpmCj4Jj1nC41VhDFg==}
dev: true dev: true
/braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
dependencies:
fill-range: 7.1.1
dev: true
/consola@3.2.3:
resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==}
engines: {node: ^14.18.0 || >=16.10.0}
dev: true
/copy-anything@3.0.5: /copy-anything@3.0.5:
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
engines: {node: '>=12.13'} engines: {node: '>=12.13'}
@ -907,10 +949,47 @@ packages:
'@esbuild/win32-x64': 0.21.5 '@esbuild/win32-x64': 0.21.5
dev: true dev: true
/esprima@4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: true
/estree-walker@2.0.2: /estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
dev: true dev: true
/extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
dependencies:
is-extendable: 0.1.1
dev: true
/fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'}
dependencies:
'@nodelib/fs.stat': 2.0.5
'@nodelib/fs.walk': 1.2.8
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.8
dev: true
/fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
dependencies:
reusify: 1.0.4
dev: true
/fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
dependencies:
to-regex-range: 5.0.1
dev: true
/focus-trap@7.5.4: /focus-trap@7.5.4:
resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==}
dependencies: dependencies:
@ -925,15 +1004,67 @@ packages:
dev: true dev: true
optional: true optional: true
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
dev: true
/gray-matter@4.0.3:
resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
engines: {node: '>=6.0'}
dependencies:
js-yaml: 3.14.1
kind-of: 6.0.3
section-matter: 1.0.0
strip-bom-string: 1.0.0
dev: true
/hookable@5.5.3: /hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
dev: true dev: true
/is-extendable@0.1.1:
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
engines: {node: '>=0.10.0'}
dev: true
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
dev: true
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
dev: true
/is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
dev: true
/is-what@4.1.16: /is-what@4.1.16:
resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
engines: {node: '>=12.13'} engines: {node: '>=12.13'}
dev: true dev: true
/js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
dependencies:
argparse: 1.0.10
esprima: 4.0.1
dev: true
/kind-of@6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
dev: true
/magic-string@0.30.11: /magic-string@0.30.11:
resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==}
dependencies: dependencies:
@ -944,6 +1075,19 @@ packages:
resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==}
dev: true dev: true
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
dev: true
/micromatch@4.0.8:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
dependencies:
braces: 3.0.3
picomatch: 2.3.1
dev: true
/minisearch@7.1.0: /minisearch@7.1.0:
resolution: {integrity: sha512-tv7c/uefWdEhcu6hvrfTihflgeEi2tN6VV7HJnCjK6VxM75QQJh4t9FwJCsA2EsRS8LCnu3W87CuGPWMocOLCA==} resolution: {integrity: sha512-tv7c/uefWdEhcu6hvrfTihflgeEi2tN6VV7HJnCjK6VxM75QQJh4t9FwJCsA2EsRS8LCnu3W87CuGPWMocOLCA==}
dev: true dev: true
@ -958,6 +1102,10 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/pathe@1.1.2:
resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
dev: true
/perfect-debounce@1.0.0: /perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
dev: true dev: true
@ -966,6 +1114,11 @@ packages:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
dev: true dev: true
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
dev: true
/postcss@8.4.41: /postcss@8.4.41:
resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==} resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
@ -979,6 +1132,15 @@ packages:
resolution: {integrity: sha512-kKYfePf9rzKnxOAKDpsWhg/ysrHPqT+yQ7UW4JjdnqjFIeNUnNcEJvhuA8fDenxAGWzUqtd51DfVg7xp/8T9NA==} resolution: {integrity: sha512-kKYfePf9rzKnxOAKDpsWhg/ysrHPqT+yQ7UW4JjdnqjFIeNUnNcEJvhuA8fDenxAGWzUqtd51DfVg7xp/8T9NA==}
dev: true dev: true
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: true
/rfdc@1.4.1: /rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
dev: true dev: true
@ -1009,10 +1171,24 @@ packages:
fsevents: 2.3.3 fsevents: 2.3.3
dev: true dev: true
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
dev: true
/search-insights@2.17.0: /search-insights@2.17.0:
resolution: {integrity: sha512-AskayU3QNsXQzSL6v4LTYST7NNfs2HWyHHB+sdORP9chsytAhro5XRfToAMI/LAVYgNbzowVZTMfBRodgbUHKg==} resolution: {integrity: sha512-AskayU3QNsXQzSL6v4LTYST7NNfs2HWyHHB+sdORP9chsytAhro5XRfToAMI/LAVYgNbzowVZTMfBRodgbUHKg==}
dev: true dev: true
/section-matter@1.0.0:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
engines: {node: '>=4'}
dependencies:
extend-shallow: 2.0.1
kind-of: 6.0.3
dev: true
/shiki@1.14.1: /shiki@1.14.1:
resolution: {integrity: sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==} resolution: {integrity: sha512-FujAN40NEejeXdzPt+3sZ3F2dx1U24BY2XTY01+MG8mbxCiA2XukXdcbyMyLAHJ/1AUUnQd1tZlvIjefWWEJeA==}
dependencies: dependencies:
@ -1030,6 +1206,15 @@ packages:
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: true dev: true
/sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
dev: true
/strip-bom-string@1.0.0:
resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
engines: {node: '>=0.10.0'}
dev: true
/superjson@2.2.1: /superjson@2.2.1:
resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==}
engines: {node: '>=16'} engines: {node: '>=16'}
@ -1046,6 +1231,13 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true dev: true
/to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
dependencies:
is-number: 7.0.0
dev: true
/vite@5.4.2: /vite@5.4.2:
resolution: {integrity: sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==} resolution: {integrity: sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
@ -1084,6 +1276,21 @@ packages:
fsevents: 2.3.3 fsevents: 2.3.3
dev: true dev: true
/vitepress-auto-sidebar-plugin@0.2.4(vite@5.4.2)(vitepress@1.3.4):
resolution: {integrity: sha512-s2EcnBAi6zTDKSODTKl1dtmq/0Wl/WSVT0QWS4/6Q8j2+LIL9s4tV6swVhffrGii/zQGouIlMyQflqDFGGZJIw==}
peerDependencies:
vite: ^5.2.9
vitepress: ^1.1.0
dependencies:
consola: 3.2.3
fast-glob: 3.3.2
gray-matter: 4.0.3
pathe: 1.1.2
perfect-debounce: 1.0.0
vite: 5.4.2
vitepress: 1.3.4(@algolia/client-search@5.1.1)(search-insights@2.17.0)
dev: true
/vitepress@1.3.4(@algolia/client-search@5.1.1)(search-insights@2.17.0): /vitepress@1.3.4(@algolia/client-search@5.1.1)(search-insights@2.17.0):
resolution: {integrity: sha512-I1/F6OW1xl3kW4PaIMC6snxjWgf3qfziq2aqsDoFc/Gt41WbcRv++z8zjw8qGRIJ+I4bUW7ZcKFDHHN/jkH9DQ==} resolution: {integrity: sha512-I1/F6OW1xl3kW4PaIMC6snxjWgf3qfziq2aqsDoFc/Gt41WbcRv++z8zjw8qGRIJ+I4bUW7ZcKFDHHN/jkH9DQ==}
hasBin: true hasBin: true

View File

@ -0,0 +1,10 @@
# -*- 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
"""

View File

@ -0,0 +1,46 @@
# -*- 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 liteyuki_autodoc.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()

View File

@ -0,0 +1,10 @@
# -*- 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
"""

View File

@ -0,0 +1,150 @@
# -*- 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 liteyuki_autodoc.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
if is_classmethod:
PREFIX = " -"
ret = ""
ret += self.desc + "\n\n"
if self.args:
ret += PREFIX + f"{get_text(lang, 'docstring.args')}:\n\n"
for arg in self.args:
ret += PREFIX + f"{arg.name}: {arg.type} {arg.desc}\n\n"
if self.attrs:
ret += PREFIX + f"{get_text(lang, 'docstring.attrs')}:\n\n"
for attr in self.attrs:
ret += PREFIX + f"{attr.name}: {attr.type} {attr.desc}\n\n"
if self.return_:
ret += PREFIX + f"{get_text(lang, 'docstring.return')}:\n\n"
ret += PREFIX + f"{self.return_.desc}\n\n"
if self.raise_:
ret += PREFIX + f"{get_text(lang, 'docstring.raises')}:\n\n"
for exception in self.raise_:
ret += PREFIX + f"{exception.name} {exception.desc}\n\n"
if self.example:
ret += PREFIX + f"{get_text(lang, 'docstring.example')}:\n\n"
for example in self.example:
ret += PREFIX + f"{example.desc}\n Input: {example.input}\n Output: {example.output}\n\n"
return ret
def __str__(self):
return self.desc

View File

@ -0,0 +1,178 @@
"""
Google docstring parser for Python.
"""
from typing import Optional
from liteyuki_autodoc.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 match_token(self) -> Optional[str]:
for token in self._tokens:
if self.lines[self.lineno][self.char:].startswith(token):
self.char += len(token)
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:
"""
while self.lineno + 1 < len(self.lines):
line = self.lines[self.lineno + 1]
if line.startswith(" " * self.indent):
line = line[self.indent:]
else:
return None
if not line:
return None
self.lineno += 1
return line
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}")

123
liteyuki_autodoc/i18n.py Normal file
View File

@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
"""
Internationalization module.
"""
from typing import Optional, TypeAlias
NestedDict: TypeAlias = dict[str, 'str | NestedDict']
i18n_dict: dict[str, NestedDict] = {
"en" : {
"docstring": {
"args" : "Args",
"return" : "Return",
"attribute": "Attribute",
"raises" : "Raises",
"example" : "Examples",
"yields" : "Yields",
},
"src": "Source code",
},
"zh-Hans": {
"docstring": {
"args" : "参数",
"return" : "返回",
"attribute": "属性",
"raises" : "引发",
"example" : "示例",
"yields" : "产出",
},
"src": "源码",
},
"zh-Hant": {
"docstring": {
"args" : "參數",
"return" : "返回",
"attribute": "屬性",
"raises" : "引發",
"example" : "示例",
"yields" : "產出",
},
"src": "源碼",
},
"ja" : {
"docstring": {
"args" : "引数",
"return" : "戻り値",
"attribute": "属性",
"raises" : "例外",
"example" : "",
"yields" : "生成",
},
"src": "ソースコード",
},
}
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

107
liteyuki_autodoc/output.py Normal file
View File

@ -0,0 +1,107 @@
# -*- 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 liteyuki_autodoc.style.markdown import generate
from liteyuki_autodoc.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)

View File

@ -0,0 +1,10 @@
# -*- 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
"""

View File

@ -0,0 +1,61 @@
# -*- 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 liteyuki_autodoc.syntax.astparser import AstParser
from liteyuki_autodoc.syntax.node import *
from liteyuki_autodoc.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
"""
print(parser.variables)
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 var in parser.variables:
if var.type == TypeHint.NO_TYPEHINT:
md += f"### ***var*** `{var.name} = {var.value}`\n\n"
else:
md += f"### ***var*** `{var.name}: {var.type} = {var.value}`\n\n"
for func in parser.functions:
md += func.markdown(lang)
for cls in parser.classes:
md += f"### ***class*** `{cls.name}`\n\n"
for mtd in cls.methods:
md += mtd.markdown(lang, 2, True)
for attr in cls.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

View File

@ -0,0 +1,198 @@
# -*- 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
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()
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=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=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=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_=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()
))
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=ast.unparse(arg.annotation).strip() if arg.annotation else TypeHint.NO_TYPEHINT,
)
for arg in node.args.posonlyargs
],
args=[
ArgNode(
name=arg.arg,
type=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=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_=ast.unparse(node.returns).strip() if node.returns else TypeHint.NO_TYPEHINT,
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_variable(node):
# print("变量不在模块级别", ast.unparse(node))
continue
else:
print("变量在模块级别", ast.unparse(node))
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
))
elif 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()
))
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):
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

View File

@ -0,0 +1,258 @@
# -*- 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 liteyuki_autodoc.docstring.docstring import Docstring
from liteyuki_autodoc.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
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 = Field(TypeHint.NO_RETURN, alias="return")
decorators: list[str] = []
src: str
is_async: bool = False
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, is_classmethod: bool = False) -> str:
"""
Args:
indent: int
The number of spaces to indent the markdown.
is_classmethod: bool
lang: str
The language of the
Returns:
markdown style document
"""
self.complete_default_args()
PREFIX = "" * indent
if is_classmethod:
PREFIX = "- #"
md = ""
# 装饰器部分
if len(self.decorators) > 0:
for decorator in self.decorators:
md += PREFIX + f"### `@{decorator}`\n"
if self.is_async:
md += PREFIX + "### *async def* "
else:
md += PREFIX + "### *def* "
md += f"`{self.name}(" # 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)
md += ", ".join(args) + ")"
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>{get_text(lang, 'src')}</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.
inherit: list["ClassNode"] = []
The classes that the class inherits from
"""
name: str
docs: Optional[Docstring] = None
attrs: list[AttrNode] = []
methods: list[FunctionNode] = []
inherit: list["ClassNode"] = []

10
make_docs.py Normal file
View File

@ -0,0 +1,10 @@
# -*- 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
"""

View File

@ -15,7 +15,11 @@ from .const import PI # type: ignore
from .utils import approx from .utils import approx
class AnyAngle: class Angle:
...
class AnyAngle(Angle):
def __init__(self, value: float, is_radian: bool = False): def __init__(self, value: float, is_radian: bool = False):
""" """
任意角度 任意角度

View File

@ -18,9 +18,10 @@ class CurveEquation:
def __init__(self, x_func: OneVarFunc, y_func: OneVarFunc, z_func: OneVarFunc): def __init__(self, x_func: OneVarFunc, y_func: OneVarFunc, z_func: OneVarFunc):
""" """
曲线方程 曲线方程
:param x_func: Args:
:param y_func: x_func: x函数
:param z_func: y_func: y函数
z_func: z函数
""" """
self.x_func = x_func self.x_func = x_func
self.y_func = y_func self.y_func = y_func
@ -31,7 +32,7 @@ class CurveEquation:
计算曲线上的点 计算曲线上的点
Args: Args:
*t: *t:
参数
Returns: Returns:
""" """

View File

@ -32,12 +32,11 @@ class Plane3:
self.c = c self.c = c
self.d = d self.d = d
def approx(self, other: 'Plane3', epsilon: float = APPROX) -> bool: def approx(self, other: 'Plane3') -> bool:
""" """
判断两个平面是否近似相等 判断两个平面是否近似相等
Args: Args:
other: other:
epsilon:
Returns: Returns:
是否近似相等 是否近似相等

View File

@ -62,15 +62,15 @@ class Point3:
""" """
return approx(self.x, other.x) and approx(self.y, other.y) and approx(self.z, other.z) return approx(self.x, other.x) and approx(self.y, other.y) and approx(self.z, other.z)
def __sub__(self, other: "Point3") -> "Vector3": # def __sub__(self, other: "Point3") -> "Vector3":
""" # """
P - P -> V # P - P -> V
#
P - V -> P 已在 :class:`Vector3` 中实现 # P - V -> P 已在 :class:`Vector3` 中实现
Args: # Args:
other: # other:
Returns: # Returns:
#
""" # """
from .vector import Vector3 # from .vector import Vector3
return Vector3(self.x - other.x, self.y - other.y, self.z - other.z) # return Vector3(self.x - other.x, self.y - other.y, self.z - other.z)

View File

@ -323,19 +323,13 @@ def generate_docs(module_folder: str, output_dir: str, with_top: bool = False, l
# 生成markdown # 生成markdown
if "README" in abs_md_path: if "index" in abs_md_path:
front_matter = { front_matter = {
"title" : module_info.module_path.replace(".__init__", "").replace("_", "\\n"), "title" : module_info.module_path.replace(".__init__", ""),
"index" : "true",
"icon" : "laptop-code",
"category": "API"
} }
else: else:
front_matter = { front_matter = {
"title" : module_info.module_path.replace("_", "\\n"), "title" : module_info.module_path
"order" : "1",
"icon" : "laptop-code",
"category": "API"
} }
md_content = generate_markdown(module_info, front_matter) md_content = generate_markdown(module_info, front_matter)