List Layers
false
false
true
list_layers
tools_menu.end
ruby
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# DESCRIPTION: List all layers under a ruler
#
# Run the script with
# klayout -rm list_layers.lym ...
# or put the script as "list_layers.lym" into the installation path (on Unix for version <=0.21:
# set $KLAYOUTPATH to the installation folder).
#
# This script will install a new entry in the "Tools" menu called "List Layers". Before this
# function can be used, a single ruler must be drawn. The script looks for
# shapes that are crossed by this ruler and reports the layers of those shapes. The script can operate
# on multiple layouts as well.
#
require 'stringio'
# locate the layout and the (single) ruler
app = RBA::Application.instance
view = app.main_window.current_view
if !view
raise "No view open for creating the cross section from"
end
# fetch the ruler
ruler = nil
nrulers = 0
view.each_annotation do |a|
# Use only rulers with "plain line" or ruler style
if a.style == RBA::Annotation::style_line || a.style == RBA::Annotation::style_ruler
ruler = a
nrulers += 1
end
end
if nrulers == 0
raise "No ruler present (these must have 'plain line' or 'ruler' style)"
end
if nrulers > 1
raise "More than one ruler present (with 'plain line' or 'ruler' style)"
end
cv = view.cellview(view.active_cellview_index)
if ! cv.is_valid?
raise "The selected layout is not valid"
end
# get all layers from the layer list
layers = []
layer_titles = []
cellviews = []
layout_indices = []
i = view.begin_layers
while !i.at_end?
lyi = i.current.source_cellview(true)
if lyi >= 0 && lyi < view.cellviews
layout = view.cellview(lyi).layout
if layout.is_valid_layer?(i.current.layer_index)
layout_indices.push(lyi)
cellviews.push(view.cellview(lyi))
layers.push(i.current.layer_index)
d = i.current.name
if d == ""
d = i.current.source(true).sub(/@\d+$/, "")
end
layer_titles.push(d)
end
end
i.next
end
founds = {}
layers.each_with_index do |layer_index,i|
cv = cellviews[i]
layout = cv.layout
cell = cv.cell_index
dbu = layout.dbu
# get the start and end points in database units and micron
p1_dbu = RBA::Point::from_dpoint(ruler.p1 * (1.0 / dbu))
p2_dbu = RBA::Point::from_dpoint(ruler.p2 * (1.0 / dbu))
line_dbu = RBA::Edge.new(p1_dbu, p2_dbu)
# detect all touching shapes and all edges of those which cross the measurement line
shape_iter = layout.begin_shapes_touching(cell, layer_index, line_dbu.bbox)
while !shape_iter.at_end
found = false
shape = shape_iter.shape
if shape.is_polygon? || shape.is_path? || shape.is_box?
polygon = shape.polygon.transformed_cplx(shape_iter.itrans)
polygon.each_edge do |edge_dbu|
if line_dbu.crossed_by?(edge_dbu) && (line_dbu.side_of(edge_dbu.p1) > 0 || line_dbu.side_of(edge_dbu.p2) > 0)
layout_index = layout_indices[i]
founds[layout_index] ||= {}
founds[layout_index][layer_index] = i
found = true
break
end
end
end
shape_iter.next
if found
break
end
end
end
# produce the output
output = StringIO.new("", "w")
output.write "<html><body>"
output.write "<h2>Layer report</h2>"
x1 = (0.5 + ruler.p1.x * 1e5).floor * 1e-5
y1 = (0.5 + ruler.p1.y * 1e5).floor * 1e-5
x2 = (0.5 + ruler.p2.x * 1e5).floor * 1e-5
y2 = (0.5 + ruler.p2.y * 1e5).floor * 1e-5
output.write "<p>Position #{x1},#{y1} to #{x2},#{y2}</p>"
founds.each do |lyi,f|
output.write "<h4>Layout #{view.cellview(lyi).name} (@#{lyi+1})</h4>"
ii = []
f.each do |li,i|
ii.push(i)
end
ii.sort.each do |i|
output.write "Layer #{layer_titles[i]}<br/>"
end
end
output.write "</body></html>"
bs = RBA::BrowserSource::new_html(output.string)
bd = RBA::BrowserDialog::new
bd.set_source(bs)
bd.set_home("int:index.html")
bd.exec