Hi everybody,
Thnaks to the Pcell tools developped by Matthias i have written a small Pcell which is used for Box In Box alignement control patterns. You can have a "standard" BiB  which is 30x30 µm wide or a larger one which is 90µmx90µm (text not comprised) with alignement control better than 1µm (with optical means) and even better using SEM.
The code is probably clean, but i didn't detect bugs in it. The difference in the way Box and In Box are drawn (mainly coordinates), is on purpose (but there is probably a better way to do what i do there)
Here it is
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
 <description/>
 <version/>
 <prolog/>
 <epilog/>
 <doc/>
 <format>general</format>
 <autorun>true</autorun>
 <autorun-early>true</autorun-early>
 <shortcut/>
 <show-in-menu>false</show-in-menu>
 <group-name/>
 <menu-path/>
 <interpreter>ruby</interpreter>
 <text># PCell Pour motif alignement et contrôles
#
# This library contains
# BoxInBox
# sample PCell implements a library called "MyLib" with a single PCell that
# draws a circle. It demonstrates the basic implementation techniques for a PCell 
# and how to use the "guiding shape" feature to implement a handle for the circle
# radius.
# 
# NOTE: after changing the code, the macro needs to be rerun to install the new
# implementation. The macro is also set to "auto run" to install the PCell 
# when KLayout is run.
module AligneControle
  include RBA
  # Remove any definition of our classes (this helps when 
  # reexecuting this code after a change has been applied)
  AligneControle.constants.member?(:BoxinBox) && remove_const(:BoxinBox)
  AligneControle.constants.member?(:AligneControle) && remove_const(:AligneControle)
  
  # The PCell declaration for the circle
  class BoxinBox < PCellDeclarationHelper
  
    include RBA
    def initialize
      # Important: initialize the super class
      super
      # declare the parameters
      param(:larg, TypeBoolean, "Large ?",:default=> false)
      param(:bl, TypeLayer, "Layer Box", :default => LayerInfo::new(1, 0))
      param(:binv,TypeBoolean, "Box polarité inverse?",:default => false)
      param(:ibl, TypeLayer, "Layer InBox", :default => LayerInfo::new(1, 0))
      param(:ibinv,TypeBoolean, "InBox polarité inverse?",:default => false)
#      param(:s, TypeShape, "", :default => DPoint::new(0, 0))
#      param(:r, TypeDouble, "Radius", :default => 0.1)
#      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(:ru, TypeDouble, "Radius", :default => 0.0, :hidden => true)
  #    param(:inv,TypeBoolean, "inverse?",:default => false)
    end
  
    def display_text_impl
      # Provide a descriptive text for the cell
      "BoxInBox(L1=#{bl.to_s},L2=#{ibl.to_s})"
    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 
      # radius ru) and set ru to the effective radius. We also update the 
      # numerical value or the shape, depending on which on has not changed.
  #    rs = nil
   #   if s.is_a?(DPoint) 
        # compute distance in micron
    #    rs = s.distance(DPoint::new(0, 0))
    #  end 
     # if rs && (r-ru).abs < 1e-6
      #  set_ru rs
       # set_r rs 
      #else
       # set_ru r 
        #set_s DPoint::new(-r, 0)
      #end
      
      # n must be larger or equal than 4
      #n > 4 || (set_n 4)
       r =25
    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_ibl layout.get_info(layer)
      set_bl 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
      # fetch the parameters
	if larg
		f_ib = 3.5
		f_b = 3.0
	else
		f_b = 1.0
		f_ib = 1.0
	end
 
  # find the lib
