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