import pya
import os

base_dir = os.path.dirname(os.path.abspath(__file__))

# init vars
pixel_size = 20
shift_mult = 5
image_size = 4266 * pixel_size * 100 #calculate this directly (4266 and 4242 for shift_mult 5 and 3, respectively)
image_size_half = image_size / 2
image_dist = (shift_mult * 3 * 2 + 2) * pixel_size * 100
object_border = 0
#print(image_dist)


# create layout
layout = pya.Layout()
layout.dbu = 0.01
top = layout.create_cell("Top")
layer1_index = layout.insert_layer(pya.LayerInfo.new(1, 0))
layer2_index = layout.insert_layer(pya.LayerInfo.new(2, 0))
layer3_index = layout.insert_layer(pya.LayerInfo.new(3, 0))
layer4_index = layout.insert_layer(pya.LayerInfo.new(4, 0))
layer5_index = layout.insert_layer(pya.LayerInfo.new(5, 0))


# wafer limits
wafer = layout.create_cell("Wafer")
wafer_circle_limit = layout.create_cell("CIRCLE", "Basic", 
  { "actual_radius": 75000, "npoints": 256, "layer": pya.LayerInfo(5, 0)} )
wafer1_cell_border = layout.create_cell("DONUT", "Basic", 
  { "actual_radius1": 67500, "actual_radius2": 75000, "npoints": 256, "layer": pya.LayerInfo(1, 0)} )
wafer2_cell_border = layout.create_cell("DONUT", "Basic", 
  { "actual_radius1": 67500, "actual_radius2": 75000, "npoints": 256, "layer": pya.LayerInfo(2, 0)} )
wafer.insert(pya.CellInstArray(wafer_circle_limit.cell_index(), pya.Trans(0, 0)))
wafer.insert(pya.CellInstArray(wafer1_cell_border.cell_index(), pya.Trans(0, 0)))
wafer.insert(pya.CellInstArray(wafer2_cell_border.cell_index(), pya.Trans(0, 0)))

limit_region = pya.Region(wafer_circle_limit.begin_shapes_rec(layer5_index))

wafer1_fill_region = pya.Region()
wafer1_fill_region.insert(pya.Box(-7500000, -6850000 + 1750000, 7500000, -1 * (6850000 + 1850000))) #mount area fill

frame_width = 300000
square_width = 2000000
wafer1_fill_region.insert(pya.Box(image_size_half, image_size_half, image_size_half + square_width, image_size_half + square_width)) #encoder
wafer1_fill_region.insert(pya.Box(image_size_half, -1 * image_size_half, image_size_half + square_width, -1 * (image_size_half + square_width))) #encoder
wafer1_fill_region.insert(pya.Box(-1 * image_size_half, image_size_half, -1 * (image_size_half + square_width), image_size_half + square_width)) #encoder
wafer1_fill_region.insert(pya.Box(-1 * image_size_half, -1 * image_size_half, -1 * (image_size_half + square_width), -1 * (image_size_half + square_width))) #encoder
wafer.shapes(layer1_index).insert(limit_region & wafer1_fill_region)

wafer2_fill_region = pya.Region()
wafer2_fill_region.insert(pya.Box(-7500000, 6850000 - 1750000, 7500000, 6850000 + 1850000)) #mount area fill
wafer2_fill_region.insert(pya.Box(image_size_half, image_size_half, image_size_half + square_width, image_size_half + square_width)) #encoder
wafer2_fill_region.insert(pya.Box(image_size_half, -1 * image_size_half, image_size_half + square_width, -1 * (image_size_half + square_width))) #encoder
wafer2_fill_region.insert(pya.Box(-1 * image_size_half, image_size_half, -1 * (image_size_half + square_width), image_size_half + square_width)) #encoder
wafer2_fill_region.insert(pya.Box(-1 * image_size_half, -1 * image_size_half, -1 * (image_size_half + square_width), -1 * (image_size_half + square_width))) #encoder
wafer.shapes(layer2_index).insert(limit_region & wafer2_fill_region)

wafer.shapes(layer3_index).insert(pya.Box(-7500000, -6850000, 7500000, 6850000 - 1850000)) #printable area wafer 1
wafer.shapes(layer4_index).insert(pya.Box(-7500000, 6850000, 7500000, -1 * (6850000 - 1850000))) #printable area wafer 2

