It looks like you're new here. If you want to get involved, click one of these buttons!
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
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
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