lib = RBA::Library.library_by_name("Basic")
lib || raise("Unknown lib 'Basic'")
# find the pcell
pcell_decl = lib.layout.pcell_declaration("TEXT")
pcell_decl || raise("Unknown PCell 'TEXT'")
layer = ibl.layer
datatype = ibl.datatype
if !ibinv
param = {"text" => ibl.layer.to_s, "layer" =>RBA::LayerInfo::new(layer, datatype), "mag"=>f_b*15, "inverse"=> false}
pv = pcell_decl.get_parameters.collect do |p|
param[p.name] || p.default
end
# InBox
  pts3 = [ [ [-4.5*f_ib,6*f_ib],[-4.5*f_ib,8*f_ib],[4.5*f_ib,8*f_ib],[4.5*f_ib,6*f_ib] ],
          [ [-4.5*f_ib,-6*f_ib],[-4.5*f_ib,-8*f_ib],[4.5*f_ib,-8*f_ib],[4.5*f_ib,-6*f_ib] ],
          [ [-6*f_ib,4.5*f_ib],[-8*f_ib,4.5*f_ib],[-8*f_ib,-4.5*f_ib],[-6*f_ib,-4.5*f_ib] ],
          [ [6*f_ib,4.5*f_ib],[8*f_ib,4.5*f_ib],[8*f_ib,-4.5*f_ib],[6*f_ib,-4.5*f_ib] ] ]
    pts3.each { |pp|
     pointlist = []
      pp.each { |p| pointlist.push(Point.from_dpoint(DPoint.new( p[0]/layout.dbu, p[1]/layout.dbu ) )) }
           cell.shapes(ibl_layer).insert(Polygon.new(pointlist))
 }
else
param = {"text" => ibl.layer.to_s, "layer" =>RBA::LayerInfo::new(layer, datatype), "mag"=>f_b*15, "inverse"=> true}
pv = pcell_decl.get_parameters.collect do |p|
param[p.name] || p.default
end
    # InBox inverse
  pts3 = [ [-15.00000*f_b,-15.00000*f_b],
[-15.00000*f_b,15.00000*f_b],
[15.00000*f_b,15.00000*f_b],
[15.00000*f_b,8.00000*f_ib],
[-4.50000*f_ib,8.00000*f_ib],
[-4.50000*f_ib,6.00000*f_ib],
[4.50000*f_ib,6.00000*f_ib],
[4.50000*f_ib,8.00000*f_ib],
[15.00000*f_b,8.00000*f_ib],
[15.00000*f_b,4.50000*f_ib],
[-8.00000*f_ib,4.50000*f_ib],
[-8.00000*f_ib,-4.50000*f_ib],
[-6.00000*f_ib,-4.50000*f_ib],
[-6.00000*f_ib,4.50000*f_ib],
[6.00000*f_ib,4.50000*f_ib],
[6.00000*f_ib,-4.50000*f_ib],
[8.00000*f_ib,-4.50000*f_ib],
[8.00000*f_ib,4.50000*f_ib],
[15.00000*f_b,4.50000*f_ib],
[15.00000*f_b,-6.00000*f_ib],
[-4.50000*f_ib,-6.00000*f_ib],
[-4.50000*f_ib,-8.00000*f_ib],
[4.50000*f_ib,-8.00000*f_ib],
[4.50000*f_ib,-6.00000*f_ib],
[15.00000*f_b,-6.00000*f_ib],
[15.00000*f_b,-15.00000*f_b] ]
#    pts3.each { |pp|
     pointlist = []
      pts3.each { |p| pointlist.push(Point.from_dpoint(DPoint.new( p[0]/layout.dbu, p[1]/layout.dbu ) )) }
           cell.shapes(ibl_layer).insert(Polygon.new(pointlist))