top.insert(pya.CellInstArray(wafer.cell_index(), pya.Trans(0, 0)))
layout.rename_cell(wafer.cell_index(), "Wafer_Border")

# def for circ grating
def gen_circ_grating(pitch, width, square_size, name):

  #create grating archetype for circ grating
  circ_grating = layout.create_cell("Circ_Grating")
  circ_grating_inv = layout.create_cell("Circ_Grating_Inv")

  i = 0
  while (i * pitch) < (8000):
    donut = layout.create_cell("DONUT", "Basic", 
      { "actual_radius1": (i * pitch), "actual_radius2": (i * pitch + width), "npoints": 256, "layer": pya.LayerInfo(1, 0)} )
    circ_grating.insert(pya.CellInstArray(donut.cell_index(), pya.Trans(0, 0)))
    i = i + 1
    
  i = 0
  while (i * pitch) < (8000):
    donut = layout.create_cell("DONUT", "Basic", 
      { "actual_radius1": (i * pitch) + width, "actual_radius2": (i * pitch + width) + width, "npoints": 256, "layer": pya.LayerInfo(2, 0)} )
    circ_grating_inv.insert(pya.CellInstArray(donut.cell_index(), pya.Trans(0, 0)))
    i = i + 1

  circ_grating_clip = layout.clip(circ_grating.cell_index(), pya.Box(-1 * square_size, -1 * square_size, square_size, square_size))
  circ_grating_inv_clip = layout.clip(circ_grating_inv.cell_index(), pya.Box(-1 * square_size, -1 * square_size, square_size, square_size))
  
  circ_grating.delete()
  circ_grating_inv.delete()
    
  layout.rename_cell(circ_grating_clip, name + "_Clip")
  layout.rename_cell(circ_grating_inv_clip, name + "_Inv_Clip")
  
  return [circ_grating_clip, circ_grating_inv_clip]


# verniers
linear_grating_vernier = layout.create_cell("Vernier")
base_period = image_size_half - 500000
revealing_period = image_dist
velocity_ratio = 1
pitch1 = (base_period * (revealing_period / velocity_ratio)) / (base_period - (revealing_period / velocity_ratio))
pitch2 = revealing_period / velocity_ratio
opening1 = 4000
#print(pitch1)
#print(pitch2)


frame_width = 300000

for i in range(-1 * int((image_size_half) / pitch1), int((image_size_half) / pitch1)):
  line = layout.create_cell("Line")
  line.shapes(layer2_index).insert(pya.Box(opening1 / 2, -1 * frame_width, pitch1 - opening1 / 2, 0))
  linear_grating_vernier.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i * pitch1, 0)))
  
for i in range(-1 * int((image_size_half - image_dist) / pitch2), int((image_size_half - image_dist) / pitch2)):
  line = layout.create_cell("Line")
  line.shapes(layer1_index).insert(pya.Box(opening1 / 2, -1 * frame_width, pitch2 - opening1 / 2, 0))
  linear_grating_vernier.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i * pitch2, 0)))

base_period = -1 * (image_size_half - 500000) 
revealing_period = image_dist
velocity_ratio = 5
pitch3 = (base_period * (revealing_period / velocity_ratio)) / (base_period - (revealing_period / velocity_ratio))
pitch4 = revealing_period / velocity_ratio
opening2 = 800
  
for i in range(-1 * int(image_size_half / pitch3), int(image_size_half / pitch3)):
  line = layout.create_cell("Line")
  line.shapes(layer2_index).insert(pya.Box(opening2 / 2, 0, pitch3 - opening2 / 2, frame_width))
  linear_grating_vernier.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i * pitch3, 0)))
  

for i in range(-1 * int((image_size_half - image_dist) / pitch4), int((image_size_half - image_dist) / pitch4)):
  line = layout.create_cell("Line")
  line.shapes(layer1_index).insert(pya.Box(opening2 / 2, 0, pitch4 - opening2 / 2, frame_width))
  linear_grating_vernier.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i * pitch4, 0)))

