def define_points(self, pts): c = Shape(self.original_shape) if len(c) == 0: return pts if self.original_shape.is_closed(): if not c[0] == c[-1]: c.append(c[0]) #closed curve c.append(c[1]) else: # open curve pts.append(c[0]) min_sw = self.stub_width for i in range(1, len(c) - 1): angle1 = angle_rad(c[i], c[i - 1]) angle2 = angle_rad(c[i + 1], c[i]) turn = (angle2 - angle1 + pi) % (2 * pi) - pi if turn == 0 or (abs(turn) <= (pi / 2.0) and self.only_sharp_angles): pts.append(c[i]) elif abs(turn == pi): LOG.error( "ShapeStub::define_points : ERROR : Cannot stub shape with a 180 degree turn" ) else: d1 = distance(c[i], c[i - 1]) d2 = distance(c[i + 1], c[i]) L = self.stub_width * sin(turn / 2.0) / sin(turn) max_L = max([d1 / 2.0, d2 / 2.0]) if L > max_L: L = max_L sw = L * sin(turn) / sin(turn / 2.0) else: sw = self.stub_width if sw < min_sw: min_sw = sw s1 = (c[i][0] - L * cos(angle1), c[i][1] - L * sin(angle1)) s2 = (c[i][0] + L * cos(angle2), c[i][1] + L * sin(angle2)) pts.append(s1) pts.append(s2) ''' REFACTORED --> moved to constructor if self.original_shape.closed: #closed curve self.close() else: ''' if not self.original_shape.closed: # open curve pts.append(c[-1]) if min_sw < self.stub_width: LOG.warning( "Warning: ShapeStub::define_points : Stub width is reduced from " + str(self.stub_width) + " to " + str(min_sw) + "to stub shape.") return pts
def __filter_str__(self, item): if item is None: return None name = copy.copy(item) name = name.replace("-", "_") name = name.replace(" ", "_") name = name.replace(".", "_") name = name.replace("/", "_") if self.scramble_all: hashval = hash(name) if hashval < 0: prefix = "S_" else: prefix = "S" name = prefix + str(abs(hashval)) name = name.upper() elif self.max_name_length != None: if self.max_name_length > 0 and len(name) > self.max_name_length: hashval = str(abs(hash(name))) L = len(hashval) if L > self.max_name_length + 1: raise ValueError( "max_name_length %d in NameScrambleFilter is too short for hash algorithm" % (self.max_name_length)) name = name[0:self.max_name_length - L - 1] + "_" + hashval LOG.warning("Too long name encountered. Current length = %d" % len(name)) return [name]
def __radii_and_turns__(self, s): R = self.radii r = array(R) D = s.distances() a2 = s.angles_rad() # angle to next vertex a1 = roll(a2, 1) # angle from previous vertex t = (a2 - a1 + pi) % (2 * pi) - pi # turns, save an extra angle computation tt = abs(tan(0.5 * t)) L = R * tt # length of the straight section consumed by the bend (Swsa, dummy) = self.__original_shape_without_straight_angles__( self.original_shape, self.radii) if not Swsa.closed: L[0] = 0 L[-1] = 0 # check where the bend consumes more length than possible! m_L = ((L + roll(L, -1)) - D) # missing length in the next segment missing_L = amax(column_stack((m_L, roll(m_L, 1))), 1) # missing length over previous and next segment overf = (missing_L > 0.5 / settings.get_grids_per_unit()) r[overf] = 0.5 * (amin(column_stack( (D[overf], roll(D, 1)[overf])), 1)) / tt[overf] # FIXME: Find a more robust algorithm to reduce the radius if there is insufficient space r_difference = R - r if (r_difference > settings.get_current_library().units_per_grid).any(): LOG.warning( "Bend radius is reduced by maximum %f to round shape." % max(r_difference)) if not Swsa.closed: r[0] = 0 r[-1] = 0 L = r * tt # recompute the length of the straight section consumed by the bend return (r, tt, t, a1, a2, L, D)
def define_gdsiilayer_map(self): lm = {} for k, v in self.pplayer_map.items(): if v in lm: LOG.warning( "PPLayer to GDSII layer mapping for GDSII %i:%i => %s:%s overwritten with %s:%s" % (v[0], v[1], lm[v][0], lm[v][1], k[0], k[1])) lm[v] = k return lm
def __getitem__(self, gdsiilayer, default=None): if (gdsiilayer.number, gdsiilayer.datatype) in self.layer_map: return self.layer_map[(gdsiilayer.number, gdsiilayer.datatype)] else: error_message = "Warning during GDSII import : no corresponding process/purpose layer found for number = %i and datatype = %s" % ( gdsiilayer.number, gdsiilayer.datatype) if self.ignore_undefined_mappings: LOG.warning(error_message) return default else: raise Exception(error_message)
def __getitem__(self, key, default=None): if (key.number, key.datatype) in self.gdsiilayer_map: (pl, pp) = self.gdsiilayer_map[(key.number, key.datatype)] return PPLayer(process=pl, purpose=pp) else: error_message = "Warning during GDSII import : no corresponding process/purpose layer found for number = %i and datatype = %s" % ( key.number, key.datatype) if self.ignore_undefined_mappings: LOG.warning(error_message) return default else: raise Exception(error_message)
def __getitem__(self, key, default=None): if (key.process, key.purpose) in self.pplayer_map: (lay, dat) = self.pplayer_map[(key.process, key.purpose)] return GdsiiLayer(number=lay, datatype=dat) else: error_message = "Warning during GDSII export : no corresponding GDSII layer/datatype found for process = %s and purpose = %s" % ( key.process, key.purpose) if self.ignore_undefined_mappings: LOG.warning(error_message) return default else: raise Exception(error_message)
def shapes_character (self, character, letter_height = 1.0, south_west_coord = (0.0,0.0), angle = 0.0): #returns a list of shapes!!! if character in self.coords: shapes = self.coords[character] else: shapes = [self.default_char] ret_shapes = [] #T = Rotation((0.0,0.0), angle) + Magnification((0.0,0,0), letter_height) + Translation(south_west_coord) T = NoDistortTransform(south_west_coord, angle, letter_height/self.letter_height()) for s in shapes: if len(s) < 2: LOG.warning("Shape with too few coordinates in letter " % character) #ret_shapes.append(shape_translate(shape_scale(shape_rotate(s, (0.0,0.0), angle), (letter_height, letter_height)), south_west_coord)) ret_shapes.append(T.apply_to_copy(s)) return ret_shapes
def top_layout(self): L = self.unreferenced_structures() if len(L) == 1: return L[0] elif len(L) == 0: if len(self.structures) == 0: return Structure("__empty__") else: LOG.warning("There is no top_level structure in library %s. This could be caused by a circular reference" % self.name) return None elif self.layout: warning_string = """There is more than one top-level structure in library %s. This is ambiguous if the library is to be used as a layout. Please make sure that all but the top-level structures are referred to. #The following structures are 'floating': #%s """ % (self.name, "#\n".join([s.name for s in L])) LOG.warning(warning_string)
def collect_Path(self, item, additional_transform=None, **kwargs): shape = item.shape.transform_copy(item.transformation + additional_transform) shape.snap_to_grid(self.grids_per_unit) shape.remove_identicals() coordinates = Shape(shape) if len(coordinates) < 2: if self.write_empty: LOG.warning("PATH with fewer than 2 coordinates not allowed") return if shape.closed: if not (shape[-1] == shape[0]): coordinates.append(shape[0]) self.collect_path_element(layer=item.layer, coordinates=coordinates, line_width=item.line_width, path_type=item.path_type) return
def collect_Boundary(self, item, additional_transform=None, **kwargs): shape = item.shape.transform_copy(item.transformation + additional_transform) shape.snap_to_grid(self.grids_per_unit) shape.remove_identicals() coordinates = shape # BOUNDARIES if len(shape) < 3: LOG.warning( "BOUNDARY with fewer than 3 coordinates not allowed in structure %s" % self.__current_structure__.name) return if len(shape) > TECH.GDSII.MAX_VERTEX_COUNT: LOG.warning("BOUNDARY with more than " + str(TECH.GDSII.MAX_VERTEX_COUNT) + " coordinates not supported in structure " + self.__current_structure__.name) # shape must be closed! if not (coordinates[0] == coordinates[-1]): coordinates.append(coordinates[0]) self.collect_boundary_element(layer=item.layer, coordinates=coordinates) return
def define_points(self, pts): c = Shape(self.original_shape) if len(c) == 0: return if self.original_shape.is_closed(): if not c[0] == c[-1]: c.append(c[0]) #closed curve c.append(c[1]) else: # open curve pts.append(c[0]) c.remove_identicals() min_sw = self.stub_width for i in range(1, len(c) - 1): angle1 = angle_rad(c[i], c[i - 1]) angle2 = angle_rad(c[i + 1], c[i]) turn = (angle2 - angle1 + pi) % (2 * pi) - pi if turn == 0 or (abs(turn) <= (pi / 2.0) and self.only_sharp_angles): pts.append(c[i]) elif abs(turn == pi): LOG.error("Cannot stub shape with a 180 degree turn") else: d1 = distance(c[i], c[i - 1]) d2 = distance(c[i + 1], c[i]) L = self.stub_width * sin(turn / 2.0) / sin(turn) max_L = max([d1 / 2.0, d2 / 2.0]) if L > max_L: L = max_L sw = L * sin(turn) / sin(turn / 2.0) else: sw = self.stub_width if sw < min_sw: min_sw = sw theta_div2 = (pi - angle1 + angle2) % (2 * pi) / 2.0 s1 = Coord2(c[i][0] - L * cos(angle1), c[i][1] - L * sin(angle1)) s2 = (c[i][0] + L * cos(angle2), c[i][1] + L * sin(angle2)) B = -self.stub_height * sign(turn) delta = 0.5 * (self.stub_width - self.tip_width) s2 = (s1[0] + B * cos(angle1 + theta_div2) + delta * cos(angle1 + theta_div2 - pi / 2.0), s1[1] + B * sin(angle1 + theta_div2) + delta * sin(angle1 + theta_div2 - pi / 2.0)) s4 = Coord2(c[i][0] + L * cos(angle2), c[i][1] + L * sin(angle2)) s3 = (s4[0] + B * cos(angle2 + pi - theta_div2) + delta * cos(angle2 + pi - theta_div2 + pi / 2.0), s4[1] + B * sin(angle2 + pi - theta_div2) + delta * sin(angle2 + pi - theta_div2 + pi / 2.0)) pts.append(s1) pts.append(s2) pts.append(s3) pts.append(s4) if not self.original_shape.closed: # open curve pts.append(c[-1]) if min_sw < self.stub_width: LOG.warning("Stub width is reduced from " + str(self.stub_width) + " to " + str(min_sw) + "to stub shape.") return pts
def define_points(self, pts): (s, R, A) = self.__original_shape_without_straight_angles__() if len(R) != len(s): raise AttributeError( "ShapeRoundAdiabaticSplineGeneric: length of radius vector should be identical to that of points in shape" ) if len(A) != len(s): raise AttributeError( "ShapeRoundAdiabaticSplineGeneric: length of adiabatic_angles vector should be identical to that of points in shape" ) if len(s) < 3: self.__points__ = s.points return margin = 0.5 / get_grids_per_unit() S = [] if not self.original_shape.closed: S.append(numpy.array([s.points[0]])) L1 = 0.0 for i in range(1, len(s) - 1): sh = AdiabaticSplineCircleSplineShape(start_point=s[i - 1], turn_point=s[i], end_point=s[i + 1], radius=R[i], adiabatic_angles=A[i], angle_step=self.angle_step) L0 = sh[0].distance(s[i]) if L0 + L1 - margin > s[i - 1].distance(s[i]): LOG.warning( "Insufficient space for spline rounding in (%f, %f)" % (s[i].x, s[i].y)) L1 = sh[-1].distance(s[i]) S.append(sh.points) if self.original_shape.closed: sh = AdiabaticSplineCircleSplineShape(start_point=s[-2], turn_point=s[-1], end_point=s[0], radius=R[-1], adiabatic_angles=A[-1], angle_step=self.angle_step) L0 = sh[0].distance(s[-1]) if L0 + L1 - margin > s[-2].distance(s[-1]): LOG.warning( "Insufficient space for spline rounding in (%f, %f)" % (s[-1].x, s[-1].y)) L1 = sh[-1].distance(s[-1]) S.append(sh.points) sh = AdiabaticSplineCircleSplineShape(start_point=s[-1], turn_point=s[0], end_point=s[1], radius=R[0], adiabatic_angles=A[0], angle_step=self.angle_step) L0 = sh[0].distance(s[0]) if L0 + L1 - margin > s[-1].distance(s[0]): LOG.warning( "Insufficient space for spline rounding in (%f, %f)" % (s[0].x, s[0].y)) L1 = sh[-1].distance(s[0]) S.append(sh.points) self.__closed__ = True else: # open curve S.append(numpy.array([s.points[-1]])) L0 = 0.0 if L0 + L1 - margin > s[-2].distance(s[-1]): LOG.warning( "Insufficient space for spline rounding in (%f, %f)" % (s[-1].x, s[-1].y)) L1 = sh[-1].distance(s[0]) self.__closed__ = False return numpy.vstack(S)