docs: 将仓库代码注释统一为中文
CI / docs-check (push) Canceled after 0s
CI / backend-test (push) Canceled after 0s
CI / service-test (push) Canceled after 0s
CI / frontend-test (push) Canceled after 0s
CI / rust-core (push) Canceled after 0s
CI / docs-check (pull_request) Canceled after 0s
CI / backend-test (pull_request) Canceled after 0s
CI / service-test (pull_request) Canceled after 0s
CI / frontend-test (pull_request) Canceled after 0s
CI / rust-core (pull_request) Canceled after 0s
CI / docs-check (push) Canceled after 0s
CI / backend-test (push) Canceled after 0s
CI / service-test (push) Canceled after 0s
CI / frontend-test (push) Canceled after 0s
CI / rust-core (push) Canceled after 0s
CI / docs-check (pull_request) Canceled after 0s
CI / backend-test (pull_request) Canceled after 0s
CI / service-test (pull_request) Canceled after 0s
CI / frontend-test (pull_request) Canceled after 0s
CI / rust-core (pull_request) Canceled after 0s
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""Safe AST-to-LaTeX conversion and vector math layout for plot labels."""
|
||||
"""安全的 AST 到 LaTeX 转换和绘图标签的矢量数学布局。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -66,7 +66,7 @@ def _latex(node: ast.AST, parent_precedence: int = 0) -> str:
|
||||
|
||||
|
||||
def expression_latex(expression: str) -> str:
|
||||
"""Convert one already-supported function expression to MathText-compatible LaTeX."""
|
||||
"""将一个已支持的函数表达式转换为 MathText 兼容的 LaTeX。"""
|
||||
return "y = " + _latex(parse_expression(expression).body)
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ def _offset(values: tuple[float, ...], x: float, y: float) -> tuple[float, ...]:
|
||||
|
||||
@lru_cache(maxsize=256)
|
||||
def math_layout(latex: str, size: float = 12.0) -> MathLayout:
|
||||
"""Lay out LaTeX as reusable vector paths; calls are cached and serialized for FT2Font."""
|
||||
"""将 LaTeX 布局为可重用的矢量路径; FT2Font 的调用被缓存和序列化。"""
|
||||
with _MATH_LOCK:
|
||||
parsed = _MATH_PARSER.parse(f"${latex}$", dpi=72, prop=FontProperties(size=size))
|
||||
paths: list[VectorPath] = []
|
||||
@@ -125,7 +125,7 @@ def _svg_path(path: VectorPath) -> str:
|
||||
|
||||
|
||||
def render_math_svg(latex: str, *, x: float, top: float, class_name: str, color: str) -> str:
|
||||
"""Return a script-free SVG group containing MathText vector glyphs."""
|
||||
"""返回包含 MathText 矢量字形的无脚本 SVG 组。"""
|
||||
layout = math_layout(latex)
|
||||
baseline = top + layout.height - layout.depth
|
||||
accessible = html.escape(latex, quote=True)
|
||||
@@ -145,7 +145,7 @@ def render_math_svg(latex: str, *, x: float, top: float, class_name: str, color:
|
||||
|
||||
|
||||
def render_math_reportlab(latex: str, *, x: float, visual_top: float, color: object):
|
||||
"""Return a reportlab Group containing the same LaTeX glyph geometry as the SVG."""
|
||||
"""返回包含与 SVG 相同的 LaTeX 字形几何形状的 reportlab 组。"""
|
||||
from reportlab.graphics.shapes import Group, Path, Rect
|
||||
|
||||
layout = math_layout(latex)
|
||||
@@ -181,7 +181,7 @@ def render_math_reportlab(latex: str, *, x: float, visual_top: float, color: obj
|
||||
|
||||
@lru_cache(maxsize=256)
|
||||
def render_math_mask(latex: str, size: float = 12.0, dpi: float = 144.0) -> tuple[int, int, bytes]:
|
||||
"""Rasterize LaTeX to an 8-bit alpha mask for DOCX/PNG export."""
|
||||
"""将 LaTeX 光栅化为 8 位 alpha 掩码以用于 DOCX/PNG 导出。"""
|
||||
with _MATH_LOCK:
|
||||
parsed = _RASTER_PARSER.parse(f"${latex}$", dpi=dpi, prop=FontProperties(size=size))
|
||||
image = parsed.image
|
||||
|
||||
@@ -226,13 +226,7 @@ _CURVE_MAX_REFINEMENT_EVALUATIONS = 8192
|
||||
|
||||
|
||||
def _refine_crossing(tree, left, right, ymin, ymax, budget=None):
|
||||
"""Adaptively check both halves of a crossing; None explicitly breaks a path.
|
||||
|
||||
A visible midpoint is not a continuity proof. Accept a visible chord only
|
||||
when its midpoint error is within a quarter pixel; otherwise subdivide both
|
||||
halves. Depth, evaluation and floating-point limits always break unresolved
|
||||
intervals instead of joining them. Entirely off-screen triples can be culled.
|
||||
"""
|
||||
"""自适应检查路口的两半; None 明确中断了一条路径。可见的中点并不是连续性证明。仅当中点误差在四分之一像素以内时才接受可见弦;否则将两半细分。深度、求值和浮点限制总是打破未解决的间隔,而不是连接它们。完全不在屏幕外的三元组可以被剔除。"""
|
||||
remaining = _REFINE_MAX_EVALUATIONS
|
||||
if budget is None:
|
||||
budget = [_REFINE_MAX_EVALUATIONS]
|
||||
@@ -255,12 +249,11 @@ def _refine_crossing(tree, left, right, ymin, ymax, budget=None):
|
||||
values = (a[1], y, b[1])
|
||||
if all(math.isfinite(v) for v in values):
|
||||
if max(values) < ymin or min(values) > ymax:
|
||||
return [a, None, b] # No visible chord; do not connect across it.
|
||||
return [a, None, b] # 无可见和弦;不要通过它连接。
|
||||
error = abs(y - (a[1] / 2 + b[1] / 2))
|
||||
if any(ymin <= v <= ymax for v in values) and error <= tolerance:
|
||||
return [a, mid, b]
|
||||
# Refine either side of a nonfinite midpoint too: dropping the whole
|
||||
# interval would erase valid branches between the original samples.
|
||||
# 也优化非有限中点的任一侧:删除整个间隔将擦除原始样本之间的有效分支。
|
||||
first = refine(a, mid, depth + 1)
|
||||
second = refine(mid, b, depth + 1)
|
||||
return first + second[1:]
|
||||
@@ -309,7 +302,7 @@ def _sample_segments(
|
||||
continue
|
||||
if prev_y is not None:
|
||||
refined = _refine_crossing(tree, (prev_x, prev_y), (x, y), ymin, ymax, budget)
|
||||
samples = refined[1:] # The previous endpoint is already in points.
|
||||
samples = refined[1:] # 前一个端点已经以点为单位。
|
||||
else:
|
||||
samples = [(x, y)]
|
||||
for sample in samples:
|
||||
|
||||
Reference in New Issue
Block a user