line = layout.create_cell("Line")
line.shapes(layer2_index).insert(pya.Box(image_size_half - (2 * image_dist), -1 * frame_width, image_size_half, 0))
line.shapes(layer2_index).insert(pya.Box(-1 * (image_size_half - (2 * image_dist)), -1 * frame_width, -1 * (image_size_half), 0))
line.shapes(layer2_index).insert(pya.Box(image_size_half - (2 * image_dist), image_dist, image_size_half, image_dist + frame_width))
line.shapes(layer2_index).insert(pya.Box(-1 * (image_size_half - (2 * image_dist)), image_dist, -1 * (image_size_half), image_dist + frame_width))

#These four lines can be taken away to get rid of the bounding black out
line.shapes(layer2_index).insert(pya.Box(-1 * image_size_half, image_dist, image_size_half, 0 - image_dist))
line.shapes(layer2_index).insert(pya.Box(-1 * image_size_half, -1 * (frame_width - image_dist), image_size_half, -1 * (frame_width + image_dist)))
line.shapes(layer2_index).insert(pya.Box(-1 * image_size_half, 0, image_size_half, image_dist))
line.shapes(layer2_index).insert(pya.Box(-1 * image_size_half, frame_width + (1 * image_dist), image_size_half, frame_width - image_dist))
linear_grating_vernier.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, 0)))

  
line = layout.create_cell("Line")
line.shapes(layer1_index).insert(pya.Box(image_size_half - image_dist, -1 * frame_width, image_size_half - (2 * image_dist), 0))
line.shapes(layer1_index).insert(pya.Box(-1 * (image_size_half - image_dist), -1 * frame_width, -1 * (image_size_half - (2 * image_dist)), 0))
line.shapes(layer1_index).insert(pya.Box(image_size_half - image_dist, 0, image_size_half - (2 * image_dist), frame_width))
line.shapes(layer1_index).insert(pya.Box(-1 * (image_size_half - image_dist), 0, -1 * (image_size_half - (2 * image_dist)), frame_width))
linear_grating_vernier.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, 0)))
  
vernier_extent = image_size_half + object_border + frame_width + image_dist
top.insert(pya.CellInstArray(linear_grating_vernier.cell_index(), pya.Trans(3, False, vernier_extent, 0)))
top.insert(pya.CellInstArray(linear_grating_vernier.cell_index(), pya.Trans(1, False, -1 * vernier_extent, 0)))
top.insert(pya.CellInstArray(linear_grating_vernier.cell_index(), pya.Trans(0, False, 0, vernier_extent)))
top.insert(pya.CellInstArray(linear_grating_vernier.cell_index(), pya.Trans(2, False,  0, -1 * vernier_extent)))
vernier_extent = vernier_extent + frame_width + image_dist


# linear grating unison for rotational alignment
linear_grating_uni = layout.create_cell("Linear_Grating_Uni")
pitch = 2000
line_width = 1000
frame_width = 300000 / 2
line_length = image_size_half - 500000

i = -1 * frame_width
while (i) < (frame_width):
  line = layout.create_cell("Line")
  line.shapes(layer1_index).insert(pya.Box(0, -1 * line_length, line_width, line_length))
  linear_grating_uni.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i, 0)))
  i = i + pitch
  
i = -1 * frame_width
shift =  line_width
while (i) < (frame_width):
  line = layout.create_cell("Line")
  line.shapes(layer2_index).insert(pya.Box(0, -1 * line_length, line_width, line_length))
  linear_grating_uni.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i + shift, 0)))
  i = i + pitch
  
unison_rot_extent = vernier_extent + object_border + frame_width + image_dist
top.insert(pya.CellInstArray(linear_grating_uni.cell_index(), pya.Trans(2, False, unison_rot_extent, 0)))
top.insert(pya.CellInstArray(linear_grating_uni.cell_index(), pya.Trans(0, False, -1 * unison_rot_extent, 0)))
unison_rot_extent = unison_rot_extent + frame_width + image_dist


# 9 * 9 grid with larger squares
circ_grating_square_array_2 = layout.create_cell("Circ_Grating_Square_Array_2")
square_dist = 400000
pitch = 10
width = 5
square_size = (square_dist / 2) - 20000
[circ_grating_square_array_clip, circ_grating_square_array_inv_clip] = gen_circ_grating(pitch, width, square_size, "Circ_Grating_2")

