More annotation added to the program

This commit is contained in:
2026-05-30 12:44:44 +08:00
parent b3f29398f0
commit bf223b52ac
22 changed files with 729 additions and 353 deletions
+18
View File
@@ -13,6 +13,8 @@ import yaml
def create_layout_svg_from_gds(yaml_content: str, output_path: str, pdk_registry, project_dir: str = None) -> str:
"""Create an SVG preview by placing real public _BB.gds cells from layout YAML."""
layout = yaml.safe_load(yaml_content) or {}
# Try gdstk first because it can write SVG directly; keep Nazca as a GDS
# placement fallback for environments where gdstk is unavailable.
try:
return _create_with_gdstk(layout, output_path, pdk_registry, project_dir)
except ImportError as gdstk_error:
@@ -26,6 +28,7 @@ def create_layout_svg_from_gds(yaml_content: str, output_path: str, pdk_registry
def _create_with_gdstk(layout: dict, output_path: str, pdk_registry, project_dir: Optional[str]) -> str:
"""Generate preview SVG geometry using gdstk import and placement APIs."""
import gdstk
library = gdstk.Library()
@@ -37,9 +40,12 @@ def _create_with_gdstk(layout: dict, output_path: str, pdk_registry, project_dir
def _build_gdstk_cell(gdstk, library, layout: dict, pdk_registry, project_dir: Optional[str], cell_cache: Dict):
"""Build or reuse a gdstk cell for a saved layout document."""
cell_name = _safe_cell_name(layout.get("name") or "layout", library)
top = library.new_cell(cell_name)
# Each saved instance becomes a GDS reference to either another project cell
# or a resolved PDK asset.
for instance_name, instance in (layout.get("instances") or {}).items():
component = str(instance.get("component") or "")
x = _number(instance.get("x"))
@@ -54,9 +60,12 @@ def _build_gdstk_cell(gdstk, library, layout: dict, pdk_registry, project_dir: O
def _resolve_child_cell(gdstk, library, component: str, pdk_registry, project_dir: Optional[str], cell_cache: Dict):
"""Resolve a placed child component from local cells or PDK assets."""
if component in cell_cache:
return cell_cache[component]
# Project-local composite cells are resolved before external PDK components
# so nested user-created cells can appear in preview output.
local_layout = _load_local_layout(component, project_dir)
if local_layout is not None:
child = _build_gdstk_cell(gdstk, library, local_layout, pdk_registry, project_dir, cell_cache)
@@ -72,10 +81,12 @@ def _resolve_child_cell(gdstk, library, component: str, pdk_registry, project_di
def _import_gds_cell(gdstk, library, gds_path: str):
"""Import a GDS file and return the first usable cell for placement."""
source = gdstk.read_gds(gds_path)
top_cells = source.top_level()
if not top_cells:
raise ValueError(f"No top-level cell found in {gds_path}")
# Reuse already-imported cells by name to keep the preview library compact.
for source_cell in source.cells:
if _library_cell_by_name(library, source_cell.name) is None:
library.add(source_cell)
@@ -83,9 +94,12 @@ def _import_gds_cell(gdstk, library, gds_path: str):
def _create_with_nazca(layout: dict, output_path: str, pdk_registry, project_dir: Optional[str]) -> str:
"""Generate preview SVG geometry using Nazca when gdstk is unavailable."""
import nazca as nd
png_path = os.path.splitext(output_path)[0] + ".gds"
# Nazca can place the same GDS references as the preview path, but this
# backend still requires gdstk for final SVG conversion.
with nd.Cell(str(layout.get("name") or "layout")) as top:
for instance_name, instance in (layout.get("instances") or {}).items():
component = str(instance.get("component") or "")
@@ -101,6 +115,7 @@ def _create_with_nazca(layout: dict, output_path: str, pdk_registry, project_dir
def _load_local_layout(component: str, project_dir: Optional[str]) -> Optional[dict]:
"""Load a project-local composite layout referenced by another cell."""
if not project_dir or "/" in component or "\\" in component or component == "generate_with_forge":
return None
for ext in (".yml", ".yaml"):
@@ -112,6 +127,7 @@ def _load_local_layout(component: str, project_dir: Optional[str]) -> Optional[d
def _safe_cell_name(name, library) -> str:
"""Generate a backend-safe unique cell name for GDS/Nazca libraries."""
base = "".join(ch if ch.isalnum() or ch in "._$" else "_" for ch in str(name)) or "layout"
candidate = base
counter = 1
@@ -122,6 +138,7 @@ def _safe_cell_name(name, library) -> str:
def _library_cell_by_name(library, name: str):
"""Find a cell object in a loaded layout library by name."""
for cell in library.cells:
if cell.name == name:
return cell
@@ -129,6 +146,7 @@ def _library_cell_by_name(library, name: str):
def _number(value, default=0.0) -> float:
"""Convert numeric YAML values to floats with a stable default."""
try:
if value is None or value == "":
return default