svg correction

This commit is contained in:
2026-05-09 22:24:30 +02:00
parent 490487a1bd
commit 89d6415ff4
8 changed files with 76 additions and 26 deletions

View File

@@ -179,6 +179,14 @@ def shape_box(node: ET.Element, ox: float, oy: float) -> Box | None:
return None
def panel_box_from_rect(node: ET.Element, ox: float, oy: float) -> Box | None:
if local_name(node.tag) != "rect" or not class_names(node).intersection({"panel", "soft", "card", "white"}):
return None
x = ox + parse_number(node.attrib.get("x"))
y = oy + parse_number(node.attrib.get("y"))
return Box("panel", "panel", x, y, x + parse_number(node.attrib.get("width")), y + parse_number(node.attrib.get("height")))
def collect_layout_boxes(
node: ET.Element,
styles: dict[str, dict[str, str]],
@@ -228,6 +236,45 @@ def validate_layout_collisions(path: Path, root: ET.Element, styles: dict[str, d
return issues
def validate_panel_containment(
path: Path,
node: ET.Element,
styles: dict[str, dict[str, str]],
ox: float = 0.0,
oy: float = 0.0,
) -> list[Issue]:
issues: list[Issue] = []
tx, ty = parse_translate(node.attrib.get("transform"))
ox += tx
oy += ty
if local_name(node.tag) == "g":
panel = next((panel_box_from_rect(child, ox, oy) for child in node if panel_box_from_rect(child, ox, oy)), None)
if panel:
safe = Box("panel", panel.label, panel.x1, panel.y1, panel.x2, panel.y2)
for box in collect_layout_boxes(node, styles, ox - tx, oy - ty):
if box.kind == "shape" and box.label == "line":
continue
tolerance = 0.0 if box.kind == "fraction" else 70.0
if (
box.x1 < safe.x1 - tolerance
or box.y1 < safe.y1 - tolerance
or box.x2 > safe.x2 + tolerance
or box.y2 > safe.y2 + tolerance
):
issues.append(
Issue(
"error",
path,
f"Element hors panneau: {box.kind} {box.label!r} depasse la zone utile du panneau.",
)
)
for child in node:
issues.extend(validate_panel_containment(path, child, styles, ox, oy))
return issues
def validate_fraction_group(path: Path, group: ET.Element, styles: dict[str, dict[str, str]]) -> list[Issue]:
issues: list[Issue] = []
texts = [node for node in group if local_name(node.tag) == "text"]
@@ -257,7 +304,9 @@ def validate_fraction_group(path: Path, group: ET.Element, styles: dict[str, dic
num_size = font_size(numerator, styles)
den_size = font_size(denominator, styles)
min_top_gap = max(8.0, num_size * 0.30)
# La baseline du numérateur est volontairement plus proche du trait que celle
# du dénominateur : c'est ce qui équilibre l'espace visible autour de la barre.
min_top_gap = max(8.0, num_size * 0.24)
min_bottom_gap = max(8.0, den_size * 0.30)
if bar_y - num_y < min_top_gap:
@@ -314,6 +363,7 @@ def validate_svg(path: Path) -> list[Issue]:
styles = parse_styles(root)
issues.extend(validate_layout_collisions(path, root, styles))
issues.extend(validate_panel_containment(path, root, styles))
for node in root.iter():
if local_name(node.tag) == "text":