for r in range(-1, 2):
  for c in range(-1, 2):
    circ_grating_square_array_2.insert(pya.CellInstArray(circ_grating_square_array_clip, pya.Trans(0, False, square_dist * r, square_dist * c)))
    circ_grating_square_array_2.insert(pya.CellInstArray(circ_grating_square_array_inv_clip, pya.Trans(0, False, square_dist * r + (r * image_dist), square_dist * c + (c * image_dist))))
    
grid_extent = unison_rot_extent + square_size + square_dist + image_dist
y_offset = square_dist + image_dist + (square_size)
top.insert(pya.CellInstArray(circ_grating_square_array_2.cell_index(), pya.Trans(2, False, grid_extent, 0)))
top.insert(pya.CellInstArray(circ_grating_square_array_2.cell_index(), pya.Trans(0, False, -1 * grid_extent, 0)))

# verniers md course
linear_grating_vernier_md_course = layout.create_cell("Vernier_md_course")
square_size = 650000
fray = 0 
line_length = square_size / 2 + fray
velocity_ratio = 2
pitch1 = ((square_size * 1) * (image_dist / velocity_ratio)) / ((square_size * 1) - (image_dist / velocity_ratio))
pitch2 = image_dist / velocity_ratio
opening = 8000

for i in range(-1 * int(square_size / 2 / pitch1) - 0, int(square_size / 2 / pitch1) + 0):

  line = layout.create_cell("Line")
  line.shapes(layer2_index).insert(pya.Box(opening / 2, -1 * line_length, pitch1 - opening / 2, line_length))
  linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i * pitch1, 0)))
  linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, False, 0, (i * pitch1))))
  
for i in range(-1 * int(square_size / 2 / pitch2) - 0, int(square_size / 2 / pitch2) + 0):

  line = layout.create_cell("Line")
  line.shapes(layer1_index).insert(pya.Box(opening / 2, -1 * line_length, pitch2 - opening / 2, line_length))
  linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i * pitch2, 0)))
  linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, False, 0, (i * pitch2))))
  
line = layout.create_cell("Line")
line.shapes(layer2_index).insert(pya.Box(-1 * (square_size / 2 + (1 * image_dist)), square_size / 2 - image_dist, square_size / 2 + (1 * image_dist), square_size / 2 + (1 * image_dist)))
linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, 0)))

line = layout.create_cell("Line")
line.shapes(layer2_index).insert(pya.Box(-1 * (square_size / 2 + (1 * image_dist)), square_size / 2 - image_dist, square_size / 2 + (0 * image_dist), square_size / 2 + (1 * image_dist)))
#linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, 0)))
linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, False, 0, 0)))
linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(2, False, 0, 0)))
linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, True, 0, 0)))

line = layout.create_cell("Line")
line.shapes(layer1_index).insert(pya.Box(-1 * (square_size / 2 + (1 * image_dist)), square_size / 2, square_size / 2 + (1 * image_dist), square_size / 2 + (0 * image_dist)))
linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, 0)))
linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, False, 0, 0)))
linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(2, False, 0, 0)))
linear_grating_vernier_md_course.insert(pya.CellInstArray(line.cell_index(), pya.Trans(3, False, 0, 0)))
  
triangle = layout.create_cell("Triangle")
triangle.shapes(layer2_index).insert(pya.Polygon([pya.Point(-45000, -1 * image_dist), pya.Point(45000, -1 * image_dist), pya.Point(0, 0)]))
linear_grating_vernier_md_course.insert(pya.CellInstArray(triangle.cell_index(), pya.Trans(0, False, 0, -1 * (square_size / 2 + (image_dist * 1)))))
linear_grating_vernier_md_course.insert(pya.CellInstArray(triangle.cell_index(), pya.Trans(1, False, (square_size / 2 + (image_dist * 1)), 0)))