# }
end
# create a PCell variant cell
pcell_var = cell.layout.add_pcell_variant(lib, pcell_decl.id, pv)
x = f_b*16.5/layout.dbu
y = f_b*3/layout.dbu
t = RBA::Trans::new(0,false, x, y)
pcell_inst = cell.insert(RBA::CellInstArray::new(pcell_var, t))
layerb = bl.layer
datatypeb = bl.datatype
if !binv
param = {"text" => bl.layer.to_s, "layer" =>RBA::LayerInfo::new(layerb, datatypeb), "mag"=>f_b*15, "inverse"=> false}
pv = pcell_decl.get_parameters.collect do |p|
param[p.name] || p.default
end
 #Box  
 
   pts2 = [ [ [-7.5,10],[-7.5,12],[7.5,12],[7.5,10] ],
          [ [-7.5,-10],[-7.5,-12],[7.5,-12],[7.5,-10] ],
          [ [-10,7.5],[-12,7.5],[-12,-7.5],[-10,-7.5] ],
          [ [10,7.5],[12,7.5],[12,-7.5],[10,-7.5] ] ]
    pts2.each { |pp|
     pointlist = []
      pp.each { |p| pointlist.push(Point.from_dpoint(DPoint.new( f_b*p[0]/layout.dbu, f_b*p[1]/layout.dbu ) )) }
           cell.shapes(bl_layer).insert(Polygon.new(pointlist))
 }
      
else   
  
param = {"text" => bl.layer.to_s, "layer" =>RBA::LayerInfo::new(layerb, datatypeb), "mag"=>f_b*15, "inverse"=> true}
pv = pcell_decl.get_parameters.collect do |p|
param[p.name] || p.default
end 
 #Box  inverse
 
   pts2 = [ [-15.00000,-15.00000],
[-15.00000,15.00000],
[-10.00000,15.00000],
[-10.00000,7.500000],
[-12.00000,7.500000],
[-12.00000,-7.500000],
[-10.00000,-7.500000],
[-10.00000,15.00000],
[7.500000,15.00000],
[7.500000,12.00000],
[-7.500000,12.00000],
[-7.500000,10.00000],
[7.500000,10.00000],
[7.500000,-10.00000],
[-7.500000,-10.00000],
[-7.500000,-12.00000],
[7.500000,-12.00000],
[7.500000,15.00000],
[12.00000,15.00000],
[12.00000,7.500000],
[10.00000,7.500000],
[10.00000,-7.500000],
[12.00000,-7.500000],
[12.00000,15.00000],
[15.00000,15.00000],
[15.00000,-15.00000]
   ]
 #   pts3.each { |pp|
     pointlist = []
      pts2.each { |p| pointlist.push(Point.from_dpoint(DPoint.new( f_b*p[0]/layout.dbu,f_b*p[1]/layout.dbu ) )) }
           cell.shapes(bl_layer).insert(Polygon.new(pointlist))
# }
 end   
pcell_var = cell.layout.add_pcell_variant(lib, pcell_decl.id, pv)
x = 16.5*f_b/layout.dbu
y = -13.5*f_b/layout.dbu
t = RBA::Trans::new(0,false, x, y)
pcell_inst = cell.insert(RBA::CellInstArray::new(pcell_var, t))
end
    
  
 #       cell.shapes(l_layer).insert(Polygon.new(pointlist))
  end
  # The library where we will put the PCell into 
  class  AligneControle < Library
  
    def initialize  
    
      # Set the description
      self.description = "Librairie alignement et controles"
      
      # Create the PCell declarations
      layout.register_pcell("BoxinBox", BoxinBox::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("AligneControle")
      
    end
  
  end
  
  # Instantiate and register the library
  AligneControle::new
  
end
</text>
</klayout-macro>                
                             
        
Comments
Hi gwondaleya,
that's amazing, thank you very much :-)
I have put the script on the server. You can download it here: bib_pcell.lym.
The "server" is actually a SVN repository already. I plan to give write access to forum users, so that could be a chance for further development of that library. Please let me know in case you object to that. I thought the code is intended to become public domain - otherwise you would not have posted it here :-)
Thank and best regards,
Matthias
Was indeed intented to become public. That's part of the spirit of GPL :-) isnt'it? You have written and released a master piece of software, so it appears to me normal to contribute when i can and with my modest ruby knowledge.
Joël
You're right :-)
Thank you,
Matthias