How to get/set the instance coords within a PCell

edited July 2015 in Ruby Scripting

Hi,

I took the Circle PCell example code and modified it so it's an ellipse with a box as the guiding shape.

As you move or drag the guiding shape around, the shape is correctly generated. I am generating the shape with its center given by two hidden parameters, cx and cy.

As you can expect, the actual origin of the PCell (the one you see when you press 'q', under Geometry tab, x and y; or the one that shows as a "+" on the layout when the PCell is selected) is unchanged through all of this. Because it's cx and cy that I am using to move the ellipse, not actually moving the instance itself.

I would like now to change the actual origin of the PCell. So, no matter how you drag and move the guiding shape, the origin of the PCell (the "+") is always at the center of the bounding box. So, it'd behave the same as it does now, except it would modify the x,y origin of the instance (and therefore the transformation of the instance in its parent cell) to keep the cell origin always in the center of the bounding box. I hope that makes sense.

For this I'd need access to the instance transformation. But I don't see how to do that from within the class PCellDeclarationHelper. Is there a way?

Thanks,
David

module MyLib

  include RBA

  # Remove any definition of our classes (this helps when 
  # reexecuting this code after a change has been applied)
  MyLib.constants.member?(:Ellipse) && remove_const(:Ellipse)
  MyLib.constants.member?(:MyLib) && remove_const(:MyLib)

  # The PCell declaration for the circle
  class Ellipse < PCellDeclarationHelper

    include RBA

    def initialize

      # Important: initialize the super class
      super

      rada = 10.0
      radb = rada / 2.0

      # declare the parameters
      param(:l, TypeLayer, "Layer", :default => LayerInfo::new(1, 0))
      param(:s, TypeShape, "", :default => DBox.new(-rada,-radb,rada,radb))
      param(:ra, TypeDouble, "Radius 'a'", :default => rada)
      param(:rb, TypeDouble, "Radius 'b'", :default => radb)
      param(:n, TypeInt, "Number of points", :default => 64)     
      # this hidden parameter is used to determine whether the radius has changed
      # or the "s" handle has been moved
      param(:rua, TypeDouble, "Radius 'a'", :default => 0.0, :hidden => true)
      param(:rub, TypeDouble, "Radius 'b'", :default => 0.0, :hidden => true)
      param(:cx, TypeDouble, "Center x", :default => 0.0, :hidden => true)
      param(:cy, TypeDouble, "Center y", :default => 0.0, :hidden => true)

    end

    def display_text_impl
      # Provide a descriptive text for the cell
      "Ellipse(L=#{l.to_s},Ra=#{'%.3f' % ra.to_f},Rb=#{'%.3f' % rb.to_f}))"
    end

    def coerce_parameters_impl

      # We employ coerce_parameters_impl to decide whether the handle or the 
      # numeric parameter has changed (by comparing against the effective 
      # radii rua,rub) and set rua,rub to the effective radius. We also update the 
      # numerical value or the shape, depending on which on has not changed.
      rsa,rsb = nil,nil
      if s.is_a?(DBox) 
        width = s.width
        height = s.height
        rsa = width / 2.0
        rsb = height / 2.0
        #extend = (width - height) / 2.0 # How far to extend the height, in order to match the width, to keep it square rather than rectangular
        #s.bottom,s.top = s.bottom - extend, s.top + extend # Coerce the height of the guid shape to be the same as the width
      end 
      if rsa && rsb && (ra-rua).abs < 1e-6 && (rb-rub).abs < 1e-6 # An edge of the guiding shape was dragged
        set_rua rsa
        set_rub rsb
        set_ra rsa
        set_rb rsb
        # Coerce the center of the circle to lie at the new center of the bounding box
        center = s.center 
        set_cx center.x
        set_cy center.y
      else
        set_rua ra
        set_rub rb
        set_s DBox.new(-ra,-rb,ra,rb)
      end

      # n must be larger than or equal to 4
      n > 4 || (set_n 4)

    end

    def can_create_from_shape_impl
      # Implement the "Create PCell from shape" protocol: we can use any shape which 
      # has a finite bounding box
      shape.is_box? || shape.is_polygon? || shape.is_path?
    end

    def parameters_from_shape_impl
      # Implement the "Create PCell from shape" protocol: we set r and l from the shape's 
      # bounding box width and layer
      set_r shape.bbox.width * layout.dbu / 2
      set_l layout.get_info(layer)
    end

    def transformation_from_shape_impl
      # Implement the "Create PCell from shape" protocol: we use the center of the shape's
      # bounding box to determine the transformation
      Trans.new(shape.bbox.center)
    end

    def produce_impl

      # This is the main part of the implementation: create the layout

      # compute the ellipse
      dbu = layout.dbu
      pts = []
      da = Math::PI * 2 / n
      n.times { |i|
        x = cx + rua * Math::cos(i * da)
        y = cy + rub * Math::sin(i * da)
        dpoint = DPoint.new(x/dbu,y/dbu)
        pts << Point.from_dpoint(dpoint)
      }

      # create the shape
      cell.shapes(l_layer).insert(Polygon.new(pts))

    end

  end

  # The library where we will put the PCell into 
  class MyLib < Library

    def initialize  

      # Set the description
      self.description = "My First Library"

      # Create the PCell declarations
      layout.register_pcell("Ellipse", Ellipse::new)
      # That would be the place to put in more PCells ...

      # Register us with the name "MyLib".
      # If a library with that name already existed, it will be replaced then.
      register("MyLib")

    end

  end

  # Instantiate and register the library
  MyLib::new

end

Comments

  • edited July 2015

    Hi David,

    you cannot modify the cell's instantiation point from within the cell. Instance and cell live in different spaces (instance in the host layout, cell in the library). So basically it's not possible to access the instances properties from within the PCell code.

    But apart from the "+" mark there should not be any difference in usage of the PCell, right?

    Matthias

  • edited July 2015

    I see. Too bad, but it makes sense.

    It is true, PCell will be the same. However I often use the origin of the cell as some kind of mental reference point -- e.g. the "+" is snapped to some relevant grid, or aligned to some other shape when I align the two shapes -- because it is visible. If you're dragging this guiding shape box all around, the "+" could be way over there when the cell is way over here. It's also hard to know where the exact center of the ellipse is unless it is marked. (Speaking of the ellipse, but in reality I have other more complicated PCells in mind)

    I suppose I could put a point at the center, at least to mark the center.

    Anyway thanks for your thoughts

    David

Sign In or Register to comment.