Render a ShapeItem to SVG with full style support.
(parent, item)
| 559 | |
| 560 | |
| 561 | def _shape(parent, item) -> None: |
| 562 | """Render a ShapeItem to SVG with full style support.""" |
| 563 | import math |
| 564 | ox, oy = item.pos().x(), item.pos().y() |
| 565 | pts = [(ox + p.x(), oy + p.y()) for p in item.rel_points] |
| 566 | lw = item.line_width |
| 567 | fill = item.fill_color if item.fill_style == "solid" else "none" |
| 568 | |
| 569 | stroke_attrs = { |
| 570 | "stroke": item.stroke_color, |
| 571 | "stroke-width": f"{lw:.2f}", |
| 572 | "fill": fill, |
| 573 | "stroke-linecap": "round", |
| 574 | "stroke-linejoin": "round", |
| 575 | } |
| 576 | da = _DASH_ARRAY.get(item.line_style) |
| 577 | if da: |
| 578 | stroke_attrs["stroke-dasharray"] = da |
| 579 | |
| 580 | if item.kind == "line" and len(pts) >= 2: |
| 581 | el = ET.SubElement(parent, f"{{{_SVG_NS}}}polyline") |
| 582 | el.set("points", " ".join(f"{x:.2f},{y:.2f}" for x, y in pts)) |
| 583 | for k, v in stroke_attrs.items(): |
| 584 | el.set(k, v) |
| 585 | # line ends drawn as separate open geometry (no SVG markers needed) |
| 586 | _svg_line_end(parent, pts[1], pts[0], item.line_end_start, lw, item.stroke_color) |
| 587 | _svg_line_end(parent, pts[-2], pts[-1], item.line_end_end, lw, item.stroke_color) |
| 588 | |
| 589 | elif item.kind == "rect" and len(pts) == 2: |
| 590 | x0 = min(pts[0][0], pts[1][0]); y0 = min(pts[0][1], pts[1][1]) |
| 591 | w = abs(pts[1][0] - pts[0][0]); h = abs(pts[1][1] - pts[0][1]) |
| 592 | el = ET.SubElement(parent, f"{{{_SVG_NS}}}rect") |
| 593 | el.set("x", f"{x0:.2f}"); el.set("y", f"{y0:.2f}") |
| 594 | el.set("width", f"{w:.2f}"); el.set("height", f"{h:.2f}") |
| 595 | for k, v in stroke_attrs.items(): |
| 596 | el.set(k, v) |
| 597 | |
| 598 | elif item.kind == "circle" and len(pts) == 2: |
| 599 | cx, cy = pts[0] |
| 600 | r = math.hypot(pts[1][0] - cx, pts[1][1] - cy) |
| 601 | el = ET.SubElement(parent, f"{{{_SVG_NS}}}circle") |
| 602 | el.set("cx", f"{cx:.2f}"); el.set("cy", f"{cy:.2f}") |
| 603 | el.set("r", f"{r:.2f}") |
| 604 | for k, v in stroke_attrs.items(): |
| 605 | el.set(k, v) |
| 606 | |
| 607 | |
| 608 | def _svg_line_end(parent, p_from, p_to, style: str, lw: float, color: str) -> None: |
no test coverage detected