def init_regions( self ): self.P0 = DPoint( 0,0 ) self.P1 = self.P0 + DPoint( self.Z1.gap,0 ) self.P2 = self.P1 + DPoint( self.Z1.width,0 ) self.P3 = self.P2 + DPoint( 0,self.Z1.gap ) self.P4 = self.P2 + DPoint( self.Z1.gap, self.Z2.gap ) self.P5 = self.P4 + DPoint( 0,self.Z2.width ) self.P6 = DPoint( 0, self.Z1.gap + self.Z1.width ) self.P7 = DPoint( 0, self.Z1.gap ) self.P8 = self.P7 + DPoint( self.Z1.gap,0 ) self.P9 = self.P2 + DPoint( self.Z1.gap,0 ) self.P10 = self.P5 + DPoint( 0, self.Z2.gap ) self.P11 = self.P10 - DPoint( 2*self.Z1.gap + self.Z1.width, 0 ) self.P12 = self.P6 + DPoint( 0, self.Z1.gap ) self.connections = [(self.P6 + self.P7)*0.5,(self.P1 + self.P2)*0.5,(self.P5 + self.P4)*0.5] self.angle_connections = [0,3/2*pi,0] self.metal_polygon = DPolygon( [self.P1,self.P2,self.P3,self.P4,self.P5,self.P6,self.P7,self.P8] ) self.empty1_polygon = DPolygon( [self.P0,self.P1,self.P8,self.P7] ) self.empty2_polygon = DPolygon( [self.P2,self.P9,self.P4,self.P3] ) self.empty3_polygon = DPolygon( [self.P5,self.P10,self.P12,self.P6] ) self.gnd_polygon = DPolygon( [self.P10,self.P11,self.P12] ) self.metal_region = pya.Region( list(map(pya.Polygon().from_dpoly,[self.metal_polygon,self.gnd_polygon])) ) self.empty_region = pya.Region( list(map(pya.Polygon().from_dpoly ,[self.empty1_polygon,self.empty2_polygon,self.empty3_polygon])) )
def produce_impl(self): # fetch the parameters dbu = self.layout.dbu tg = math.tan(math.radians(self.a / 2)) # compute the bowtie pts = [] pts.append( pya.Point(pya.DPoint((-self.lb / 2) / dbu, (self.wb / 2) / dbu))) pts.append( pya.Point( pya.DPoint((-self.lb / 2 - self.lw) / dbu, (self.wb / 2 + self.lw * tg) / dbu))) pts.append( pya.Point( pya.DPoint((-self.lb / 2 - self.lw) / dbu, (-self.wb / 2 - self.lw * tg) / dbu))) pts.append( pya.Point(pya.DPoint((-self.lb / 2) / dbu, -(self.wb / 2) / dbu))) self.cell.shapes(self.l_layer).insert(pya.Polygon(pts)) pts = [] pts.append( pya.Point(pya.DPoint((self.lb / 2) / dbu, -(self.wb / 2) / dbu))) pts.append( pya.Point( pya.DPoint((self.lb / 2 + self.lw) / dbu, (-self.wb / 2 - self.lw * tg) / dbu))) pts.append( pya.Point( pya.DPoint((self.lb / 2 + self.lw) / dbu, (self.wb / 2 + self.lw * tg) / dbu))) pts.append( pya.Point(pya.DPoint((self.lb / 2) / dbu, (self.wb / 2) / dbu))) self.cell.shapes(self.l_layer).insert(pya.Polygon(pts))
def produce_impl(self): dbu = self.layout.dbu cross = [] cross.append( pya.Point.from_dpoint( pya.DPoint(self.w / (2 * dbu), self.w / (2 * dbu)))) cross.append( pya.Point.from_dpoint(pya.DPoint(self.l1 / dbu, self.w / (2 * dbu)))) cross.append( pya.Point.from_dpoint( pya.DPoint(self.l1 / dbu, -self.w / (2 * dbu)))) cross.append( pya.Point.from_dpoint( pya.DPoint(self.w / (2 * dbu), -self.w / (2 * dbu)))) cross.append( pya.Point.from_dpoint( pya.DPoint(self.w / (2 * dbu), -self.l2 / dbu))) cross.append( pya.Point.from_dpoint( pya.DPoint(-self.w / (2 * dbu), -self.l2 / dbu))) cross.append( pya.Point.from_dpoint( pya.DPoint(-self.w / (2 * dbu), -self.w / (2 * dbu)))) cross.append( pya.Point.from_dpoint( pya.DPoint(-self.l1 / dbu, -self.w / (2 * dbu)))) cross.append( pya.Point.from_dpoint( pya.DPoint(-self.l1 / dbu, self.w / (2 * dbu)))) cross.append( pya.Point.from_dpoint( pya.DPoint(-self.w / (2 * dbu), self.w / (2 * dbu)))) cross.append( pya.Point.from_dpoint( pya.DPoint(-self.w / (2 * dbu), self.l2 / dbu))) cross.append( pya.Point.from_dpoint(pya.DPoint(self.w / (2 * dbu), self.l2 / dbu))) if not self.inv: self.cell.shapes(self.l_layer).insert(pya.Polygon(cross)) else: boundary = [] boundary.append( pya.Point.from_dpoint( pya.DPoint(-self.b1 / (2 * dbu), -self.b2 / (2 * dbu)))) boundary.append( pya.Point.from_dpoint( pya.DPoint(self.b1 / (2 * dbu), -self.b2 / (2 * dbu)))) boundary.append( pya.Point.from_dpoint( pya.DPoint(self.b1 / (2 * dbu), self.b2 / (2 * dbu)))) boundary.append( pya.Point.from_dpoint( pya.DPoint(-self.b1 / (2 * dbu), self.b2 / (2 * dbu)))) poly = pya.Polygon(boundary) poly.insert_hole(cross) self.cell.shapes(self.l_layer).insert(poly)
def test_1_Trans(self): a = pya.Trans() b = pya.Trans( pya.Trans.M135, pya.Point( 17, 5 )) c = pya.Trans( 3, True, pya.Point( 17, 5 )) d = pya.Trans( pya.Point( 17, 5 )) e = pya.Trans( pya.Trans.M135 ) e2 = pya.Trans.from_dtrans( pya.DTrans.M135 ) f = pya.Trans( pya.DTrans( pya.DTrans.M135, pya.DPoint( 17, 5 )) ) self.assertEqual( str(a), "r0 0,0" ) self.assertEqual( str(pya.Trans.from_s(str(a))), str(a) ) self.assertEqual( str(b), "m135 17,5" ) self.assertEqual( str(c), "m135 17,5" ) self.assertEqual( str(d), "r0 17,5" ) self.assertEqual( str(e), "m135 0,0" ) self.assertEqual( str(e2), "m135 0,0" ) self.assertEqual( str(f), "m135 17,5" ) self.assertEqual( str(pya.Trans.from_s(str(f))), str(f) ) self.assertEqual( str(b.trans( pya.Point( 1, 0 ))), "17,4" ) self.assertEqual( a == b, False ) self.assertEqual( a == a, True ) self.assertEqual( a != b, True ) self.assertEqual( a != a, False ) self.assertEqual( (d * e) == b, True ) self.assertEqual( (e * d) == b, False ) i = c.inverted() self.assertEqual( str(i), "m135 5,17" ) self.assertEqual( (i * b) == a, True ) self.assertEqual( (b * i) == a, True ) c = pya.Trans( 3, True, pya.Point( 17, 5 )) self.assertEqual( str(c), "m135 17,5" ) c.disp = pya.Point(1, 7) self.assertEqual( str(c), "m135 1,7" ) c.angle = 1 self.assertEqual( str(c), "m45 1,7" ) c.rot = 3 self.assertEqual( str(c), "r270 1,7" ) c.mirror = True self.assertEqual( str(c), "m135 1,7" ) self.assertEqual( str(e.trans( pya.Edge(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(( e * pya.Edge(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(e.trans( pya.Box(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(( e * pya.Box(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(e.trans( pya.Text("text", pya.Vector(0, 1)) )), "('text',m135 -1,0)" ) self.assertEqual( str(( e * pya.Text("text", pya.Vector(0, 1)) )), "('text',m135 -1,0)" ) self.assertEqual( str(e.trans( pya.Polygon( [ pya.Point(0, 1), pya.Point(2, -3), pya.Point(4, 5) ] ) )), "(-5,-4;-1,0;3,-2)" ) self.assertEqual( str(( e * pya.Polygon( [ pya.Point(0, 1), pya.Point(2, -3), pya.Point(4, 5) ] ) )), "(-5,-4;-1,0;3,-2)" ) self.assertEqual( str(e.trans( pya.Path( [ pya.Point(0, 1), pya.Point(2, 3) ], 10 ) )), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false" ) self.assertEqual( str(( e * pya.Path( [ pya.Point(0, 1), pya.Point(2, 3) ], 10 ) )), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false" )
def vernier(self, width, length, pitch): ''' vernier(width, length, pitch) Generates a vernier scale Parameters --------- width : integer The width of each tick marker length : integer The length of the central tick mark The major tick marks are 3/4 this length The minor tick marks are half this length pitch : integer The distance between each tick mark Returns ------ region : [pya.Region] A region containing the vernier scale Description --------- A pair of vernier scale can be used to measure misalignment by eye. In photolithography the wafer will contain one vernier pattern (width = 4, length = 40, pitch = 8, units = micron) and the mask will contain a second vernier pattern (pitch = 8.2) providing an alignment measurement resolution of 0.2 micron. ''' scaleM = 0.75 scaleS = 0.5 # Create the large tick mark polygons = [] #tick = pya.Polygon([pya.Point(0,0), pya.Point(length,0), pya.Point(length,width), pya.Point(0,width)]) tick = pya.Polygon([pya.Point(0,0), pya.Point(0,width), pya.Point(length,width), pya.Point(length,0)]) tc = pya.ICplxTrans(int(-length/2),int(-width/2)) polygons.append(tc.trans(tick)) # Create the medium tick mark #tickm = pya.Polygon([pya.Point(0,0), pya.Point(length*scaleM,0), pya.Point(length*scaleM,width), pya.Point(0,width)]) tickm = pya.Polygon([pya.Point(0,0), pya.Point(0,width), pya.Point(length*scaleM,width), pya.Point(length*scaleM,0)]) pos = [-2, -1, 1, 2] for i in pos: tt = pya.ICplxTrans(0,int(i*pitch*5)) polygons.append(tc.trans(tt.trans(tickm))) # Create the small tick mark #ticks = pya.Polygon([pya.Point(0,0), pya.Point(length*scaleS,0), pya.Point(length*scaleS,width), pya.Point(0,width)]) ticks = pya.Polygon([pya.Point(0,0), pya.Point(0,width), pya.Point(length*scaleS,width), pya.Point(length*scaleS,0)]) pos = [-9, -8, -7, -6, -4, -3, -2, -1, 1, 2, 3, 4, 6, 7, 8, 9] for i in pos: tt = pya.ICplxTrans(0,int(i*pitch)) polygons.append(tc.trans(tt.trans(ticks))) return pya.Region(polygons)
def pieceHolderCassette(self, dbu=1): ''' pieceHolderCassette() Generates the shape of the Jeol JBX-5500FS piece holder cassette Parameters --------- dbu : double The database unit Returns ------ region : [pya.Region] A region containing the piece holder cassette shape Description ------ The center of this piece holder shape (0,0) is at stage position (62.5mm, 37.5mm) Jeol Stage Y axis is reverse of KLayout Y axis ''' # Create the quarter circle r = 36100 / dbu rx = 62500 / dbu ry = -37500 / dbu polygon = pya.Polygon([ pya.Point(-r, -r), pya.Point(-r, r), pya.Point(r, r), pya.Point(r, -r) ]) polygon = polygon.round_corners(0, r, 128) rectangle = pya.Polygon([ pya.Point(-r, 0), pya.Point(-r, r), pya.Point(r, r), pya.Point(r, 0) ]) tt = pya.ICplxTrans(1, 90, False, 0, 0) qCircle = pya.Region(polygon) - pya.Region(rectangle) - pya.Region( rectangle.transform(tt)) # Create the trapezoid trapezoid = pya.Polygon([ pya.Point(49500 / dbu, -70500 / dbu), pya.Point(40500 / dbu, -20500 / dbu), pya.Point(60500 / dbu, -20500 / dbu), pya.Point(51500 / dbu, -70500 / dbu) ]) tt = pya.ICplxTrans(-rx, -ry) cassette = qCircle + pya.Region(trapezoid.transform(tt)) return cassette
def ring(self, outerDiameter, innerDiameter, vertices=128, fracture=True): ''' circle(outerDiameter, innerDiameter, vertices) Generates a circle shape Parameters --------- outerDiameter : integer The outer diameter of the ring innerDiameter : integer The inner diameter of the ring vertices : integer (128) Number of vertices in the circle (coerce to multiples of 4) fracture : boolean (True) Create the inner polygon with vertices that is optimal for fracturing horizontally Returns ------ region : [pya.Region] A region containing the circle shape ''' ro = int(outerDiameter / 2) ri = int(innerDiameter / 2) vertices = int(vertices / 4) * 4 # Create a circle polygon = pya.Polygon([ pya.Point(-ro, -ro), pya.Point(-ro, ro), pya.Point(ro, ro), pya.Point(ro, -ro) ]) polygonOuter = polygon.round_corners(0, ro, vertices) polygon = pya.Polygon([ pya.Point(-ri, -ri), pya.Point(-ri, ri), pya.Point(ri, ri), pya.Point(ri, -ri) ]) if fracture: points = polygonOuter.each_point_hull() polygonInnerPoints = [] r2 = np.power(ri, 2) for point in points: if (ri > np.absolute(point.y)): x = np.sqrt(r2 - np.power(point.y, 2)) polygonInnerPoints.append( pya.Point(np.sign(point.x) * x, point.y)) polygonInner = pya.Polygon(polygonInnerPoints) else: polygonInner = polygon.round_corners(0, ri, vertices) return pya.Region(polygonOuter) - pya.Region(polygonInner)
def siWafer(self, diameter, primaryFlat, secondaryFlat, angle, vertices = 128): ''' siWafer(diameter, secondaryFlatAngle) Generates a Silicon Wafer shape Parameters --------- diameter : integer The diameter of a standard silicon wafer primaryFlat : integer The length of the primary flat secondaryFlat : integer The length of the secondary flat angle : double The location of the secondary flat relative (counterclockwise) to primary flat vertices : integer (coerce to even number) The number of vertices used to generate the circle Returns ------ region : [pya.Region] A region containing the Si Wafer shape Description --------- SEMI Wafer Flat M1-0302 Specification Wafer Size = [2", 3", 100mm, 125mm, 150mm, 200mm, 300mm] Diameter [mm] = [50.8, 76.2, 100, 125, 150, 200, 300] Thickness [um] = [279, 381, 525 or 625, 625, 675 or 625, 725, 775] Primary Flat Length = [15.88, 22.22, 32.5, 42.5, 57.5, Notch, Notch] Secondary Flat Length = [8, 11.18, 18, 27.5, 37.5, NA, NA] ''' dList = [50800, 76200, 10000, 12500, 15000] pFlatLengthList = [15.88, 22.22, 32.5, 42.5, 57.5] sFlatLengthList = [8, 11.18, 18, 27.5, 37.5] r = int(diameter/2) #Height of arc position (https://mathworld.wolfram.com/CircularSegment.html) pH = r- int(np.sqrt(4*np.power(r,2)-np.power(primaryFlat,2))/2) sH = r - int(np.sqrt(4*np.power(r,2)-np.power(secondaryFlat,2))/2) # Create a circle polygon = pya.Polygon([pya.Point(-r,-r), pya.Point(-r,r), pya.Point(r,r), pya.Point(r,-r)]) polygon = polygon.round_corners(0,r,vertices) #Create a rectangle to produce the primary flat pRectangle = pya.Polygon([pya.Point(-r,r-pH), pya.Point(-r,r+pH), pya.Point(r,r+pH), pya.Point(r,r-pH)]) #Create a rectangle to produce the secondary flat sRectangle = pya.Polygon([pya.Point(-r,r-sH), pya.Point(-r,r+sH), pya.Point(r,r+sH), pya.Point(r,r-sH)]) tt = pya.ICplxTrans(1, angle, False, 0, 0) return pya.Region(polygon)-pya.Region(pRectangle)-pya.Region(sRectangle.transform(tt))
def produce_impl(self): dbu = self.layout.dbu path = pya.QPainterPath() font = pya.QFont(self.f, self.q, self.w, False) if self.s == 0: font.setStyle(pya.QFont.StyleNormal) elif self.s == 1: font.setStyle(pya.QFont.StyleItalic) else: font.setStyle(pya.QFont.StyleOblique) path.addText(0, 0, font, self.text) polygons = path.toSubpathPolygons() # gen polygon data source = [] for polygon in polygons: points = [] for point in polygon: points.append( pya.Point.from_dpoint( pya.DPoint(point.x / dbu / self.q, -point.y / dbu / self.q))) source.append([points, []]) # generate parent tree for polygon in source: for suspectedParent in source: if polygon != suspectedParent: inside = True for point in polygon[0]: if not pya.Polygon(suspectedParent[0]).inside(point): inside = False if inside: polygon[1].append(suspectedParent) # generate KLayout polygons outpoly = [] i = 0 while len(source): # find top for poly in source: if len(poly[1]) == 0: source.remove(poly) top = pya.Polygon(poly[0]) break remove = [] # add corresponding holes for polygon in source: if poly in polygon[1]: if len(polygon[1]) == 1: remove.append(polygon) top.insert_hole(polygon[0]) polygon[1].remove(poly) for polygon in remove: source.remove(polygon) self.cell.shapes(self.l_layer).insert(top)
def produce_impl(self): # This is the main part of the implementation: create the layout # fetch the parameters ru_dbu = self.ru / self.layout.dbu dist=0 da = math.pi * 2 / self.n for i in range(0,self.taper): pts=[] rad_dbu=self.radius/self.layout.dbu # calculate the size of the hole rad=self.depth*rad_dbu+(i**2)/float(self.taper-1)**2*(1-self.depth)*rad_dbu print('rad: '+str(rad)) print('i: '+str(i)) # calculate the spacing between the last taper hole sp=self.depth*self.spacing+(i**2)/float(self.taper-1)**2*(1-self.depth)*self.spacing # add to the total distance along mirror dist+=sp # create a circle at the correct position # iterate through all the points on each circle for j in range(0,self.n): pts.append(pya.Point.from_dpoint(pya.DPoint((rad*math.cos(j*da)+dist/self.layout.dbu),(rad*math.sin(j*da))))) # create the shape for this circle self.cell.shapes(self.l_layer).insert(pya.Polygon(pts)) print('self.normal: '+str(self.normal)) # now create the untapered holes for i in range(0,int(self.normal)): pts=[] rad_dbu=self.radius/self.layout.dbu # add the total distance along mirror dist+=self.spacing # create a circle at the correct position # iterate through all the points on each circle for j in range(0,self.n): pts.append(pya.Point.from_dpoint(pya.DPoint((rad*math.cos(j*da)+dist/self.layout.dbu),(rad*math.sin(j*da))))) # create the shape for this circle self.cell.shapes(self.l_layer).insert(pya.Polygon(pts))
def produce_impl(self): from SiEPIC.utils import arc from SiEPIC.extend import to_itype dbu = self.layout.dbu layer = self.layout.layer(self.layer) radius = to_itype(self.radius, dbu) width = to_itype(self.width, dbu) poly = pya.Polygon(arc(radius + width / 2, 0, 360)) hole = pya.Polygon(arc(radius - width / 2, 0, 360)) poly.insert_hole(hole.get_points()) self.cell.shapes(layer).insert(poly)
def test_extractRad(self): ex = pya.SimplePolygon().extract_rad() self.assertEqual(repr(ex), "[]") sp = pya.SimplePolygon.from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)") sp = sp.round_corners(10000, 5000, 200) ex = sp.extract_rad() self.assertEqual(ex, [pya.SimplePolygon.from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)"), 10000.0, 5000.0, 200]) ex = pya.Polygon().extract_rad() self.assertEqual(ex, []) sp = pya.Polygon.from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)") sp = sp.round_corners(10000, 5000, 200) ex = sp.extract_rad() self.assertEqual(ex, [pya.Polygon.from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)"), 10000.0, 5000.0, 200]) # double coords too ... ex = pya.DSimplePolygon().extract_rad() self.assertEqual(ex, []) sp = pya.DSimplePolygon.from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)") sp = sp.round_corners(10000, 5000, 200) ex = sp.extract_rad() # round to integers for better comparison ex[0] = pya.SimplePolygon(ex[0]) self.assertEqual(ex, [pya.SimplePolygon.from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)"), 10000.0, 5000.0, 200]) ex = pya.DPolygon().extract_rad() self.assertEqual(ex, []) sp = pya.DPolygon.from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)") sp = sp.round_corners(10000, 5000, 200) ex = sp.extract_rad() # round to integers for better comparison ex[0] = pya.Polygon(ex[0]) self.assertEqual(ex, [pya.Polygon.from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)"), 10000.0, 5000.0, 200])
def test_selfRef(self): # p1 is a reference to the new'd object: p1 = pya.Polygon(pya.Box(10, 20, 30, 40)).move(10, 20) self.assertEqual(str(p1), "(20,40;20,60;40,60;40,40)") pp = pya.Polygon(pya.Box(10, 20, 30, 40)) p1 = pp.move(10, 20) self.assertEqual(str(p1), "(20,40;20,60;40,60;40,40)") self.assertEqual(str(pp), "(20,40;20,60;40,60;40,40)") pp.move(1, 2) # p1 and pp are the same object self.assertEqual(str(p1), "(21,42;21,62;41,62;41,42)") self.assertEqual(str(pp), "(21,42;21,62;41,62;41,42)")
def arc_wg_xy(x, y, r, w, theta_start, theta_stop, DevRec=None): # function to draw an arc of waveguide # x, y: location of the origin # r: radius # w: waveguide width # length units in dbu # theta_start, theta_stop: angles for the arc # angles in degrees from math import pi, cos, sin from . import points_per_circle circle_fraction = abs(theta_stop - theta_start) / 360.0 npoints = int(points_per_circle(r) * circle_fraction) if DevRec: npoints = int(npoints / 10) if npoints == 0: npoints = 1 da = 2 * pi / npoints * circle_fraction # increment, in radians pts = [] th = theta_start / 360.0 * 2 * pi for i in range(0, npoints + 1): pts.append( pya.Point.from_dpoint( pya.DPoint((x + (r + w / 2) * cos(i * da + th)) / 1, (y + (r + w / 2) * sin(i * da + th)) / 1))) for i in range(npoints, -1, -1): pts.append( pya.Point.from_dpoint( pya.DPoint((x + (r - w / 2) * cos(i * da + th)) / 1, (y + (r - w / 2) * sin(i * da + th)) / 1))) return pya.Polygon(pts)
def test_voidMethodsReturnSelf(self): hull = [ pya.Point(0, 0), pya.Point(6000, 0), pya.Point(6000, 3000), pya.Point(0, 3000) ] hole1 = [ pya.Point(1000, 1000), pya.Point(2000, 1000), pya.Point(2000, 2000), pya.Point(1000, 2000) ] hole2 = [ pya.Point(3000, 1000), pya.Point(4000, 1000), pya.Point(4000, 2000), pya.Point(3000, 2000) ] poly = pya.Polygon(hull).insert_hole(hole1).insert_hole(hole2) self.assertEqual( str(poly), "(0,0;0,3000;6000,3000;6000,0/1000,1000;2000,1000;2000,2000;1000,2000/3000,1000;4000,1000;4000,2000;3000,2000)" )
def produce_impl(self): # fetch the parameters dbu = self.layout.dbu ly = self.layout LayerSi = self.layer LayerSiN = ly.layer(self.layer) LayerPinRecN = ly.layer(self.pinrec) LayerDevRecN = ly.layer(self.devrec) LayerTextN = ly.layer(self.textl) # Fetch all the parameters: a = self.a/dbu r = self.r/dbu # function to generate points to create a circle def hexagon_half(a): theta_div = math.pi/3 triangle_length = a/math.sqrt(3) pts = [] for i in range(0,4): pts.append(Point.from_dpoint(pya.DPoint(triangle_length*math.cos(i*theta_div-math.pi/2), triangle_length*math.sin(i*theta_div-math.pi/2)))) return pts hexagon_pts = hexagon_half(a) hexagon_cell_poly_half = pya.Polygon(hexagon_pts) #hole_cell.insert(hole_cell_poly_0) self.cell.shapes(LayerSiN).insert(hexagon_cell_poly_half)
def layout_taper(cell, layer, trans, w1, w2, length, insert=True): """ Lays out a taper Args: trans: pya.Trans: location and rotation w1: width of waveguide, float for DPoint type (microns); int for Point type (nm) w2: width of waveguide, float for DPoint type (microns); int for Point type (nm) length: length, float insert: flag to insert drawn waveguide or return shape, boolean """ import pya if type(w1) == type(float()): pts = [ pya.DPoint(0, -w1 / 2), pya.DPoint(0, w1 / 2), pya.DPoint(length, w2 / 2), pya.DPoint(length, -w2 / 2) ] shape_taper = pya.DPolygon(pts).transformed(trans) else: pts = [ pya.Point(0, -w1 / 2), pya.Point(0, w1 / 2), pya.Point(length, w2 / 2), pya.Point(length, -w2 / 2) ] shape_taper = pya.Polygon(pts).transformed(trans) if insert == True: cell.shapes(layer).insert(shape_taper) else: return shape_taper
def arc_wg(radius, w, theta_start, theta_stop, DevRec=None): # function to draw an arc of waveguide # radius: radius # w: waveguide width # length units in dbu # theta_start, theta_stop: angles for the arc # angles in degrees from math import pi, cos, sin from . import points_per_circle print("SiEPIC.utils arc_wg") circle_fraction = abs(theta_stop - theta_start) / 360.0 npoints = int(points_per_circle(radius / 1000) * circle_fraction) if DevRec: npoints = int(npoints / 3) if npoints == 0: npoints = 1 da = 2 * pi / npoints * circle_fraction # increment, in radians pts = [] th = theta_start / 360.0 * 2 * pi for i in range(0, npoints + 1): pts.append( pya.Point.from_dpoint( pya.DPoint(((radius + w / 2) * cos(i * da + th)) / 1, ((radius + w / 2) * sin(i * da + th)) / 1))) for i in range(npoints, -1, -1): pts.append( pya.Point.from_dpoint( pya.DPoint(((radius - w / 2) * cos(i * da + th)) / 1, ((radius - w / 2) * sin(i * da + th)) / 1))) return pya.Polygon(pts)
def circle(self, diameter, vertices=128): ''' circle(diameter, vertices) Generates a circle shape Parameters --------- diameter : integer The diameter of a circle vertices : integer (128) Number of vertices in the circle (coerce to multiple of 4) Returns ------ region : [pya.Region] A region containing the circle shape Description ------ The number of vertices is coerced to even numbers to ensure good fracturing ''' r = int(diameter / 2) vertices = int(vertices / 4) * 4 # Create a circle polygon = pya.Polygon([ pya.Point(-r, -r), pya.Point(-r, r), pya.Point(r, r), pya.Point(r, -r) ]) polygon = polygon.round_corners(0, r, vertices) return pya.Region(polygon)
def produce_impl(self): dbu = self.layout.dbu # resolve path info = pya.QFileInfo(self.path) if info.isRelative(): view = pya.Application.instance().main_window().current_view() designfile = view.active_cellview().filename() if designfile == "": self.error = "Error: In order to use relative file path, design must be saved first" return designdir = pya.QFileInfo(designfile).dir() path = designdir.absoluteFilePath(self.path) else: path = self.path # open image image = pya.QImage(path) if image.isNull(): self.error = "Error opening image" return image = image.convertToFormat(pya.QImage.Format_Grayscale8) width = image.width() height = image.height() tilesx = math.ceil(width / self.t) tilesy = math.ceil(height / self.t) for tiley in range(tilesy): for tilex in range(tilesx): tile = image.copy(tilex * self.t, tiley * self.t, self.t, self.t) polygons = [] # generate pixels rangex = rangey = self.t if self.t * (tilex + 1) > width: rangex = width % self.t if self.t * (tiley + 1) > height: rangey = height % self.t for y in range(rangey): for x in range(rangex): color = pya.QColor(tile.pixel(x, y)) color = (color.red + color.green + color.blue) / 3 if (color > self.th and not self.inv) or (color <= self.th and self.inv): x1 = (tilex * self.t + x) * self.px / dbu y1 = -(tiley * self.t + y) * self.px / dbu x2 = (tilex * self.t + x + 1) * self.px / dbu y2 = -(tiley * self.t + y + 1) * self.px / dbu polygons.append( pya.Polygon( pya.Box( pya.Point.from_dpoint( pya.DPoint(x1, y1)), pya.Point.from_dpoint( pya.DPoint(x2, y2))))) # merge processor = pya.EdgeProcessor() merged = processor.simple_merge_p2p(polygons, False, False) for polygon in merged: self.cell.shapes(self.l_layer).insert(polygon) self.error = None
def __init__(self, side, wall, dbu=1): self.a = side / 2 / dbu self.h = side / 2 / dbu - wall / dbu self.assign( pya.Polygon(pya.Box(-self.a, -self.a, self.a, self.a))) self.insert_hole(pya.Box(-self.h, -self.h, self.h, self.h))
def produce_impl(self): # This is the main part of the implementation: create the layout # fetch the parameters dbu = self.layout.dbu; ly = self.layout shapes = self.cell.shapes spacing = self.spacing cwidth = self.cwidth amplitude = self.amplitude maxamplitude = cwidth/2+amplitude dist=0 # spacing between each point dx=spacing/self.n dy=maxamplitude/self.n da = math.pi*2/self.n for i in range(0,self.period): pts=[] # add the total distance along mirror dist+=spacing #creat the left edge bottom part for j in range(0,self.n): pts.append(pya.Point.from_dpoint(pya.DPoint((0+dist)/dbu,-maxamplitude+j*dy/dbu))) #creat the left edge upper part for j in range(0,self.n): pts.append(pya.Point.from_dpoint(pya.DPoint((0+dist)/dbu,j*dy/dbu))) # creat the top curve # iterate through all the points on each circle for j in range(0,self.n+1): pts.append(pya.Point.from_dpoint(pya.DPoint(((j*dx+dist)/dbu),(cwidth/2+amplitude/2+(amplitude/2)*math.cos(2*math.pi*j*dx/spacing))/dbu))) #pts.append(pya.Point.from_dpoint(pya.DPoint(0*dx/dbu,j*dy/dbu))) #creat the right edge upper part for j in range(0,self.n): pts.append(pya.Point.from_dpoint(pya.DPoint((spacing+dist)/dbu,maxamplitude-j*dy/dbu))) #creat the right edge bottom part for j in range(0,self.n): pts.append(pya.Point.from_dpoint(pya.DPoint((spacing+dist)/dbu,-j*dy/dbu))) #creat the bottom curve for j in range(0,self.n+1): pts.append(pya.Point.from_dpoint(pya.DPoint(((dist+spacing-j*dx)/dbu),(-1)*(cwidth/2+amplitude/2+(amplitude/2)*math.cos(2*math.pi*(dist+spacing-j*dx)/spacing))/dbu))) # pts.append(pya.Point.from_dpoint(pya.DPoint((0/dbu),dy*self.n/dbu))) # create the shape for this sine curve self.cell.shapes(self.l_layer).insert(pya.Polygon(pts))
def Border(leng=3050000,siz=3050000,wed=50000): polygons=[] pts=[pya.Point(-siz,-siz),pya.Point(-siz+leng,-siz),pya.Point(-siz+leng,-siz+wed)] pts.extend([pya.Point(-siz+wed,-siz+wed),pya.Point(-siz+wed,-siz+leng),pya.Point(-siz,-siz+leng)]) polygon1=pya.Polygon(pts) polygons.append(polygon1) polygons.append(polygon1.transformed(pya.Trans(pya.Trans.R90))) polygons.append(polygon1.transformed(pya.Trans(pya.Trans.R180))) polygons.append(polygon1.transformed(pya.Trans(pya.Trans.R270))) return pya.Region(polygons)
def test_touches(self): p1 = pya.Polygon(pya.Box(10, 20, 30, 40)) self.assertEqual(p1.touches(pya.Polygon(pya.Box(30, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.Polygon(pya.Box(31, 20, 40, 50))), False) self.assertEqual(p1.touches(pya.Polygon(pya.Box(29, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(30, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(31, 20, 40, 50))), False) self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(29, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.Box(30, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.Box(31, 20, 40, 50)), False) self.assertEqual(p1.touches(pya.Box(29, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.Edge(30, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.Edge(31, 20, 40, 50)), False) self.assertEqual(p1.touches(pya.Edge(29, 20, 40, 50)), True) p1 = pya.SimplePolygon(pya.Box(10, 20, 30, 40)) self.assertEqual(p1.touches(pya.Polygon(pya.Box(30, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.Polygon(pya.Box(31, 20, 40, 50))), False) self.assertEqual(p1.touches(pya.Polygon(pya.Box(29, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(30, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(31, 20, 40, 50))), False) self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(29, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.Box(30, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.Box(31, 20, 40, 50)), False) self.assertEqual(p1.touches(pya.Box(29, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.Edge(30, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.Edge(31, 20, 40, 50)), False) self.assertEqual(p1.touches(pya.Edge(29, 20, 40, 50)), True) p1 = pya.DPolygon(pya.DBox(10, 20, 30, 40)) self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(30, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(31, 20, 40, 50))), False) self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(29, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(30, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(31, 20, 40, 50))), False) self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(29, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.DBox(30, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.DBox(31, 20, 40, 50)), False) self.assertEqual(p1.touches(pya.DBox(29, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.DEdge(30, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.DEdge(31, 20, 40, 50)), False) self.assertEqual(p1.touches(pya.DEdge(29, 20, 40, 50)), True) p1 = pya.DSimplePolygon(pya.DBox(10, 20, 30, 40)) self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(30, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(31, 20, 40, 50))), False) self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(29, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(30, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(31, 20, 40, 50))), False) self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(29, 20, 40, 50))), True) self.assertEqual(p1.touches(pya.DBox(30, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.DBox(31, 20, 40, 50)), False) self.assertEqual(p1.touches(pya.DBox(29, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.DEdge(30, 20, 40, 50)), True) self.assertEqual(p1.touches(pya.DEdge(31, 20, 40, 50)), False) self.assertEqual(p1.touches(pya.DEdge(29, 20, 40, 50)), True)
def layout_taper(cell, layer, trans, w1, w2, length): """ Lays out a taper Args: trans: pya.Trans: location and rotation w1: width of waveguide, float w2: width of waveguide, float length: length, float """ import pya pts = [pya.Point(0,-w1/2), pya.Point(0,w1/2), pya.Point(length,w2/2), pya.Point(length,-w2/2)] cell.shapes(layer).insert(pya.Polygon(pts).transformed(trans))
def produce_impl(self): dbu = self.layout.dbu star = [] anglestep = math.radians(360 / self.n) for i in range(self.n): angle = i * anglestep x = self.ri * math.cos(angle) y = self.ri * math.sin(angle) star.append(pya.Point.from_dpoint(pya.DPoint(x / dbu, y / dbu))) x = self.ro * math.cos(angle + anglestep / 2) y = self.ro * math.sin(angle + anglestep / 2) star.append(pya.Point.from_dpoint(pya.DPoint(x / dbu, y / dbu))) self.cell.shapes(self.l_layer).insert(pya.Polygon(star))
def produce_impl(self): dbu = self.layout.dbu arrow = [] tg = math.tan(math.radians(self.a/2)) hw = self.h * tg arrow.append(pya.Point.from_dpoint(pya.DPoint(self.w/(2*dbu), -self.b/dbu))) arrow.append(pya.Point.from_dpoint(pya.DPoint(self.w/(2*dbu), 0))) arrow.append(pya.Point.from_dpoint(pya.DPoint(hw/dbu, 0))) arrow.append(pya.Point.from_dpoint(pya.DPoint(0, self.h/dbu))) arrow.append(pya.Point.from_dpoint(pya.DPoint(-hw/dbu, 0))) arrow.append(pya.Point.from_dpoint(pya.DPoint(-self.w/(2*dbu), 0))) arrow.append(pya.Point.from_dpoint(pya.DPoint(-self.w/(2*dbu), -self.b/dbu))) self.cell.shapes(self.l_layer).insert(pya.Polygon(arrow))
def produce_impl(self): ru_dbu = self.w / self.layout.dbu # compute the circle pts = [] da = math.pi * 2 / 4 for i in range(0, 4): pts.append( pya.Point.from_dpoint( pya.DPoint(ru_dbu * math.cos(i * da), ru_dbu * math.sin(i * da)))) # create the shape self.cell.shapes(self.ls_layer).insert(pya.Polygon(pts))
def produce_impl(self): # This is the main part of the implementation: create the layout # fetch the parameters ru_dbu = self.ru / self.layout.dbu # compute the circle pts = [] #da = math.pi * 2 / self.n #for i in range(0, self.n): #pts.append(pya.Point.from_dpoint(pya.DPoint(ru_dbu * math.cos(i * da), ru_dbu * math.sin(i * da)))) # create the shape self.cell.shapes(self.l_layer).insert(pya.Polygon(pts))
def test_2_DPolygon(self): pts = [pya.DPoint(0, 0)] p = pya.DPolygon(pts, True) self.assertEqual(str(p), "(0,0)") arr = [] for e in p.each_edge(): arr.append(str(e)) self.assertEqual(arr, ["(0,0;0,0)"]) p = pya.DPolygon(pya.DBox(0, 0, 100, 100)) p.insert_hole([pya.DPoint(0, 0), pya.DPoint(10, 0)], True) self.assertEqual(str(p), "(0,0;0,100;100,100;100,0/0,0;10,0)") p.assign_hole(0, [pya.DPoint(0, 0), pya.DPoint(10, 0)]) self.assertEqual(str(p), "(0,0;0,100;100,100;100,0/0,0;10,0)") p.assign_hole(0, [pya.DPoint(0, 0), pya.DPoint(10, 0)], True) self.assertEqual(str(p), "(0,0;0,100;100,100;100,0/0,0;10,0)") pts = [pya.DPoint(0, 0), pya.DPoint(10, 0)] p = pya.DPolygon(pts, True) self.assertEqual(str(p), "(0,0;10,0)") self.assertEqual(str(pya.Polygon(p)), "(0,0;10,0)") p.hull = [] self.assertEqual(str(p), "()") p.hull = [pya.DPoint(0, 0), pya.DPoint(10, 0)] self.assertEqual(str(p), "(0,0;10,0)") p.assign_hull([pya.DPoint(0, 0), pya.DPoint(10, 0)], True) self.assertEqual(str(p), "(0,0;10,0)") arr = [] for e in p.each_edge(): arr.append(str(e)) self.assertEqual(arr, ["(0,0;10,0)", "(10,0;0,0)"]) self.assertEqual(str(p.moved(1, 2)), "(1,2;11,2)") self.assertEqual(str(p.sized(2)), "(0,-2;0,2;10,2;10,-2)") self.assertEqual(str(p * 2), "(0,0;20,0)") self.assertEqual(str(p.transformed(pya.DTrans(pya.DTrans.R90))), "(0,0;0,10)") pp = p.dup() pp.transform(pya.DTrans(pya.DTrans.R90)) self.assertEqual(str(pp), "(0,0;0,10)")