def remove_colinear_points(self, verbose=False): """ remove all but 1 colinear point """ from SiEPIC.utils import pt_intersects_segment, angle_b_vectors, angle_vector if self.__class__ == pya.Path: pts = self.get_points() else: pts = self.get_dpoints() for i in range(1,len(pts)-1): turn = ((angle_b_vectors(pts[i]-pts[i-1],pts[i+1]-pts[i])+90)%360-90)/90 angle = angle_vector(pts[i]-pts[i-1])/90 if verbose: print('%s, %s' %(turn, angle)) # this version removed all colinear points, which doesn't make sense for a path self.points = [pts[0]] + [pts[i] for i in range(1, len(pts) - 1) if not pt_intersects_segment(pts[i + 1], pts[i - 1], pts[i])] + [pts[-1]] return self
def produce_impl(self): from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal from math import cos, sin, pi, sqrt import pya from SiEPIC.extend import to_itype print("GSiP.Wireguide") TECHNOLOGY = get_technology_by_name( 'GSiP') if op_tag == "GUI" else Tech.load_from_xml( lyp_filepath).layers dbu = self.layout.dbu wg_width = to_itype(self.width, dbu) path = self.path.to_itype(dbu) if not (len(self.layers) == len(self.widths) and len(self.layers) == len(self.offsets) and len(self.offsets) == len(self.widths)): raise Exception( "There must be an equal number of layers, widths and offsets") path.unique_points() turn = 0 for lr in range(0, len(self.layers)): layer = self.layout.layer(TECHNOLOGY[self.layers[lr]]) width = to_itype(self.widths[lr], dbu) offset = to_itype(self.offsets[lr], dbu) pts = path.get_points() wg_pts = [pts[0]] for i in range(1, len(pts) - 1): turn = ((angle_b_vectors(pts[i] - pts[i - 1], pts[i + 1] - pts[i]) + 90) % 360 - 90) / 90 dis1 = pts[i].distance(pts[i - 1]) dis2 = pts[i].distance(pts[i + 1]) angle = angle_vector(pts[i] - pts[i - 1]) / 90 pt_radius = self.radius # determine the radius, based on how much space is available if len(pts) == 3: pt_radius = min(dis1, dis2, pt_radius) else: if i == 1: if dis1 <= pt_radius: pt_radius = dis1 elif dis1 < 2 * pt_radius: pt_radius = dis1 / 2 if i == len(pts) - 2: if dis2 <= pt_radius: pt_radius = dis2 elif dis2 < 2 * pt_radius: pt_radius = dis2 / 2 # wireguide bends: if (self.adiab): wg_pts += Path( arc_bezier( pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), self.bezier, DevRec='DevRec' in self.layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() else: wg_pts += Path( arc_xy(-pt_radius, pt_radius, pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), DevRec='DevRec' in self.layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() wg_pts += [pts[-1]] wg_pts = pya.Path(wg_pts, 0).unique_points().get_points() wg_polygon = Path(wg_pts, wg_width) self.cell.shapes(layer).insert(wg_polygon) # insert the wireguide #if self.layout.layer(TECHNOLOGY['Wireguide']) == layer: waveguide_length = wg_polygon.area() / self.width * dbu**2 pts = path.get_points() LayerPinRecN = self.layout.layer(TECHNOLOGY['PinRecM']) # insert pins to wireguide t1 = Trans(angle_vector(pts[0] - pts[1]) / 90, False, pts[0]) self.cell.shapes(LayerPinRecN).insert( Path([Point(-50, 0), Point(50, 0)], wg_width).transformed(t1)) self.cell.shapes(LayerPinRecN).insert(Text("pin1", t1, 0.3 / dbu, -1)) t = Trans(angle_vector(pts[-1] - pts[-2]) / 90, False, pts[-1]) self.cell.shapes(LayerPinRecN).insert( Path([Point(-50, 0), Point(50, 0)], wg_width).transformed(t)) self.cell.shapes(LayerPinRecN).insert(Text("pin2", t, 0.3 / dbu, -1)) LayerDevRecN = self.layout.layer(TECHNOLOGY['DevRec']) # Compact model information angle_vec = angle_vector(pts[0] - pts[1]) / 90 halign = 0 # left angle = 0 pt2 = pts[0] pt3 = pts[0] if angle_vec == 0: # horizontal halign = 2 # right angle = 0 pt2 = pts[0] + Point(0, wg_width) pt3 = pts[0] + Point(0, -wg_width) if angle_vec == 2: # horizontal halign = 0 # left angle = 0 pt2 = pts[0] + Point(0, wg_width) pt3 = pts[0] + Point(0, -wg_width) if angle_vec == 1: # vertical halign = 2 # right angle = 1 pt2 = pts[0] + Point(wg_width, 0) pt3 = pts[0] + Point(-wg_width, 0) if angle_vec == -1: # vertical halign = 0 # left angle = 1 pt2 = pts[0] + Point(wg_width, 0) pt3 = pts[0] + Point(-wg_width, 0)
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, radius, adiab, bezier): ''' Create a waveguide, in a specific technology inputs - TECHNOLOGY, layout, cell: from SiEPIC.utils import get_layout_variables TECHNOLOGY, lv, layout, cell = get_layout_variables() - layers: list of text names, e.g., ['Waveguide'] - widths: list of floats in units Microns, e.g., [0.50] - offsets: list of floats in units Microns, e.g., [0] - pts: a list of pya.Points, e.g. L=15/dbu pts = [Point(0,0), Point(L,0), Point(L,L)] - radius: in Microns, e.g., 5 - adiab: 1 = Bezier curve, 0 = radial bend (arc) - bezier: the bezier parameter, between 0 and 0.45 (almost a radial bend) Note: bezier parameters need to be simulated and optimized, and will depend on wavelength, polarization, width, etc. TM and rib waveguides don't benefit from bezier curves most useful for TE ''' from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal from SiEPIC.extend import to_itype from pya import Path, Polygon, Trans dbu = layout.dbu width=widths[0] turn=0 waveguide_length = 0 for lr in range(0, len(layers)): wg_pts = [pts[0]] layer = layout.layer(TECHNOLOGY[layers[lr]]) width = to_itype(widths[lr],dbu) offset = to_itype(offsets[lr],dbu) for i in range(1,len(pts)-1): turn = ((angle_b_vectors(pts[i]-pts[i-1],pts[i+1]-pts[i])+90)%360-90)/90 dis1 = pts[i].distance(pts[i-1]) dis2 = pts[i].distance(pts[i+1]) angle = angle_vector(pts[i]-pts[i-1])/90 pt_radius = to_itype(radius,dbu) # determine the radius, based on how much space is available if len(pts)==3: pt_radius = min (dis1, dis2, pt_radius) else: if i==1: if dis1 <= pt_radius: pt_radius = dis1 elif dis1 < 2*pt_radius: pt_radius = dis1/2 if i==len(pts)-2: if dis2 <= pt_radius: pt_radius = dis2 elif dis2 < 2*pt_radius: pt_radius = dis2/2 # waveguide bends: if abs(turn)==1: if(adiab): wg_pts += Path(arc_bezier(pt_radius, 270, 270 + inner_angle_b_vectors(pts[i-1]-pts[i], pts[i+1]-pts[i]), bezier, DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() else: wg_pts += Path(arc_xy(-pt_radius, pt_radius, pt_radius, 270, 270 + inner_angle_b_vectors(pts[i-1]-pts[i], pts[i+1]-pts[i]),DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() wg_pts += [pts[-1]] wg_pts = pya.Path(wg_pts, 0).unique_points().get_points() wg_polygon = Polygon(translate_from_normal(wg_pts, width/2 + (offset if turn > 0 else - offset))+translate_from_normal(wg_pts, -width/2 + (offset if turn > 0 else - offset))[::-1]) cell.shapes(layer).insert(wg_polygon) if layout.layer(TECHNOLOGY['Waveguide']) == layer: waveguide_length = wg_polygon.area() / width * dbu return waveguide_length
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, radius, adiab, bezier): from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal from SiEPIC.extend import to_itype from pya import Path, Polygon, Trans dbu = layout.dbu width = widths[0] turn = 0 waveguide_length = 0 for lr in range(0, len(layers)): wg_pts = [pts[0]] layer = layout.layer(TECHNOLOGY[layers[lr]]) width = to_itype(widths[lr], dbu) offset = to_itype(offsets[lr], dbu) for i in range(1, len(pts) - 1): turn = ( (angle_b_vectors(pts[i] - pts[i - 1], pts[i + 1] - pts[i]) + 90) % 360 - 90) / 90 dis1 = pts[i].distance(pts[i - 1]) dis2 = pts[i].distance(pts[i + 1]) angle = angle_vector(pts[i] - pts[i - 1]) / 90 pt_radius = to_itype(radius, dbu) # determine the radius, based on how much space is available if len(pts) == 3: pt_radius = min(dis1, dis2, pt_radius) else: if i == 1: if dis1 <= pt_radius: pt_radius = dis1 elif dis1 < 2 * pt_radius: pt_radius = dis1 / 2 if i == len(pts) - 2: if dis2 <= pt_radius: pt_radius = dis2 elif dis2 < 2 * pt_radius: pt_radius = dis2 / 2 # waveguide bends: if abs(turn) == 1: if (adiab): wg_pts += Path( arc_bezier( pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), float(bezier), DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() else: wg_pts += Path( arc_xy(-pt_radius, pt_radius, pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() wg_pts += [pts[-1]] wg_pts = pya.Path(wg_pts, 0).unique_points().get_points() wg_polygon = Polygon( translate_from_normal( wg_pts, width / 2 + (offset if turn > 0 else -offset)) + translate_from_normal( wg_pts, -width / 2 + (offset if turn > 0 else -offset))[::-1]) cell.shapes(layer).insert(wg_polygon) if layout.layer(TECHNOLOGY['Waveguide']) == layer: waveguide_length = wg_polygon.area() / width * dbu return waveguide_length
def layout_waveguide2(TECHNOLOGY, layout, cell, layers, widths, offsets, pts, radius, adiab, bezier): from SiEPIC.utils import arc_xy, arc_bezier, angle_vector, angle_b_vectors, inner_angle_b_vectors, translate_from_normal from SiEPIC.extend import to_itype from pya import Path, Polygon, Trans dbu = layout.dbu if 'Errors' in TECHNOLOGY: error_layer = layout.layer(TECHNOLOGY['Errors']) else: error_layer = None width = widths[0] turn = 0 waveguide_length = 0 for lr in range(0, len(layers)): wg_pts = [pts[0]] layer = layout.layer(TECHNOLOGY[layers[lr]]) width = to_itype(widths[lr], dbu) offset = to_itype(offsets[lr], dbu) for i in range(1, len(pts) - 1): turn = ( (angle_b_vectors(pts[i] - pts[i - 1], pts[i + 1] - pts[i]) + 90) % 360 - 90) / 90 dis1 = pts[i].distance(pts[i - 1]) dis2 = pts[i].distance(pts[i + 1]) angle = angle_vector(pts[i] - pts[i - 1]) / 90 pt_radius = to_itype(radius, dbu) error_seg1 = False error_seg2 = False # determine the radius, based on how much space is available if len(pts) == 3: # simple corner, limit radius by the two edges if dis1 < pt_radius: error_seg1 = True if dis2 < pt_radius: error_seg2 = True pt_radius = min(dis1, dis2, pt_radius) else: if i == 1: # first corner, limit radius by first edge, or 1/2 of second one if dis1 < pt_radius: error_seg1 = True if dis2 / 2 < pt_radius: error_seg2 = True pt_radius = min(dis1, dis2 / 2, pt_radius) elif i == len(pts) - 2: # last corner, limit radius by second edge, or 1/2 of first one if dis1 / 2 < pt_radius: error_seg1 = True if dis2 < pt_radius: error_seg2 = True pt_radius = min(dis1 / 2, dis2, pt_radius) else: if dis1 / 2 < pt_radius: error_seg1 = True if dis2 / 2 < pt_radius: error_seg2 = True pt_radius = min(dis1 / 2, dis2 / 2, pt_radius) if error_seg1 or error_seg2: if not error_layer: # we have an error, but no Error layer print('- SiEPIC:layout_waveguide2: missing Error layer') # and pt_radius < to_itype(radius,dbu): elif layer == layout.layer(TECHNOLOGY['Waveguide']): # add an error polygon to flag the incorrect bend if error_seg1: error_pts = pya.Path([pts[i - 1], pts[i]], width) cell.shapes(error_layer).insert(error_pts) if error_seg2: error_pts = pya.Path([pts[i], pts[i + 1]], width) cell.shapes(error_layer).insert(error_pts) # error_pts = pya.Path([pts[i-1], pts[i], pts[i+1]], width) # cell.shapes(error_layer).insert(error_pts) # waveguide bends: if abs(turn) == 1: if (adiab): wg_pts += Path( arc_bezier( pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), float(bezier), DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() else: wg_pts += Path( arc_xy(-pt_radius, pt_radius, pt_radius, 270, 270 + inner_angle_b_vectors( pts[i - 1] - pts[i], pts[i + 1] - pts[i]), DevRec='DevRec' in layers[lr]), 0).transformed(Trans(angle, turn < 0, pts[i])).get_points() wg_pts += [pts[-1]] wg_pts = pya.Path(wg_pts, 0).unique_points().get_points() wg_polygon = Polygon( translate_from_normal( wg_pts, width / 2 + (offset if turn > 0 else -offset)) + translate_from_normal( wg_pts, -width / 2 + (offset if turn > 0 else -offset))[::-1]) cell.shapes(layer).insert(wg_polygon) if layout.layer(TECHNOLOGY['Waveguide']) == layer: waveguide_length = wg_polygon.area() / width * dbu return waveguide_length