Hi,
I have some wires with orthogonal corners. I would like to round the corners. In other words, imagine a windy road through the mountains rather than a Manhattan-type xy road.
Is there some way to do this via scripting? I found the Edit>Selection>RoundCorners option, but of course this is for polygons.
Thanks,
David
Comments
However I am having trouble on the following things:
1. I have a path called "shape" below. How do I return the number of vertices?
2. How do I return a specific vertex (e.g. the third vertex)?
3. How do I loop through only certain vertices? I want to loop through vertex 1 to N-1, where the vertex indices go from 0 to N. I know of each_point method, but this goes through each point. If you scroll down to the comment with the ### you will see the point where I'm unsure how to proceed.
=================
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_area = MenuAction.new( "Convert wires", "" ) do
app = RBA::Application.instance
mw = app.main_window
lv = mw.current_view
if lv == nil
raise "No view selected"
end
radius = 15.0
radius = RBA::InputDialog.get_double("Radius", "What radius?",15,5)
#RBA::MessageBox.info("Result", "Radius is #{radius.value} um or meters", RBA::MessageBox.b_ok)
lv.each_object_selected do |obj|
shape = obj.shape
layout = lv.cellview(obj.cv_index).layout
if shape.is_path?
RBA::MessageBox.info("Found path", "Found a path", RBA::MessageBox.b_ok)
# Get the number of vertices
#N = ???
# Loop through the vertices
#for i in 1..(N-1)
# prev_vertex = ??? #This should point to the (i-1)th vertex
# curr_vertex = ??? #This should point to the ith vertex
# next_vertex = ??? #This should point to the (i+1)th vertex
# #Here is where I put code that calculates the new multi-segment path
#
# #Here is where I put code to replace the old path with the new path
#
#end
end
end
#RBA::MessageBox.info("Finished", "Finished converting wires", RBA::MessageBox.b_ok)
end
app = RBA::Application.instance
mw = app.main_window
menu = mw.menu
menu.insert_separator("tools_menu.end", "sep_calc_area")
menu.insert_item("tools_menu.end", "compute_total_area", $compute_total_area)
Hi David,
that is actually a good start.
Now let's look how to proceed after you have checked that the shape is a path:
If you're lucky, the selection remains valid after that operation. That is not necessarily the case, specifically if you change the shape type, so one has to be careful. "lv.cancel" at the end makes sure the selected shape is not used any longer and any pending operations are cancelled.
You can also add undo support by wrapping your modification code into a block like this:
Regards,
Matthias
BTW: The forum system allows entering code by indenting the lines (Markdown syntax). So far nobody seems to have noticed :-)
I noticed Markdown syntax radio button but unfortunately:
1. It wasn't clear what kind of markdown/markup I should use. e.g. should I use something similar to wiki markup? Should I indent with spaces? Do I need e.g. <code></code> tags (;ltcode;gt;lt/code;gt)? I now see the page you linked to but it would be nice if there were a short description under the Markdown syntax radio button...
2. After I submitted, I wanted to undo or edit the post, try the Markdown syntax radio button, and re-post, thus fixing the formatting. However there was no option to edit my post :)
Just mentioning this because it is probably the same sequence that others who didn't notice Markdown radio button might be going through... So this might help some of the Markdown woes.
David
I succeeded in doing this - at least a rough version (e.g. no error checking on manhattan geometry input etc). I pasted the code below in case future users are interested.
However a few questions:
How do I assign a shortcut key? I see in Macro Development you can click on Edit Properties and there is a place to insert a shortcut key, but I have tried "F5", "$", "C" etc all with no luck - I press the key in KLayout and nothing happens...?
I'd like to actually leave the old wire and duplicate it, and act only on the duplicate. And also change the duplicate wire to a different GDS layer number. So in the end you have your original wire and then another duplicate wire on a different layer. I've tried various things but can't figure this out perhaps due to not understanding ruby syntax well enough -- it should be simple though..?
Once I have those two wires I'd like to convert both to polygon or simplepolygon using the commands here http://www.klayout.de/doc/code/class_Path.html. But I can't figure out how to write those commands to work. Should be simple I just can't figure out how to write them. I've tried newpoly = shape.path.polygon and some other things but it's not drawing anything.
Lastly, having two polygons, I hope to subtract one from the other and put the result on yet another layer. Also not having luck there. Could you pls provide a simple code snippit?
Thanks,
David
===
Hi David,
I don't have time right now to look into your code, but I hope I can do so soon.
Regarding the key assignment: it's working on my installation but under the following conditions:
Regards,
Matthias
Hi David,
here are some answers to your question:
For 2.) you'll have insert a shape rather than changing it. So
If I understand your request correctly for 3.) you want to replace one path by two polygons - one with the rounded corners and one as the original. That would be this code (shape is the original shape):
And finally for 4.):
Hope that answers your question.
Matthias
Thanks Matthias,
Regarding the shortcut key - it still appears to not be working. Here are the steps I do:
At this point I click on the layout editor so it is in focus, I press Shift+Z. The script does not run, but instead the Macro Editor comes back in focus - strange. Happens every time. At this point I close the macro editor to see if that makes a difference. I press Shift+Z again. Nothing happens. However the script itself works as evidenced by the fact I can run it from the Tools menu.
What am I doing wrong?
[Regarding the other items, I'll try these and get back to you.]
Thanks!
Hi David,
I am still confident that it's working, because I still can reproduce the functionality both on Linux and Windows.
Just a question: does the keyboard shortcut show up in the menu entry in the Tools menu? In my case I have used the following settings in the properties:
The macro is a very simple one:
All other fields in the properties dialog are empty.
Then the "Tools" menu shows my macro as "My Macro Shift+Z" under "Macros" (0.22.7 on Ubunto 12.04LTS). Seeing the shortcut there is a good indication that the shortcut is registered and will work.
If I press Shift+Z in the layout area (with a layout loaded), the message box pops up.
If that is still not working on your installation, I can just guess. Maybe there is something wrong with other settings - you could try moving away the configuration file ("~/.klayout/klayoutrc" on Linux or "%HOME%/KLayout/klayoutrc" on Windows) and see whether it's working then. Maybe there is some custom shortcut interfering with the macro-specific shortcut.
Regards,
Matthias
I figured out why I was having strange shortcut key issues.
If I simply remove this wrapper from my entire code:
and replace it with this wrapper:
then it all works as you say.
To be honest I don't understand the function of all of this extra code, I was just building from a known example (the "calculate total area" example on this website, I believe). But hey it works now just as you describe. Thanks!
However now another question
This works fine (total code pasted below) in the following case:
Make a new layout, new top cell called "top", new layer called layer 1, new layer called layer 6.
Draw a wire e.g. 1um wide, on the "top" cell, in some arbitrary Manhattan geometry with various sharp 90deg bends.
Select the wire.
Run this macro from the menu or press Shift-Z. The right-angled wire is now a bendy wire. (Actually, two parallel bendy wires which is what I wanted - but that is a small detail.)
However this DOESN'T work fine if you do the same as above, but the wire is not on the top cell. If the wire is instead on a child cell that is instanced in the top cell, you can still select the wire the same (assuming you are looking at the top cell you can still select elements of the child cell). You can still run the code. But then KLayout crashes and closes without error message.
Any ideas how to fix it so it loops through all wires selected, regardless of whether the wire is in the top cell or in a child (or grandchild) cell?
Thanks! Code pasted below.
Hi David,
sorry I did not catch the last one about the key binding: of course the wrapper code is responsible for the behavior. The wrapper code is "old style menu binding" which was necessary before macros came into existence.
Simple ruby modules (".rbm" files) are plain scripts which are executed on startup. Using the application's API these scripts were able to register a piece of code inside a menu handler (an "action") and attach that code to a single or even multiple menu items and/or bind it to a key. That mechanism was implemented through the MenuAction helper class and often appears in sample code.
"Macros" (".lym" files) however are annotated ruby scripts (more precisely XML files containing the Ruby code plus some attributes). They can be given attributes indicating that they shall appear in the menu and KLayout will add the wrapper code itself in that case. The same way, key bindings are created. These are the attributes you can configure in the macro properties page.
By placing "old" wrapper code inside the macros plus configuring them for key binding, you basically make KLayout execute the registration code instead of the actual body part - hence the key binding did not have an effect.
Regarding the second question: The crash is probably because you were using the cell index as the cellview index. That will result in an invalid access (I certainly admit that crashing is unfriendly behavior). Please use "layout.cell(cell_index)".
But allow me one more remark: you don't need to insert a path into the Shapes container and use Shape#polygon to convert it to a polygon. Path#polygon will simply to the job. So the replacement of the shape should look like this:
Thje two "erase" calls are no longer required.
That should fix the issue.
There is one additional pitfall: if you have a selection of multiple shapes, it may happen that you select the same shape of the same child cell twice. That results in the same polygon being created twice in the target cell. Right now there is no good way to avoid that - the easiest solution is to confine the code to single-object selections.
Regards,
Matthias
This works great now, thanks.
I made the changes you recommended and all works great. I understand the difference between .lym and .rbm now.
Pasting the final code below in case future readers are interested.
Thanks