示例#1
0
class EdgeGenerator(Group, __LayerElement__):
    """ Generates edge objects for each shape segment. """

    shape = ShapeParameter()
    internal_pid = StringParameter(
        default='no_pid',
        doc='A unique polygon ID to which the edge connects.')

    def create_elements(self, elems):

        shape = self.shape.remove_straight_angles()
        shape = shape.reverse_points()

        for i, s in enumerate(shape.segments()):

            line_shape = Shape(points=s)

            L = RDD.GDSII.IMPORT_LAYER_MAP[self.layer]
            width = RDD[L.process.symbol].MIN_SIZE

            layer = PLayer(process=L.process,
                           purpose=RDD.PURPOSE.PORT.OUTSIDE_EDGE_DISABLED)

            elems += Edge(shape=[],
                          line_shape=line_shape,
                          layer=layer,
                          internal_pid=self.internal_pid,
                          width=width,
                          transformation=self.transformation)

        return elems
示例#2
0
class Edge(Path):
    """ Edge elements are object that represents the edge of a polygonal shape. """

    line_shape = ShapeParameter(default=[])

    edge_type = RestrictedParameter(default=constants.EDGE_TYPE_NORMAL,
                                    restriction=RestrictValueList(
                                        constants.EDGE_TYPES))

    internal_pid = StringParameter(
        default='no_pid',
        doc='A unique polygon ID to which the edge connects.')
    external_pid = StringParameter(
        default='no_pid',
        doc='A unique polygon ID to which the edge connects.')

    def __init__(self, shape, layer, transformation=None, **kwargs):
        super().__init__(shape=shape,
                         layer=layer,
                         transformation=transformation,
                         **kwargs)

    def __repr__(self):
        if self is None:
            return 'Edge is None!'
        layer = RDD.GDSII.IMPORT_LAYER_MAP[self.layer]
        class_string = "[SPiRA: Edge] (center {}, width {}, process {}, purpose {})"
        return class_string.format(self.center, self.width,
                                   self.layer.process.symbol,
                                   self.layer.purpose.symbol)

    def __str__(self):
        return self.__repr__()

    def __hash__(self):
        return hash(self.__repr__())

    def short_string(self):
        # return "Edge [{}, {}, {}]".format(self.center, self.layer.process.symbol, self.layer.purpose.symbol)
        # NOTE: We want to ignore the purpose for CIRCUIT_METAL ot DEVICE_METAL net connections.
        return "Edge [{}, {}]".format(self.center, self.layer.process.symbol)

    def flat_copy(self, level=-1):
        """ Flatten a copy of the polygon. """
        S = Edge(shape=self.shape,
                 layer=self.layer,
                 transformation=self.transformation)
        S.expand_transform()
        return S
示例#3
0
class RouteGeneral(Cell):

    layer = LayerParameter()

    route_shape = ShapeParameter(doc='Shape of the routing polygon.')

    port_input = Parameter(fdef_name='create_port_input')
    port_output = Parameter(fdef_name='create_port_output')

    gds_layer = Parameter(fdef_name='create_gds_layer')

    def create_gds_layer(self):
        ll = spira.Layer(
            number=self.layer.number,
            # datatype=RDD.PURPOSE.TERM.datatype
            datatype=22)
        return ll

    def create_port_input(self):
        term = spira.Port(
            name='P1',
            midpoint=self.route_shape.m1,
            width=self.route_shape.w1,
            orientation=self.route_shape.o1,
            # gds_layer=self.gds_layer
        )
        return term

    def create_port_gdsii_output(self):
        term = spira.Port(
            name='P2',
            midpoint=self.route_shape.m2,
            width=self.route_shape.w2,
            orientation=self.route_shape.o2,
            # gds_layer=self.gds_layer
        )
        return term

    def create_elements(self, elems):
        poly = spira.Polygon(shape=self.route_shape,
                             layer=self.layer,
                             enable_edges=False)
        elems += poly
        return elems

    def create_ports(self, ports):
        ports += self.port_input
        ports += self.port_output
        return ports
示例#4
0
class EdgeGenerator(Group, __LayerElement__):
    """ Generates edge objects for each shape segment. """

    shape = ShapeParameter()

    def create_elements(self, elems):

        xpts = list(self.shape.x_coords)
        ypts = list(self.shape.y_coords)

        n = len(xpts)
        xpts.append(xpts[0])
        ypts.append(ypts[0])

        clockwise = 0
        for i in range(0, n):
            clockwise += ((xpts[i + 1] - xpts[i]) * (ypts[i + 1] + ypts[i]))

        if self.layer.name == 'BBOX': bbox = True
        else: bbox = False

        for i in range(0, n):

            name = '{}_e{}'.format(self.layer.name, i)
            x = np.sign(clockwise) * (xpts[i + 1] - xpts[i])
            y = np.sign(clockwise) * (ypts[i] - ypts[i + 1])
            orientation = (np.arctan2(x, y) * constants.RAD2DEG) + 90
            midpoint = [(xpts[i + 1] + xpts[i]) / 2,
                        (ypts[i + 1] + ypts[i]) / 2]
            width = np.abs(
                np.sqrt((xpts[i + 1] - xpts[i])**2 +
                        (ypts[i + 1] - ypts[i])**2))

            layer = RDD.GDSII.IMPORT_LAYER_MAP[self.layer]
            extend = RDD[layer.process.symbol].MIN_SIZE

            T = Rotation(orientation) + Translation(midpoint)
            layer = PLayer(process=layer.process,
                           purpose=RDD.PURPOSE.PORT.OUTSIDE_EDGE_DISABLED)
            shape = shapes.BoxShape(width=width, height=extend)
            # elems += EdgeSymmetric(width=width, extend=extend, process=layer.process, transformation=T)
            elems += Edge(shape=shape,
                          layer=layer,
                          width=width,
                          extend=extend,
                          transformation=T)

        return elems
