Hi Matthias,
Is it possible to add a function to calculate the total area of
all selected objects(box/path/polygon)?
And when the object properties window is opened, could the area
be showed as information that it would be easily for users to
get the information?
Thank you so much~
--
chi-hsiang-hung
Comments
Hi,
currently, that functionality is not provided as a standard feature.
It is possible however, to implement such a function in ruby. Just copy the code below to a file with extension .rbm (i.e. compute_area.rbm) and copy that file into the installation directory of KLayout. It will add a new entry to the "Tools" menu which computes the area of all objects selected.
Please note, that the objects are not merged - overlapping parts are counted multiple times.
I hope, this script is helpful.
Best regards,
Matthias
I tried this script and it really fits our request,
it's a helpful code, thank you~ :)
About the overlap issue, it could be "solved" by
merge shapes first in Edit => Selection and re-calculate
the area again after merging all the shapes selected.
Best Regards,
--
chi-hsiang-hung
To estimate quickly the amount of parasitic wire capacitance, I implemented the area calculation as given below. However, with very thin wires the perimeter is contributing also a lot to the capacitance, but there seems to be no perimeter function call in the Shapes class. Do you plan to implement that (I can try to rite it myself)?
(Unix diff of the file extNetTracerDialog.cc compared to version 0.22)
1575a1576,1577
> double total_area = 0; // use area_type instead?
> double total_perimeter = 0; // use distance_type instead?
1649c1651
<
---
> double dbu_unidir = mp_nets [item_index]->dbu ();
1723a1726
> total_area += net_shape->shape.area();
1762c1765,1773
<
---
> info.start_element ("h3");
> info.cdata (tl::translate ("Statistics:"));
> info.end_element ("h3");
> info.start_element ("p");
> info.cdata (tl::sprintf (tl::translate ("Total area: %ld um^2"), total_area));
> info.start_element ("br");
> info.end_element ("br");
> info.cdata (tl::sprintf (tl::translate ("Total perimeter: %ld um"), total_area * dbu_unidir * dbu_unidir ));
> info.end_element ("p");
Hi Peter,
regarding any plans I have, they would probably involve a cold beer rather than a perimeter function :-)
But I'm glad for any suggestion which is as useful and easy to implement as this one:
I have to tried it myself yet, but the basic idea is to use the polygon edge iterator to collect the total length of all edges. The edge iterator is used in many places so it should work.
Please note that shape.begin_edge() will assert if the shape is not a polygon. But I assume you are using a merged layer (because otherwise you would count overlapping areas twice) which contains only polygons and not objects like paths or boxes.
To support the more general case (boxes and paths too) you should consider converting the shape to a db::Polygon object first:
Best regards,
Matthias
std::map<unsigned int, std::vector <db::Polygon> > polygons_by_layer;
std::map<unsigned int, db::Shapes>::iterator i = shapes_by_layer.begin();
while (i != shapes_by_layer.end() )
{
unsigned int l = (*i).first;
db::ShapeProcessor sp;
polygons_by_layer.insert(std::make_pair(l, gsi::merge_to_polygon2(sp, shapes_by_layer[l], 0, true, true) ) ); // <- this call fails,
// with "error: ‘merge_to_polygon2’ is not a member of ‘gsi’
}
Any idea how to solve this?
(And how to use the Markdown so I see a nice box around the code?)
Hi Peter,
"merge_to_polygon" is a method of ShapeProcessor (in fact it's called "merge"). The code should look like this:
I have not tested it myself, but that is the way it should work.
Best regards,
Matthias
I have a quick question (at least I hope its quick). I am a bit unfamiliar with this code... Anyhow, I'd like to find the perimeter of a shape. With the code that you have provided for the perimeter, do I need to copy and paste it somewhere in the area code? Should something be removed?
Thanks! Natalie
class MenuAction < RBA::Action
def initialize( title, shortcut, &action )
self.title = title
self.shortcut = shortcut
@action = action
end
def triggered
@action.call( self )
end
private
@action
end
$compute_total_perimeter = MenuAction.new( "Compute perimeter of selected shapes", "" ) do
app = RBA::Application.instance
mw = app.main_window
lv = mw.current_view
if lv == nil
raise "No view selected"
end
total_perimeter = 0.0
lv.each_object_selected do |obj|
shape = obj.shape
layout = lv.cellview(obj.cv_index).layout
if shape.is_polygon? || shape.is_box? || shape.is_path?
db::Shape::polygon_edge_iterator e = shape.begin_edge();
db::Coord p = 0;
while (! e.at_end()) {
p += e->length ();
}
end
end
RBA::MessageBox.info("Total perimeter", "Total perimeter of selected object is #{total_perimeter} microns", RBA::MessageBox.b_ok)
end
app = RBA::Application.instance
mw = app.main_window
menu = mw.menu
menu.insert_separator("tools_menu.end", "name")
menu.insert_item("tools_menu.end", "compute_total_perimeter", $compute_total_perimeter)
I get several errors when opening KLayout with this code which are:
SyntaxError: C:/Program Files (x86)/KLayout (64bit)/compute_perimeter.rbm:34: syntax error, unexpected '{', expecting keyword_do_cond or ';' or '\n'
C:/Program Files (x86)/KLayout (64bit)/compute_perimeter.rbm:35: syntax error, unexpected tLPAREN_ARG, expecting keyword_do_LAMBDA or tLAMBEG
p += e->length ();
^
C:/Program Files (x86)/KLayout (64bit)/compute_perimeter.rbm:54: syntax error, unexpected $end, expecting keyword_end
...ter", $compute_total_perimeter)
... ^
And if I take out the while loop, KLayout opens without error, but when I click to calculate parameter, I get:
NameError: undefined local variable or method `db' for main:Object in Action::triggered
C:/Program Files (x86)/KLayout (64bit)/compute_perimeter.rbm:32:in `block (2 levels) in <top (required)>'
C:/Program Files (x86)/KLayout (64bit)/compute_perimeter.rbm:26:in `each_object_selected'
C:/Program Files (x86)/KLayout (64bit)/compute_perimeter.rbm:26:in `block in <top (required)>'
C:/Program Files (x86)/KLayout (64bit)/compute_perimeter.rbm:8:in `call'
C:/Program Files (x86)/KLayout (64bit)/compute_perimeter.rbm:8:in `triggered'
Hi Natalie,
this discussion might be quite confusing. It mixes C++ code with Ruby code.
The correct Ruby code to compute the perimeter of a polygon is:
Regards,
Matthias
I used your "area calculator" code in a previous version of Klayout (32 bits ?) and it worked perfectly. Now I moved to Klayout 64bits with windows7 and I tried again to install the "area calculator" tool, but it does not work.
When starting klayout, here is the emssage that I receive :
"SyntaxError: C:/Program Files/KLayout (64bit)/Area_Calculator.rbm:49: syntax error, unexpected $end, expecting ')'
...otal_area", $compute_total_area
..."
^
Do I do something wrong ? Is there something I should change in the code ?
Thank you for your help.
François
Hi Francois,
I think there is a closing round bracket missing at the end of your text (copy/past issue?). I changed the Ruby version - maybe the older one was less picky. Could you add the bracket and try again?
Matthias
Thanks a lot for your response. It now works very well !
François
Hi Francois,
I'd like to mention there is an alternative method now inside the DRC engine.
The following DRC script prints the area of layer 16, datatype 0:
That method is typically faster than the Ruby code. It will also merge the shapes and not count overlapping regions.
If performance is an issue, you can use tiling to reduce memory requirements and employ multiple CPU cores to compute the area, i.e.
Matthias
An application for this area calculation is a density check within the DRC :
Regards,
Laurent
Hi Laurent,
thank you for pointing that out.
It is even possible to extend the DRC language with a local density check:
Regards,
Matthias
Hi Matthias,
Thank you in advance for any advise. I was trying out the local density code and wanted to ask the following as I have not managed to figure it out on my own.
1) Is it possible to implement a step to the tiling ? That means there will be a 50% overlap when tiling through the extent when considering the local density.
2) Is it possible to output the density of the tiling window that fails ? When I tried I seem to be getting the density of the entire layout instead of the tiling window.
3) Is it possible to tile through the extent of all the layers in the layout instead of just the extent of the input layer ?
Thank you in advance for your help. Not sure if I have misunderstood the intent of the code above.
Best regards,
Lester
Hi Matthias,
Sorry it's me again.
Currently we have two methods to count the area of selected objects:
=
Is it possible to improve the code that we could get the correct area like "merge shapes" + method1 ?
Really appreciate your effort~
Best Regards,
chhung
Hi @phlion,
welcome back
The solution is simple: first all the shape to the region and then compute the area:
You code above is slow since on every iteration it will add one more shape to the region making it bigger and bigger and wasting more and more time in the merged-region are computation.
Matthias
Hi @Matthias,
The code "region.insert(obj.trans * shape.polygon)" seems not work on v0.24.x with the following error message
however works like a charm after v0.25.x
Thanks for your great help~ XDDD
Best Regards,
chhung
Oh yes ... a lot happened since 0.24 was released six years ago