grid_extent = unison_rot_extent + (square_size / 2) + (image_dist * 1)
y_offset = y_offset + (square_size / 2) + (image_dist * 3)
top.insert(pya.CellInstArray(linear_grating_vernier_md_course.cell_index(), pya.Trans(0, False, (grid_extent + fray), (y_offset + fray))))
top.insert(pya.CellInstArray(linear_grating_vernier_md_course.cell_index(), pya.Trans(0, True, (grid_extent + fray), -1 * (y_offset + fray))))
top.insert(pya.CellInstArray(linear_grating_vernier_md_course.cell_index(), pya.Trans(2, False, -1 * (grid_extent + fray), -1 * (y_offset + fray))))
top.insert(pya.CellInstArray(linear_grating_vernier_md_course.cell_index(), pya.Trans(2, True, -1 * (grid_extent + fray), (y_offset + fray))))


# verniers md fine
linear_grating_vernier_md_fine = layout.create_cell("Vernier_md_fine")
square_size = 650000
fray = 0 
line_length = square_size / 2 + fray
velocity_ratio = 3
pitch1 = ((square_size * -1) * (image_dist / velocity_ratio)) / ((square_size * -1) - (image_dist / velocity_ratio))
pitch2 = image_dist / velocity_ratio
opening = 8000 * 2/3

for i in range(-1 * int(square_size / 2 / pitch1) - 0, int(square_size / 2 / pitch1) + 0):

  line = layout.create_cell("Line")
  line.shapes(layer2_index).insert(pya.Box(opening / 2, -1 * line_length, pitch1 - opening / 2, line_length))
  linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i * pitch1, 0)))
  linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, False, 0, (i * pitch1))))
  
for i in range(-1 * int(square_size / 2 / pitch1) - 0, int(square_size / 2 / pitch1) + 0):

  line = layout.create_cell("Line")
  line.shapes(layer1_index).insert(pya.Box(opening / 2, -1 * line_length, pitch2 - opening / 2, line_length))
  linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(i * pitch2, 0)))
  linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, False, 0, (i * pitch2))))
  
line = layout.create_cell("Line")
line.shapes(layer2_index).insert(pya.Box(-1 * (square_size / 2 + (1 * image_dist)), square_size / 2 - image_dist, square_size / 2 + (1 * image_dist), square_size / 2 + (1 * image_dist)))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, 0)))

line = layout.create_cell("Line")
line.shapes(layer2_index).insert(pya.Box(-1 * (square_size / 2 + (1 * image_dist)), square_size / 2 - image_dist, square_size / 2 + (0 * image_dist), square_size / 2 + (1 * image_dist)))
#linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, 0)))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, False, 0, 0)))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(2, False, 0, 0)))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, True, 0, 0)))

line = layout.create_cell("Line")
line.shapes(layer1_index).insert(pya.Box(-1 * (square_size / 2 + (1 * image_dist)), square_size / 2, square_size / 2 + (1 * image_dist), square_size / 2 + (0 * image_dist)))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, 0)))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(1, False, 0, 0)))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(2, False, 0, 0)))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(line.cell_index(), pya.Trans(3, False, 0, 0)))
  
triangle = layout.create_cell("Triangle")
triangle.shapes(layer2_index).insert(pya.Polygon([pya.Point(-45000, -1 * image_dist), pya.Point(45000, -1 * image_dist), pya.Point(0, 0)]))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(triangle.cell_index(), pya.Trans(0, False, 0, -1 * (square_size / 2 + (image_dist * 1)))))
linear_grating_vernier_md_fine.insert(pya.CellInstArray(triangle.cell_index(), pya.Trans(1, False, (square_size / 2 + (image_dist * 1)), 0)))

  
grid_extent = unison_rot_extent + (square_size / 2) + (image_dist * 1)
y_offset = y_offset + square_size + (image_dist * 1)

top.insert(pya.CellInstArray(linear_grating_vernier_md_course.cell_index(), pya.Trans(0, True, (grid_extent + fray), (y_offset + fray))))
top.insert(pya.CellInstArray(linear_grating_vernier_md_course.cell_index(), pya.Trans(0, False, (grid_extent + fray), -1 * (y_offset + fray))))
top.insert(pya.CellInstArray(linear_grating_vernier_md_course.cell_index(), pya.Trans(2, True, -1 * (grid_extent + fray), -1 * (y_offset + fray))))
top.insert(pya.CellInstArray(linear_grating_vernier_md_course.cell_index(), pya.Trans(2, False, -1 * (grid_extent + fray), (y_offset + fray))))
y_offset = y_offset + (square_size / 2) + (image_dist * 3)

