diff --git a/CHANGELOG.md b/CHANGELOG.md index 20fcd254..66c9b7b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format of this changelog is based on - Fixed incorrect conversion and reflection of split BSplines - Added FAQ entry about MeshSized/OptionalEntity styling on Paths + - Fixed issue causing duplicate `Cell` names with paths and composite components, where rendering would use the component's name rather than a unique name ## 1.4.2 (2025-07-16) diff --git a/src/paths/paths.jl b/src/paths/paths.jl index 661a3b94..a33a78b8 100644 --- a/src/paths/paths.jl +++ b/src/paths/paths.jl @@ -394,6 +394,14 @@ function DeviceLayout._geometry!(cs::CoordinateSystem, p::Path) return addref!(cs, p) end +function DeviceLayout.coordsys_name(p::Path) + # If empty, rendering path directly + isempty(p._geometry) && return name(p._geometry) + # If not empty, p._geometry holds `p` (e.g. `build!` was called) + # and the path coordsys needs its own uniquename + return uniquename(name(p)) +end + """ path_in(h::PointHook) diff --git a/src/render/render.jl b/src/render/render.jl index 5355d678..dea366de 100644 --- a/src/render/render.jl +++ b/src/render/render.jl @@ -96,7 +96,7 @@ function _render!( cur_cell = if already_seen memoized_cells[cur_cs] else - Cell{S}(name(cur_cs)) + Cell{S}(coordsys_name(cur_cs)) end # If it's a new CS, render the contents, push refs to the stack, and add to memoized_cells diff --git a/src/schematics/components/builtin_components.jl b/src/schematics/components/builtin_components.jl index e7093b1f..45b966ad 100644 --- a/src/schematics/components/builtin_components.jl +++ b/src/schematics/components/builtin_components.jl @@ -173,8 +173,11 @@ struct BasicComponent{T} <: AbstractComponent{T} name::String geometry::CoordinateSystem{T} hooks - BasicComponent(cs::CoordinateSystem{T}, hooks=compass()) where {T} = - new{T}(name(cs), cs, hooks) + function BasicComponent(cs::CoordinateSystem{T}, hooks=compass()) where {T} + newcs = copy(cs) + newcs.name = uniquename(name(cs)) + return new{T}(name(cs), newcs, hooks) + end end hooks(c::BasicComponent) = c.hooks geometry(c::BasicComponent) = c.geometry @@ -220,14 +223,13 @@ struct BasicCompositeComponent{T} <: AbstractCompositeComponent{T} function BasicCompositeComponent(g::SchematicGraph; coordtype=typeof(1.0UPREFERRED)) newg = SchematicGraph(name(g)) add_graph!(newg, g; id_prefix="") - return new{coordtype}( - newg, - Schematic{coordtype}(newg; log_dir=nothing), - Dict{Symbol, Union{Hook, Vector{<:Hook}}}() - ) + sch = Schematic{coordtype}(newg; log_dir=nothing) + sch.coordinate_system.name = uniquename(name(g)) + return new{coordtype}(newg, sch, Dict{Symbol, Union{Hook, Vector{<:Hook}}}()) end end name(c::BasicCompositeComponent) = c.graph.name +coordsys_name(c::BasicCompositeComponent) = c._schematic.coordinate_system.name function (cc::BasicCompositeComponent)( compname::String=name(cc), diff --git a/src/schematics/components/components.jl b/src/schematics/components/components.jl index 95079eed..35f8aaac 100644 --- a/src/schematics/components/components.jl +++ b/src/schematics/components/components.jl @@ -414,3 +414,5 @@ function single_component_expr(compname, comptype; params...) $escname end end + +DeviceLayout.coordsys_name(comp::AbstractComponent) = name(geometry(comp)) diff --git a/src/schematics/components/composite_components.jl b/src/schematics/components/composite_components.jl index b52f287b..822f8e72 100644 --- a/src/schematics/components/composite_components.jl +++ b/src/schematics/components/composite_components.jl @@ -106,7 +106,7 @@ function schematic(cc::AbstractCompositeComponent) floorplan = plan( graph(cc); log_dir=nothing, - id_prefix=name(graph(cc)) * COMPOSITE_NODE_ID_SEPARATOR + id_prefix=cc._schematic.coordinate_system.name * COMPOSITE_NODE_ID_SEPARATOR ) append_coordsys!(cc._schematic.coordinate_system, floorplan.coordinate_system) for (k, v) in pairs(floorplan.ref_dict) diff --git a/src/structures.jl b/src/structures.jl index 0ede9d14..a180668e 100644 --- a/src/structures.jl +++ b/src/structures.jl @@ -216,5 +216,7 @@ function flatten end # type of coordinate system created by flatten function coordsys_type end # defined elsewhere, once CoordinateSystem is defined +# name used by CoordinateSystem representation +coordsys_name(geom::GeometryStructure) = name(geom) Base.isempty(geom::GeometryStructure) = isempty(elements(geom)) && isempty(refs(geom)) diff --git a/test/test_schematicdriven.jl b/test/test_schematicdriven.jl index 89ae00b7..cdfc48ee 100644 --- a/test/test_schematicdriven.jl +++ b/test/test_schematicdriven.jl @@ -617,10 +617,12 @@ end g3 = copy(g) @test length(find_components(TestCompVariant, g3)) == 18 @test length(find_components(TestCompVariant, g3, depth=2)) == 12 - @test length(find_components(c -> name(c)[1:1] == "z", g3, depth=2)) == 4 + # There are two unique components named "z" appearing a combined 4 times up to depth 2 + @test length(find_components(c -> name(c) == "z", g3, depth=2)) == 4 @test length( - unique(component.(g3[find_components(c -> name(c)[1:1] == "z", g3, depth=2)])) + unique(component.(g3[find_components(c -> name(c) == "z", g3, depth=2)])) ) == 2 + g3_flat = SchematicDrivenLayout.flatten(g3) g3 = SchematicDrivenLayout.flatten(g3, depth=1) @test length(components(g3)) == 14 @@ -633,6 +635,11 @@ end @test origin(floorplan3, find_components(c -> name(c)[1:1] == "z", g3)[end]) ≈ Point(200.2μm, 0.1μm) + # Make sure that cells for unique "z" have unique names when rendering + c = Cell(floorplan3.coordinate_system) + a = [] + traverse!(a, c) + @test length(findall(x -> name(last(x)) == DeviceLayout.coordsys_name(zline), a)) == 2 ### Full composite component p = Path(Point(0μm, 0μm), name="pz") @@ -691,6 +698,12 @@ end @test hooks(bq2, "bq1", :xy) == hooks(bq2, 1 => :xy) # using subcomp name or index=>hsym @test keys(SchematicDrivenLayout.subcomponents(bq2)) == (:bq1, :bq2, :pz) + # test creating Cell without build uses path's coordsys_name + c = Cell(geometry(bq2); map_meta=_ -> GDSMeta()) + a = [] + traverse!(a, c) + @test DeviceLayout.coordsys_name(p) != name(p) + @test isempty(findall(x -> name(last(x)) == name(p), a)) g = SchematicGraph("comp") bq2_node = add_node!(g, bq2) @@ -745,6 +758,24 @@ end c = Cell("test_no_duplicate_names", nm) render!(c, floorplan.coordinate_system; map_meta=m -> GDSMeta()) @test_nowarn save(joinpath(tdir, "test_duplicates.gds"), c) + + ## Composite component having multiple instances of a subcomponent + ## that is also a composite component with a named component in it + pa = Path(; name="path") + g = SchematicGraph("pathgraph") + add_node!(g, pa) + sub_cc = BasicCompositeComponent(g) + pa = Path(; name="path") + g = SchematicGraph("pathgraph") + add_node!(g, pa) + sub_cc2 = BasicCompositeComponent(g) + g2 = SchematicGraph("supergraph") + add_node!(g2, sub_cc) + add_node!(g2, sub_cc2) + super_cc = BasicCompositeComponent(g2) + c = Cell("test_no_duplicate_names", nm) + render!(c, super_cc; map_meta=m -> GDSMeta()) + @test_nowarn save(joinpath(tdir, "test_duplicates.gds"), c) end @testset "GDSComponent" begin