Moving a Text shape after it has been added to Cell.shapes... and a display problem?

edited December 2013 in Ruby Scripting

Hi Matthias,

I am using version 0.23 and trying to move a Text instance after it was added to the cell:

# Create layout
main_window =  RBA::Application::instance.main_window
cellview = main_window.create_layout(1)

# Set up layout
layout = cellview.layout
layout.dbu = 0.001
layer_index = layout.insert_layer(RBA::LayerInfo.new(0,0))

# Add a cell
cell_index = layout.add_cell('MoveLabelTest')
cell = layout.cell(cell_index)

# Add a text
text = RBA::Text.new('This is a test', 1000, 2000)
puts text
cell.shapes(layer_index).insert(text)

# View cell
main_window =  RBA::Application::instance.main_window
layout_view = main_window.current_view
layout_view.select_cell(cell_index, 0)
layout_view.zoom_fit

# Try to move text
text.x = -1234
puts text

When I run that code in the Macro Development window, I see the following in the transcript:

('This is a test',r0 1000,2000)
('This is a test',r0 -1234,2000)

This suggests to me that the text coordinates have changed as intended. Nevertheless, the layout_view still shows the old coordinates and so does the Object Properties dialog of that text.

I have seen here that an object can be moved when using its Shape instances, which can be obtained by looping through all the cell.shapes on a given layer and trying to find the text I want to move by replacing the line text.x = -1234 with

new_x = -1234
cell.shapes(layer_index).each do |shape|
  if shape.is_text? and shape.text == text
    shape.transform(RBA::Trans.new(text.trans.inverted.disp + RBA::Point.new(new_x, text.trans.disp.y)))
    break
  end
end

...which seems a little too much code for moving an object I already have the reference to. Interestingly, this does move the shape in the layout_view, but the console log shows now

('This is a test',r0 1000,2000)
('This is a test',r0 1000,2000)

suggesting that the text hasn't moved. Is the text I see in the layout_view different from the text reference I kept in the script? What is the Text.x= method used for?


Now on to the minor display problem: When running above script, the text doesn't actually show, except for a 1 pixel point. I can select it though. Only if there at least one other object in the view, the text becomes visible... which is usually the case anyway.

Comments

  • edited December 2013

    Hallo,

    the behaviour is intended and there is an explanation:

    First of all, "Text" is the working object. You can manipulate it with it's methods like any normal Ruby object. When you insert such an object into the layout database, a copy of it is stored internally. Here, the Ruby analogy fails (now we enter C++) because the object you inserted will not be the one stored in the database. If you manipulate it later, this won't have any effect on the database. "Text.x=" will set the x coordinate of the text object, but for the reasons just mentioned, this also does not have any effect.

    To access objects from the database, you have to use the Shape object. The Shape object is basically a pointer to an object in the database.

    When you insert the text you will receive a Shape object which refers to the inserted text:

    shape = cell.shapes(layer_index).insert(text)
    

    You can now manipulate the text inside the database. In your case, "transform" is the method of choice:

    shape.transform(RBA::Trans::new(dx, dy))
    

    You can also change the text's position or orientation using "Shape#text_trans=" or the text's string using "Shape#text_string=". Note that this requires that the Shape object refers to a text object.

    So, you don't need to loop - only if you forgot the Shape object you received from insert. Shape objects also play a role when accessing the selected objects are when iterating over a layout with RBA::RecursiveShapeIterator.

    There is one caveat: Shape objects may become invalid, for example if you delete the cell they are contained in. For performance reasons the Shape object is not notified in that case and when you try to access it the next time, KLayout will crash.

    If your application is to generate layout, I'd suggest to use the working objects (Text, Polygon, Path, Box) as long as possible and send them to the layout database then. There is no need to manipulate them inside the layout database that way.

    Hope that helps.

    Regards,

    Matthias

    BTW: your post is a nice example how to use Markdown :-)

  • edited December 2013

    On the minor display problem - I think this was explained by Matthias in this post.

  • edited December 2013

    Thank you Matthias, for the thorough explanation.

    I am actually working on a medium-size Ruby project to procedurally generate layout. I now changed it to keep Shape references instead of the geometric primitives, since the latter aren't references to layout objects in the database.

    Two reasons for working directly with the database instead creating the "working objects" first:

    • I can use convenience methods such as Cell.each_touching_shape() already provided by the database API.
    • I thought memory efficiency would be better when keeping the objects in the database rather than having a duplicate of the layout in Ruby space.

    Are there any other disadvantages than potentially stale references? How about execution speed? What is the runtime penalty of looking up objects from the database rather than from a Ruby equivalent of it?

    Also interesting in the context of this project would be what the future of KLayout will bring in terms of support for named instances and more abstract concepts such as instance pins, as this is at the core of what I am working on.


    Yeah, the more I use it, the more I like Markdown - I still need the cheatsheet open in another window for more "fancy" stuff ;-)


    Thanks Maks, for the link - that indeed explains the behaviour.

  • edited November -1

    Friendfx - thanks for the Markdown cheatsheet link!
    I have just realized what Markdown is... I used AsciiDoc before, which has a similar idea...

  • edited November -1

    Hi friendfx,

    Regarding your questions about the stale references: performance-wise there is no difference between pure objects and database references. When it comes to execution speed, Ruby is not the best choice anyway. I considered opening a new API for C and C++ to account for that, but this will require some preparation, so it won't come soon.

    Speaking of the future - concepts like pins and named instances are not part of the GDS and OASIS specification and that still is the basis of the program. It's possible to emulate those features (and others like net information) with user properties, but the interpretation of those is strongly dependent on the tools reading these files. I have made no attempt so far to integrate OpenAccess, which is a natural basis for such objects. Despite "Open", Si2 license requirements are not compatible with GPL.

    Matthias

Sign In or Register to comment.