# larger squares only in the unison position
circ_grating_uni = layout.create_cell("Circ_Grating_Uni")
pitch = 20
width = 10
square_size = 530000 / 2
[circ_grating_uni_clip, circ_grating_uni_inv_clip] = gen_circ_grating(pitch, width, square_size, "Circ_Grating_3")

circ_grating_uni.insert(pya.CellInstArray(circ_grating_uni_clip, pya.Trans(0, False, 0, 0)))
circ_grating_uni.insert(pya.CellInstArray(circ_grating_uni_inv_clip, pya.Trans(0, False, 0, 0)))

grid_extent = unison_rot_extent + square_size + image_dist
y_offset = y_offset + (square_size / 1)
top.insert(pya.CellInstArray(circ_grating_uni.cell_index(), pya.Trans(0, False, grid_extent, -1 * y_offset)))
top.insert(pya.CellInstArray(circ_grating_uni.cell_index(), pya.Trans(0, False, -1 * grid_extent, -1 * y_offset)))
top.insert(pya.CellInstArray(circ_grating_uni.cell_index(), pya.Trans(0, False, grid_extent, y_offset)))
top.insert(pya.CellInstArray(circ_grating_uni.cell_index(), pya.Trans(0, False, -1 * grid_extent, y_offset)))
 

#top.insert(pya.CellInstArray(linear_grating_encoder_clip, pya.Trans(0, False, image_size_half, image_size_half)))

# linear grating encoder for optional optosensor
def gen_encoder_grating(alg_layout, cell):
  frame_width = 300000
  linear_grating_encoder_1 = alg_layout.create_cell("Linear_Grating_Encoder_1")
  linear_grating_encoder_2 = alg_layout.create_cell("Linear_Grating_Encoder_2")
  pitch = 1000
  line_width = 500
  square_width = (frame_width * 2) + (image_dist * 2)
  square_width  = 2000000
  line_length = square_width
  
  i = -1 * square_width
  while (i) < (square_width):
    line = alg_layout.create_cell("Line")
    line.shapes(layer1_index).insert(pya.Box(line_width, 0, -1 * square_width, line_width))
    line.shapes(layer1_index).insert(pya.Box(0, 0, line_width, -1 * square_width))
    linear_grating_encoder_1.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, False, i, i)))
    line = alg_layout.create_cell("Line")
    line.shapes(layer2_index).insert(pya.Box(line_width, 0, -1 * square_width, line_width))
    line.shapes(layer2_index).insert(pya.Box(0, 0, line_width, -1 * square_width))
    linear_grating_encoder_2.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, False, i, i)))
    i = i + pitch
    
  i = -1 * square_width
  shift =  line_width
  while (i) < (frame_width + image_dist):
    line = alg_layout.create_cell("Line")
    line.shapes(layer2_index).insert(pya.Box(line_width, 0, -1 * square_width, line_width))
    line.shapes(layer2_index).insert(pya.Box(0, 0, line_width, -1 * square_width))
    linear_grating_encoder_1.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, False, i + shift, i + shift)))
    line = alg_layout.create_cell("Line")
    line.shapes(layer1_index).insert(pya.Box(line_width, 0, -1 * square_width, line_width))
    line.shapes(layer1_index).insert(pya.Box(0, 0, line_width, -1 * square_width))
    linear_grating_encoder_2.insert(pya.CellInstArray(line.cell_index(), pya.Trans(0, False, i + shift, i + shift)))
    i = i + pitch
    
    
  inner_clip_2 = alg_layout.clip(linear_grating_encoder_2.cell_index(), pya.Box(0, 0, frame_width + image_dist, frame_width + image_dist)) 
  linear_grating_encoder_clip_2 = alg_layout.clip(linear_grating_encoder_2.cell_index(), pya.Box(0, 0, square_width, square_width)) 
  
  cell.insert(pya.CellInstArray(linear_grating_encoder_clip_2, pya.Trans(0, False, image_size_half, image_size_half)))
  cell.insert(pya.CellInstArray(inner_clip_2, pya.Trans(0, False, image_size_half + frame_width + image_dist, image_size_half + frame_width + image_dist)))
  
  cell.insert(pya.CellInstArray(linear_grating_encoder_clip_2, pya.Trans(1, False, -1 * image_size_half, image_size_half)))
  cell.insert(pya.CellInstArray(inner_clip_2, pya.Trans(1, False, -1 * (image_size_half + frame_width + image_dist), image_size_half + frame_width + image_dist)))
  
  inner_clip_1 = alg_layout.clip(linear_grating_encoder_1.cell_index(), pya.Box(0, 0, frame_width + image_dist, frame_width + image_dist)) 
  linear_grating_encoder_clip_1 = alg_layout.clip(linear_grating_encoder_1.cell_index(), pya.Box(0, 0, square_width, square_width)) 
  
  cell.insert(pya.CellInstArray(linear_grating_encoder_clip_1, pya.Trans(2, False, -1 * image_size_half, -1 * image_size_half)))
  cell.insert(pya.CellInstArray(inner_clip_1, pya.Trans(2, False, -1 * (image_size_half + frame_width + image_dist), -1 * (image_size_half + frame_width + image_dist))))

  cell.insert(pya.CellInstArray(linear_grating_encoder_clip_1, pya.Trans(3, False, image_size_half, -1 * image_size_half)))
  cell.insert(pya.CellInstArray(inner_clip_1, pya.Trans(3, False, image_size_half + frame_width + image_dist, -1 * (image_size_half + frame_width + image_dist))))
  
  cell.flatten(1)
  alg_layout.prune_cell(linear_grating_encoder_1.cell_index(), -1)
  alg_layout.prune_cell(linear_grating_encoder_2.cell_index(), -1)

