Ruby, Fetch x and y position of the mouse click from gds

I am a new KLayout user. Trying to make a macro using ruby which requires X and Y co-ordinate of the point where mouse is clicked. Any help is really appreciated

Comments

  • edited March 2

    I have made some modifications to the example Matthias provided ,
    one thing I noticed you have to load the script twice
    before it works other wise it crashes ??? Reason I have no idea.
    This works in Python not sure how to get the same script to work in Ruby,
    it's a mystery, mouse functions should not be this elaborate.
    As discussed in this example
    https://www.klayout.de/forum/discussion/1151/capture-a-mouse-click-and-its-location

    import pya
    
    # Enter your Python code here ..
    # Register this macro as "autorun" to enable the plugin
    
    # First thing is to implement a "plugin factory". This 
    # object is asked to provide a plugin for each view
    
    class GetXYOnMouseClickPluginFactory(pya.PluginFactory):
    
      def __init__(self):
        super(GetXYOnMouseClickPluginFactory, self).__init__()
        pya.MainWindow.instance()  # (workaround for bug 191)
        self.register(-1000, "get_xy", "Get X/Y")
    
      def create_plugin(self, manager, root, view):
        return GetXYOnMouseClickPlugin()
    
      # Keeps the singleton instance
      instance = None
    
    # Create and store the singleton instance
    GetXYOnMouseClickPluginFactory.instance = GetXYOnMouseClickPluginFactory()
    
    
    # Second thing is the actual plugin
    
    class GetXYOnMouseClickPlugin(pya.Plugin):
    
      def __init__(self):
        super(GetXYOnMouseClickPlugin, self).__init__()
        pass
    
      def activated(self):
        pya.MainWindow.instance().message("Click on point to Get X/Y", 10000)
    
      def deactivated(self):
        pya.MainWindow.instance().message("", 0)
    
      def mouse_click_event(self, p, buttons, prio):
        # This is where everything happens
        if prio:
          #print("Mouse clicked at X/Y" + str(p))
          pya.MainWindow.instance().message("Mouse Clicked at X/Y = " + str(p), 10000)
          return True
        return False
    
  • To combat the behavior change noted here, ruler snap to vertex, I want to automate the actions of the ruler. Specifically:
    1. Popup dialog for user to pick 3 vertices of a polygon.
    2. on each mouse click, capture the x,y coordinate of the mouse location in drawn space and the nearest x,y coordinate of the selected vertex. They must agree with some tolerance.
    3. After 3 points found, calculate the x,y coordinate of the midpoint of the hypotenuse of the triangle defined by the 3 points.
    4. Repeat for the next polygon.
    5. Calculate the distance between the 2 found centers.

  • edited March 3

    Interesting things on rulers
    https://www.klayout.de/doc-qt5/code/class_Annotation.html#method89
    Annotation objects provide a way to attach measurements or descriptive information to a layout view.
    Annotation objects can appear as rulers for example.
    Annotation objects can be configured in different ways using the styles provided.
    By configuring an annotation object properly, it can appear as a rectangle or a plain line for example.
    See Ruler properties for more details about the appearance options.
    Below are Python/Ruby Versions of this
    Update Fixed the Python



    #Python Version Ruler Annotation app = pya.Application.instance() mw = app.main_window() view = mw.current_view() ant = pya.Annotation() ant.p1 = pya.DPoint(0, 0) ant.p2 = pya.DPoint(100, 0) ant.style = pya.Annotation.StyleRuler view.insert_annotation(ant) #Ruby Version Ruler Annotation this works app = RBA::Application.instance mw = app.main_window view = mw.current_view ant = RBA::Annotation::new ant.p1 = RBA::DPoint::new(0, 0) ant.p2 = RBA::DPoint::new(100, 0) ant.style = RBA::Annotation::StyleRuler view.insert_annotation(ant)
  • I am using this code to find the center of the two shapes and measure the distance between them. How do I save the info of coordinate for finding the center and calculation of the distance between them

  • @tagger5896 Thanks for your "Get X/Y" code above.

    You should put these line

    GetXYOnMouseClickPluginFactory.instance = GetXYOnMouseClickPluginFactory()
    

    at the end. Because with a layout open it's executed immediately and at this point the GetXYOnMouseClickPlugin class isn't defined. With this fix I don't see any crashes (Ubuntu 20, version 0.26.11).

    Apart from that: "mouse functions should not be this elaborate" ... we had this topic before. If anyone has a better solution, please drop me a pull request on GitHub and I'll take a look. After all it's open source and it's not my responsibility to make you happy. My focus is on architecture. KLayout is a highly scalable application. This does not come for free.

    Matthias

  • edited March 6

    @Matthias
    @skywalk
    @raji
    @dick_freebird

    Some updates regarding interesting things with rulers
    Code below allows too ad multi-segment rulers
    It's buggy at best at the present time,
    Need too add Marker shape to follow Entered path and Snap.
    Double click First mouse button, then Right Click end's Point Entry and adds annotated Ruler.
    At process_coords():
    # TODO: put in your code to do what you like to do below
    #Unlimited things can be done
    If anybody has ideas too follow the coords for the marker layer and snap
    Please feel free to update. My mouse is entering an limited life span :)

    Regards
    Tracy

    #Tracy Groller
    #3/3/21
    #Prelimaniary Code, Rough at best and Buggy
    #Testing Ideas :=]
    #Process Rulers with Multi Coords
    #Need too add Marker and Snap
    #Adds Right Click to end , no need to select another tool
    #This will put a Ruler Path in the Tool Bar
    
    import pya
    import gc
    app = pya.Application.instance
    
    buffer = []
    
    class GetXYOnMouseClickPluginFactory(pya.PluginFactory):
    
      def __init__(self):
        super(GetXYOnMouseClickPluginFactory, self).__init__()
        pya.MainWindow.instance()  # (workaround for bug 191)
        self.register(-1000, "get_xy", "Ruler Path")
    
      def create_plugin(self, manager, root, view):
        return GetXYOnMouseClickPlugin()
    
      # Keeps the singleton instance
      instance = None
    
    # Create and store the singleton instance
    GetXYOnMouseClickPluginFactory.instance = GetXYOnMouseClickPluginFactory()
    # Second thing is the actual plugin
    class GetXYOnMouseClickPlugin(pya.Plugin):
    
      def __init__(self):
        super(GetXYOnMouseClickPlugin, self).__init__()
        pass
    
      def activated(self):
        pya.MainWindow.instance().message("Click on point to Start Ruler", 10000)
    
      def mouse_click_event(self, p, buttons, prio):
        # This is where everything happens
        #self.set_cursor(pya.Cursor.Cross)
        if buttons == pya.ButtonState.RightButton :
                #Right Click ends it process coords entered
                self.ungrab_mouse()
                pya.MainWindow.instance().cancel()
                pya.MainWindow.instance().menu().action("@toolbar.select").trigger()
                #Process Coords
                process_coords()
        if prio:
          pya.MainWindow.instance().message("Ruler Points are  = " + str(p), 10000)
          x = p.x
          y = p.y
          data(buffer,x,y)
          return True
        return False
    
    #buffer = []    
    def data(buffer,x,y):
        buffer.append([x,y])
    
    def process_coords():
      # TODO: put in your code to do what you like to do below
      #Unlimited things can be done
      app =  pya.Application.instance()
      mw =  app.main_window()
      view = mw.current_view()
      ant =   pya.Annotation()
      wdt = 10
      blen = len(buffer)
      prev = buffer[0]
      curr = buffer[1]
      print(buffer)
     #Process Prev and Curr and Nxt coords
      for nxt in buffer[2:]:
          print(f'prev: {prev}, curr: {curr}, next: {nxt}')
          prev = curr
          curr = nxt    
          x1p = prev[0]
          y1p = prev[1]   
          x1c = curr[0]
          y1c = curr[1]
          #Testing
          #x1n = nxt[0]
          #y1n = nxt[1]      
          #print("Xp = ", x1p)
          #print("Yp = ", y1p)
          #print("Xc = ", x1c)
          #print("Yc = ", y1c)
          #print("Xn = ", x1n)
          #print("Yn = ", y1n)
          #Prev and Curr for coords
    
          ant =     pya.Annotation()
          ant.p1 = pya.DPoint(x1p, y1p) 
          ant.p2 = pya.DPoint(x1c, y1c)
    
          ant.style = pya.Annotation.StyleRuler
          view.insert_annotation(ant)
    
    
    
      buffer.clear()
    
    
  • So Matthias
    @Matthias
    yes we have had ... this topic before, so I am gonna stay within the framework.
    I have been able to make multi-part segmented rulers within PluginFactory,
    with right click to end and then process the mouse inputs,
    So looking at the code below, I have tried to get this to work with paths to no avail
    Comments Suggestions
    https://www.klayout.de/forum/discussion/comment/7180#Comment_7180
    Regards
    Tracy

  • I am able to grab x and y coordinates with the above python code. But I would like to select/highlight the box when I click three vertices of the box by mouse input. Thanks!

  • edited May 19

    I am trying to get actual x and y coordinates of the selected polygon/box. How can I change this code
    in order to get actual x and y coordinates. Any help is greatly appreciated

    module ExtractPoints
    include RBA
    myListx = []
    myListy = []
    ly = CellView::active.layout
    ly.read('C:/28200.gds')
    view = RBA::LayoutView::current
    layer = RBA::LayerInfo::new(12, 0)
    li = view.begin_layers

    while !li.at_end?
    lp = li.current
    new_lp = lp.dup
    new_lp.visible = (lp.source_layer == 12 && lp.source_datatype == 0)
    view.set_layer_properties(li, new_lp)
    li.next
    end

    ly = CellView::active.layout
    lv = Application::instance.main_window.current_view
    lv.each_object_selected { |obj|
    shape = obj.shape
    if shape.is_polygon?||shape.is_box?
    shape.polygon.each_point_hull { |pt|
    x, y = pt.xly.dbu, pt.yly.dbu
    myListx << x
    myListy << y
    }
    end
    }
    p "#{myListx}", "#{myListy}"

    end

  • edited June 4

    I am trying to get actual x and y coordinates of the selected polygon/box. How can I change this code
    in order to get actual x and y coordinates. Any help is greatly appreciated

    module ExtractPoints
    include RBA
    myListx = []
    myListy = []
    ly = CellView::active.layout
    ly.read('C:/28200.gds')
    view = RBA::LayoutView::current
    layer = RBA::LayerInfo::new(12, 0)
    li = view.begin_layers
    
    while !li.at_end?
      lp = li.current
      new_lp = lp.dup
      new_lp.visible = (lp.source_layer == 12 && lp.source_datatype == 0)
      view.set_layer_properties(li, new_lp)
      li.next
    end
    
    ly = CellView::active.layout
    lv = Application::instance.main_window.current_view
    lv.each_object_selected
    {
      |obj|
      shape = obj.shape
      if shape.is_polygon?||shape.is_box?
        shape.polygon.each_point_hull 
        { 
          |pt|
          x, y = pt.x*ly.dbu, pt.y*ly.dbu
          myListx << x
          myListy << y
        }
    end
    }
    p "#{myListx}", "#{myListy}"
    end
    
  • @raji The bottom part of the script actually provides the solution with a few modifications:

    module ExtractPoints
    include RBA
    
    myListx = []
    myListy = []
    
    ly = CellView::active.layout
    lv = Application::instance.main_window.current_view
    lv.each_object_selected {
      |obj|
      shape = obj.shape
      if shape.is_polygon?||shape.is_box?
        # NOTE "transformed" - this transforms the polygon into the current cell
        shape.polygon.transformed(obj.trans).each_point_hull { 
          |pt|
          (x, y) = pt.x*ly.dbu, pt.y*ly.dbu
          myListx << x
          myListy << y
        }
      end
    }
    
    puts "#{myListx}", "#{myListy}"
    
    end
    

    Vou can select a shape and then call the script to get the coordinates. The list will be printed to stdout or the console if the macro IDE is open.

    Matthias

  • edited June 8

    Thanks Matthias!

  • edited June 15

    I would like to turnoff all layer except two layers having pads and die border. I could turn off all layers except one layer with the code below. How can I change this code to turn on two layers

    include RBA
    myListx = []
    myListy = []
    ly = CellView::active.layout
    ly.read('C:/28200.gds')
    view = RBA::LayoutView::current
    layer = RBA::LayerInfo::new(12, 0)
    li = view.begin_layers
    
    while !li.at_end?
      lp = li.current
      new_lp = lp.dup
      new_lp.visible = (lp.source_layer == 12 && lp.source_datatype == 0)
      view.set_layer_properties(li, new_lp)
      li.next
    end
    
    lv = Application::instance.main_window.current_view
    lv.each_object_selected {
      |obj|
      shape = obj.shape
      if shape.is_polygon?||shape.is_box?
        # NOTE "transformed" - this transforms the polygon into the current cell
        shape.polygon.transformed(obj.trans).each_point_hull { 
          |pt|
          (x, y) = pt.x*ly.dbu, pt.y*ly.dbu
          myListx << x
          myListy << y
        }
      end
    }
    
    puts "#{myListx}", "#{myListy}"
    
    end
    
  • Is this related to the original discussion? Maybe you want to open a new one.

    Matthias

Sign In or Register to comment.