# ----------------------------------------------------------------------------- # Description: Routed layout preview helpers that invoke the routing/build flow and return preview artifacts. # Inside functions: create_routed_layout_svg, layout_has_links # Developer : Qin Yue @ 2026 # Organization : OptiHK Limited # ----------------------------------------------------------------------------- import os import sys import tempfile import yaml def create_routed_layout_svg( yaml_content: str, output_path: str, pdk_root: str, project_dir: str, technology_manifest_path: str = None, prefer_full_gds: bool = False, ) -> str: """Create an SVG preview from routed GDS geometry generated by mxpic_router.""" import gdstk layout = yaml.safe_load(yaml_content) or {} cell_name = str(layout.get("name") or "layout") # mxpic_router is kept as a sibling repository, so the backend adds it to # sys.path only when the local checkout is available. router_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "mxpic_router")) if os.path.isdir(router_root) and router_root not in sys.path: sys.path.insert(0, router_root) from mxpic_router import build_project_gds os.makedirs(os.path.dirname(output_path), exist_ok=True) # Build into a temporary GDS first, then convert the generated top cell into # the SVG preview consumed by the canvas. with tempfile.TemporaryDirectory(prefix="mxpic_routed_preview_") as temp_dir: temp_gds = os.path.join(temp_dir, f"{cell_name}.gds") build_project_gds( project_dir=project_dir, output_path=temp_gds, pdk_root=pdk_root, technology_manifest_path=technology_manifest_path, prefer_full_gds=prefer_full_gds, target_cell_name=cell_name, ) library = gdstk.read_gds(temp_gds) top_cells = library.top_level() if not top_cells: raise RuntimeError("Routed preview GDS has no top-level cell") top_cells[0].write_svg(output_path) return output_path def layout_has_links(yaml_content: str) -> bool: """Detect whether a layout YAML document contains routed bundle links.""" layout = yaml.safe_load(yaml_content) or {} # Any bundle link means preview generation must use the routed builder # instead of simple component placement. for bundle in (layout.get("bundles") or {}).values(): links = bundle.get("links") or [] if links: return True return False