top.flatten(1)

wafer1_region1 = pya.Region(top.begin_shapes_rec(layer1_index))
wafer1_region2 = pya.Region(top.begin_shapes_rec(layer3_index))

wafer2_region1 = pya.Region(top.begin_shapes_rec(layer2_index))
wafer2_region2 = pya.Region(top.begin_shapes_rec(layer4_index))


alignment_layout = pya.Layout()
alignment = alignment_layout.create_cell("Alignment")
alignment_layout.dbu = 0.01
layer1_index = alignment_layout.insert_layer(pya.LayerInfo.new(1, 0))
layer2_index = alignment_layout.insert_layer(pya.LayerInfo.new(2, 0))

encode_region = pya.Region()
square_width = 2000000
encode_region.insert(pya.Box(image_size_half, image_size_half, image_size_half + square_width, image_size_half + square_width)) #encoder
encode_region.insert(pya.Box(image_size_half, -1 * image_size_half, image_size_half + square_width, -1 * (image_size_half + square_width))) #encoder
encode_region.insert(pya.Box(-1 * image_size_half, image_size_half, -1 * (image_size_half + square_width), image_size_half + square_width)) #encoder
encode_region.insert(pya.Box(-1 * image_size_half, -1 * image_size_half, -1 * (image_size_half + square_width), -1 * (image_size_half + square_width))) #encoder

alignment.shapes(layer1_index).insert((wafer1_region1 & wafer1_region2) - encode_region) 
alignment.shapes(layer2_index).insert((wafer2_region1 & wafer2_region2) - encode_region) 

gen_encoder_grating(alignment_layout, alignment)
#alignment_layout.transform(pya.Trans(2, False, 0, 0))

alignment_layout.write(os.path.join(base_dir, "..", "gds", "alignment_marks_overlapped.gds"))

alignment_inv_layout = pya.Layout()
alignment_inv = alignment_inv_layout.create_cell("Alignment_Inverse")
alignment_inv_layout.dbu = 0.01
layer1_index = alignment_inv_layout.insert_layer(pya.LayerInfo.new(1, 0))
layer2_index = alignment_inv_layout.insert_layer(pya.LayerInfo.new(2, 0))

alignment_inv.shapes(layer1_index).insert(wafer1_region2 - wafer1_region1) 
alignment_inv.shapes(layer2_index).insert(wafer2_region2 - wafer2_region1) 
  
gen_encoder_grating(alignment_inv_layout, alignment_inv)
#alignment_inv_layout.transform(pya.Trans(2, False, 0, 0))

alignment_inv_layout.write(os.path.join(base_dir, "..", "gds", "inverted_tonality", "alignment_marks_overlapped_inverse.gds"))