示例#5
0
class __ShapeElement__(__LayerElement__):
    """ Base class for an edge element. """

    shape = ShapeParameter()

    @property
    def points(self):
        return self.shape.points

    @property
    def area(self):
        import gdspy
        return gdspy.Polygon(self.shape.points).area()

    @property
    def count(self):
        return np.size(self.shape.points, 0)

    @property
    def bbox_info(self):
        return self.shape.bbox_info.transform_copy(self.transformation)

    @property
    def center(self):
        return self.bbox_info.center

    @center.setter
    def center(self, destination):
        self.move(midpoint=self.center, destination=destination)

    def id_string(self):
        return '{} - hash {}'.format(self.short_string(),
                                     self.shape.hash_string)

    def is_empty(self):
        """ Returns `False` is the polygon shape has no points. """
        return self.shape.is_empty()

    def encloses(self, point):
        """ Returns `True` if the polygon encloses the point. """
        from spira.yevon.utils import clipping
        shape = self.shape.transform_copy(self.transformation)
        return clipping.encloses(coord=point, points=shape.points)

    def expand_transform(self):
        """ Expand the transform by applying it to the shape. """
        from spira.core.transforms.identity import IdentityTransform
        if not self.transformation.is_identity():
            self.shape = self.shape.transform_copy(self.transformation)
            self.transformation = IdentityTransform()
        return self

    def flatten(self, level=-1, name_tree=[]):
        """ Flatten the polygon without creating a copy. """
        return self.expand_transform()

    def stretch(self, factor=(1, 1), center=(0, 0)):
        """ Stretches the polygon by a factor. """
        T = spira.Stretch(stretch_factor=factor, stretch_center=center)
        return T.apply(self)

    def stretch_copy(self, factor=(1, 1), center=(0, 0)):
        """ Stretches a copy of the polygon by a factor. """
        T = spira.Stretch(stretch_factor=factor, stretch_center=center)
        return T.apply_copy(self)

    def stretch_port(self, port, destination):
        """ The element by moving the subject port, without 
        distorting the entire element. Note: The opposite 
        port position is used as the stretching center. """
        opposite_port = bbox_info.bbox_info_opposite_boundary_port(self, port)
        T = stretching.stretch_element_by_port(self, opposite_port, port,
                                               destination)
        T.apply(self)
        return self

    def move(self, midpoint=(0, 0), destination=None, axis=None):
        """ Moves the polygon from `midpoint` to a `destination`. """
        from spira.yevon.geometry.ports import Port

        if destination is None:
            destination = midpoint
            midpoint = Coord(0, 0)

        if isinstance(midpoint, Coord):
            m = midpoint
        elif np.array(midpoint).size == 2:
            m = Coord(midpoint)
        # elif issubclass(type(midpoint), __Port__):
        elif isinstance(midpoint, Port):
            m = midpoint.midpoint
        else:
            raise ValueError('Midpoint error')

        # if issubclass(type(destination), __Port__):
        if isinstance(destination, Port):
            d = destination.midpoint
        if isinstance(destination, Coord):
            d = destination
        elif np.array(destination).size == 2:
            d = Coord(destination)
        else:
            raise ValueError('Destination error')

        dxdy = d - m
        self.translate(dxdy)
        return self
示例#6
0
class __ShapeElement__(__LayerElement__):
    """ Base class for an edge element. """

    shape = ShapeParameter()

    @property
    def points(self):
        return self.shape.points

    @property
    def area(self):
        return gdspy.Polygon(self.shape.points).area()

    @property
    def count(self):
        return np.size(self.shape.points, 0)

    @property
    def center(self):
        return self.bbox_info.center

    @center.setter
    def center(self, destination):
        self.move(midpoint=self.center, destination=destination)

    @property
    def bbox_info(self):
        return self.shape.bbox_info.transform_copy(self.transformation)

    def id_string(self):
        sid = '{} - hash {}'.format(self.__repr__(), self.shape.hash_string)
        return sid

    def is_empty(self):
        """ Returns `False` is the polygon shape has no points. """
        return self.shape.is_empty()

    def encloses(self, point):
        """ Returns `True` if the polygon encloses the point. """
        from spira.yevon.utils import clipping
        shape = self.shape.transform_copy(self.transformation)
        return clipping.encloses(coord=point, points=shape.points)

    def expand_transform(self):
        """ Expand the transform by applying it to the shape. """
        from spira.core.transforms.identity import IdentityTransform
        if not self.transformation.is_identity():
            self.shape = self.shape.transform_copy(self.transformation)
            self.transformation = IdentityTransform()
        return self

    # FIXME: Move this to an output generator.
    def convert_to_gdspy(self, transformation=None):
        """ Converts a SPiRA polygon to a Gdspy polygon.
        The extra transformation parameter is the
        polygon edge ports. """
        layer = RDD.GDSII.EXPORT_LAYER_MAP[self.layer]
        T = self.transformation + transformation
        shape = self.shape.transform_copy(T)
        return gdspy.Polygon(points=shape.points,
                             layer=layer.number,
                             datatype=layer.datatype)