Example #1
0
class ShapeStub(__ShapeModifier__):
    """ stubs the corners of a given shape """
    stub_width = NonNegativeNumberProperty(required = True)
    only_sharp_angles = BoolProperty(default = False)
    

    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
Example #2
0
class DisplayStyle(StrongPropertyInitializer):
    color = ColorProperty(default=COLOR_BLACK)
    edgecolor = ColorProperty(default=COLOR_BLACK)
    stipple = StippleProperty(default=STIPPLE_NONE)
    alpha = RestrictedProperty(restriction=RESTRICT_FRACTION, default=1.0)

    edgewidth = NonNegativeNumberProperty(default=1.0)
    visible = BoolProperty(default=True)

    def __str__(self):
        return "DisplayStyle : color: %s - edgecolor: %s - stipple: %s - alpha: %f - edgewidth: %f - visible: %s" % (
            str(self.color), str(self.edgecolor), str(
                self.stipple), self.alpha, self.edgewidth, self.visible)

    def blend(self, other, fraction_first_color=0.33):
        result_color_red = fraction_first_color * self.color.red + (
            1.0 - fraction_first_color) * other.color.red
        result_color_green = fraction_first_color * self.color.green + (
            1.0 - fraction_first_color) * other.color.green
        result_color_blue = fraction_first_color * self.color.blue + (
            1.0 - fraction_first_color) * other.color.blue
        result_color = Color(
            name="#%02X%02X%02X" %
            (result_color_red, result_color_green, result_color_blue),
            red=result_color_red,
            green=result_color_green,
            blue=result_color_blue)
        result_ds = DisplayStyle(color=result_color,
                                 edgecolor=self.edgecolor,
                                 stipple=self.stipple,
                                 alpha=self.alpha)
        return result_ds
Example #3
0
class ShapeEllipseArc(Shape):
    """ ellipse arc around a given center """
    center = Coord2Property(default=(0.0, 0.0))
    box_size = Size2Property(default=(1.0, 1.0))
    start_angle = AngleProperty(default=0.0)
    end_angle = AngleProperty(default=90.0)
    angle_step = AngleProperty(default=TECH.METRICS.ANGLE_STEP)
    clockwise = BoolProperty(default=False)

    def __init__(self, **kwargs):
        super(ShapeEllipseArc, self).__init__(**kwargs)

    def define_points(self, pts):
        sa = self.start_angle * DEG2RAD
        ea = self.end_angle * DEG2RAD
        h_radius = self.box_size[0] / 2.0
        v_radius = self.box_size[1] / 2.0
        n_s = float(self.end_angle - self.start_angle) / self.angle_step
        n_steps = int(math.ceil(abs(n_s))) * numpy.sign(n_s)
        if n_steps == 0:
            if sa == ea:
                pts = numpy.array([[
                    math.cos(sa) * h_radius + self.center[0],
                    math.sin(sa) * v_radius + self.center[1]
                ]])
            else:
                pts = numpy.array([[
                    math.cos(sa) * h_radius + self.center[0],
                    math.sin(sa) * v_radius + self.center[1]
                ], [
                    math.cos(ea) * h_radius + self.center[0],
                    math.sin(ea) * v_radius + self.center[1]
                ]])
            return pts

        angle_step = float(ea - sa) / n_steps
        if self.clockwise:
            angle_step = -angle_step
            sign = -1
        else:
            sign = +1
        while sign * sa > sign * ea:
            ea += sign * 2 * math.pi

        angles = numpy.arange(sa, ea + 0.5 * angle_step, angle_step)
        pts = numpy.column_stack(
            (numpy.cos(angles), numpy.sin(angles))) * numpy.array([
                (h_radius, v_radius)
            ]) + numpy.array([(self.center[0], self.center[1])])
        return pts

    def move(self, position):
        self.center = (self.center.x + position[0],
                       self.center.y + position[1])
        return self

    def is_empty(self):
        return self.start_angle == self.end_angle or self.box_size[0] == 0.0 or self.box_size[1] == 0.0
Example #4
0
class ShapeRoundedRectangleArc(Shape):
    center = Coord2Property(default=(0.0, 0.0))
    box_size = Size2Property(default=(1.0, 1.0))
    radius = PositiveNumberProperty(default=0.1)
    start_angle = AngleProperty(default=0.0)
    end_angle = AngleProperty(default=90.0)
    angle_step = AngleProperty(default=TECH.METRICS.ANGLE_STEP)
    clockwise = BoolProperty(default=False)

    def __init__(self, **kwargs):
        super(ShapeRoundedRectangleArc, self).__init__(**kwargs)
        # restrict radius
        if self.radius > min(self.box_size) / 2.0:
            self.radius = min(self.box_size) / 2.0

    def define_points(self, pts):
        cx = self.center[0]
        cy = self.center[1]
        dx = 0.5 * self.box_size[0]
        dy = 0.5 * self.box_size[1]
        if self.clockwise:
            as_sign = -1
        else:
            as_sign = 1
        # radius = box: circle arc
        if (self.radius == self.box_size[0] / 2.0) and (
                self.radius == self.box_size[1] / 2.0):
            pts += ShapeArc(
                self.center,
                self.radius,
                self.start_angle,
                self.end_angle,
                angle_step=self.angle_step,
                clockwise=self.clockwise)
        # radius = zero: part of rectangle
        elif self.radius <= 0:
            for a in arange(self.start_angle, self.end_angle + 45.0,
                            as_sign * 90.0):
                pts += [(cx + sign(math.cos(DEG2RAD * a)) * dx,
                         cy + sign(math.sin(DEG2RAD * a)) * dy)]
        # arbitrary
        else:
            for a in numpy.arange(self.start_angle, self.end_angle + 45.0,
                                  as_sign * 90.0):
                start = max(self.start_angle,
                            a - a % 90.0 + 45.0 - as_sign * 45.0)
                end = min(self.end_angle, a - a % 90.0 + 45.0 + as_sign * 45.0)
                pts += ShapeArc(
                    center=(cx + numpy.sign(math.cos(DEG2RAD * a)) *
                            (dx - self.radius),
                            cy + numpy.sign(math.sin(DEG2RAD * a)) *
                            (dy - self.radius)),
                    radius=self.radius,
                    start_angle=start,
                    end_angle=end,
                    angle_step=self.angle_step,
                    clockwise=self.clockwise)
        return pts
Example #5
0
class GenericGdsiiPPLayerOutputMap(StrongPropertyInitializer):
    pplayer_map = DictProperty(
        doc="map of (process, purpose) to (layer,datatype)")
    ignore_undefined_mappings = BoolProperty(default=False)

    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 get(self, key, default):
        return self.__getitem__(key, default)
Example #6
0
class GdsiiPPLayerInputMap(GdsiiPPLayerOutputMap):
    ignore_undefined_mappings = BoolProperty(default=False)

    def define_layer_map(self):
        layer_map = super(GdsiiPPLayerInputMap, self).define_layer_map()
        reverse_layer_map = dict()
        for pplayer, gdsiilayer in layer_map.items():
            reverse_layer_map[(gdsiilayer.number,
                               gdsiilayer.datatype)] = pplayer
        return reverse_layer_map

    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)
Example #7
0
class ShapeSerif(__ShapeModifier__):
    """ puts a bump on the corners of a given shape """
    stub_width = PositiveNumberProperty(required=True)
    stub_height = PositiveNumberProperty(required=True)
    tip_width = NonNegativeNumberProperty(required=True)
    only_sharp_angles = BoolProperty(default=False)

    def __init__(self, **kwargs):
        super(ShapeSerif, self).__init__(**kwargs)
        if self.original_shape.closed:
            self.close()
        else:
            self.open()

    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
Example #8
0
class NoDistortTransform(GenericNoDistortTransform):
    """ A homothetic transformation that does not distort the item it is applied to (angle conservation) 
        The transform is defined by 
        - a mirror around the x-axis
        - a scaling with respect to the origin
        - a rotation around the origin
        - a translation
        
        it is also possible to set absolute magnification and rotation, which means that subsequent transformations
        will not affect the angle and size any further
        """
    # FIXME : Use transformation matrix which is computed once (and cached)
    
    def __init__(self, translation = (0.0, 0.0), rotation = 0.0, magnification = 1.0, v_mirror = False, absolute_magnification = False, absolute_rotation = False, **kwargs):
        # note: translation is no part of gdsII transform. It should be taken into account while writing the file
        super(NoDistortTransform, self).__init__(
            translation = translation,
            rotation = rotation,
            magnification = magnification,
            v_mirror = v_mirror,
            absolute_magnification = absolute_magnification,
            absolute_rotation =absolute_rotation,
            **kwargs)

    translation = Coord2Property("__translation__", default = (0.0, 0.0))
    """ the translation coordinate """
    
   
    #def get_rotation (self): return self.rotation
    def set_rotation(self, value):
        self.__rotation__ = value % 360.0
        if value % 90.0 == 0.0:
            # make sure sine and cosine are really zero when needed!
            if self.__rotation__ == 0.0:
                self.__ca__ = 1.0
                self.__sa__ = 0.0
            elif self.__rotation__ == 90.0:
                self.__ca__ = 0.0
                self.__sa__ = 1.0
            elif self.__rotation__ == 180.0:
                self.__ca__ = -1.0
                self.__sa__ = 0.0
            elif self.__rotation__ == 270.0:
                self.__ca__ = 0.0
                self.__sa__ = -1.0
        else:
            self.__ca__ = cos(value * DEG2RAD)
            self.__sa__ = sin(value * DEG2RAD)
    rotation = SetFunctionProperty("__rotation__", set_rotation, default=0.0)
    """ the rotation around the origin """

    magnification = NumberProperty("__magnification__", restriction = RESTRICT_NONZERO, default = 1.0)
    """ the magnification factor """

    v_mirror = BoolProperty("__v_mirror__", default = False)
    """ the vertical mirror """
    flip = v_mirror
    

    #""" set absolute magnification on or off"""
    absolute_magnification = BoolProperty("__absolute_magnification__", default = False)
    
    #""" set absolute rotation on or off"""
    absolute_rotation = BoolProperty("__absolute_rotation__", default = False)
    
    def __make_simple__(self):
        """ internal use: reduces special subclasses to this generic type """
        # if you change special types, they should revert to generic type
        self.__class__ = NoDistortTransform

    def __translate__(self, coord):
        """ internal use: applies translation to a coordinate """
        return Coord2(coord[0] + self.translation.x, coord[1] + self.translation.y)
    
    def __rotate__(self, coord):
        """ internal use: applies rotation to a coordinate """
        return Coord2(coord[0] * self.__ca__ - coord[1] * self.__sa__, coord[0] * self.__sa__ + coord[1] * self.__ca__)

    def __magnify__(self, coord):
        """ internal use: applies magnification to a coordinate """
        return Coord2(coord[0] * self.magnification, coord[1] * self.magnification)

    def __v_flip__(self, coord):
        """ internal use: applies v_mirror to a coordinate """
        if self.v_mirror:
            return Coord2(coord[0], -coord[1])
        else:
            return Coord2(coord[0], coord[1])

    def __inv_translate__(self, coord):
        """ internal use: applies reverse translation to a coordinate """
        return Coord2(coord[0] - self.translation.x, coord[1] - self.translation.y)
    
    def __inv_rotate__(self, coord):
        """ internal use: applies reverse rotation to a coordinate """
        return Coord2(coord[0] * self.__ca__ + coord[1] * self.__sa__, - coord[0] * self.__sa__ + coord[1] * self.__ca__)

    def __inv_magnify__(self, coord):
        """ internal use: applies reverse magnification to a coordinate """
        return Coord2(coord[0] / self.magnification, coord[1] / self.magnification)

    def __inv_v_flip__(self, coord):
        """ internal use: applies reverse v_mirror to a coordinate """
        if self.v_mirror:
            return Coord2(coord[0], - coord[1])
        else:
            return Coord2(coord[0], coord[1])

    def __translate3__(self, coord):
        """ internal use: applies translation to a 3d coordinate """
        return Coord3(coord[0] + self.translation.x, coord[1] + self.translation.y, coord[2])
    
    def __rotate3__(self, coord):
        """ internal use: applies rotation to a 3d coordinate """
        return Coord3(coord[0] * self.__ca__ - coord[1] * self.__sa__, coord[0] * self.__sa__ + coord[1] * self.__ca__, coord[2])

    def __magnify3__(self, coord):
        """ internal use: applies magnification to a 3d coordinate """
        return Coord3(coord[0] * self.magnification, coord[1] * self.magnification, coord[2])

    def __v_flip3__(self, coord):
        """ internal use: applies v_mirror to a 3d coordinate """
        if self.v_mirror:
            return Coord3(coord[0], -coord[1], coord[2])
        else:
            return Coord3(coord[0], coord[1], coord[2])

    def __inv_translate3__(self, coord):
        """ internal use: applies reverse translation to a 3d coordinate """
        return Coord3(coord[0] - self.translation.x, coord[1] - self.translation.y, coord[2])
    
    def __inv_rotate3__(self, coord):
        """ internal use: applies reverse rotation to a 3d coordinate """
        return Coord3(coord[0] * self.__ca__ + coord[1] * self.__sa__, - coord[0] * self.__sa__ + coord[1] * self.__ca__, coord[2])

    def __inv_magnify3__(self, coord):
        """ internal use: applies reverse magnification to a 3d coordinate """
        return Coord3(coord[0] / self.magnification, coord[1] / self.magnification, coord[2])

    def __inv_v_flip3__(self, coord):
        """ internal use: applies reverse v_mirror to a 3d coordinate """
        if self.v_mirror:
            return Coord3(coord[0], - coord[1], coord[2])
        else:
            return Coord3(coord[0], coord[1], coord[2])
        
    def __translate_array__(self, coords):
        """ internal use: applies translation to a numpy array """
        coords += numpy.array([self.translation.x, self.translation.y])
        return coords
    
    def __rotate_array__(self, coords):
        """ internal use: applies rotation to a numpy array """
        x_a = numpy.array([self.__ca__, -self.__sa__])
        y_a = numpy.array([self.__sa__, self.__ca__])
        coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1))))
        return coords

    def __magnify_array__(self, coords):
        """ internal use: applies magnification to a numpy array """
        coords *= numpy.array([self.magnification, self.magnification])
        return coords

    def __v_flip_array__(self, coords):
        """ internal use: applies v_mirror to a numpy array """
        coords *= (numpy.array([False, self.v_mirror]) * -2.0 + 1.0)
        return coords

    def __inv_translate_array__(self, coords):
        """ internal use: applies reverse translation to a numpy array """
        coords -= numpy.array([self.translation.x, self.translation.y])
        return coords
    
    def __inv_rotate_array__(self, coords):
        """ internal use: applies reverse rotation to a numpy array """
        x_a = array([self.__ca__, self.__sa__])
        y_a = array([-self.__sa__, self.__ca__])
        coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1))))
        return coords

    def __inv_magnify_array__(self, coords):
        """ internal use: applies reverse magnification to a numpy array """
        coords *= numpy.array([1.0 / self.magnification, 1.0 / self.magnification])
        return coords

    def __inv_v_flip_array__(self, coords):
        """ internal use: applies reverse v_mirror to a numpy array """
        coords *= numpy.array([False, self.v_mirror]) * (-2.0) + 1.0
        return coords

    def __translate_array3__(self, coords):
        """ internal use: applies translation to a numpy array """
        coords += numpy.array([self.translation.x, self.translation.y, 0.0])
        return coords
    
    def __rotate_array3__(self, coords):
        """ internal use: applies rotation to a numpy array """
        x_a = numpy.array([self.__ca__, -self.__sa__, 0])
        y_a = numpy.array([self.__sa__, self.__ca__, 0])
        z_a = numpy.array([0, 0, 1.0])
        
        coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1), numpy.sum(coords * z_a, 1))))
        return coords

    def __magnify_array3__(self, coords):
        """ internal use: applies magnification to a numpy array """
        coords *= numpy.array([self.magnification, self.magnification, 1.0])
        return coords

    def __v_flip_array3__(self, coords):
        """ internal use: applies v_mirror to a numpy array """
        coords *= (numpy.array([False, self.v_mirror, False]) * -2.0 + 1.0)
        return coords

    def __inv_translate_array3__(self, coords):
        """ internal use: applies reverse translation to a numpy array """
        coords -= numpy.array([self.translation.x, self.translation.y, 0.0])
        return coords
    
    def __inv_rotate_array3__(self, coords):
        """ internal use: applies reverse rotation to a numpy array """
        x_a = array([self.__ca__, self.__sa__, 0.0])
        y_a = array([-self.__sa__, self.__ca__, 0.0])
        z_a = numpy.array([0, 0, 1.0])
        
        coords = numpy.transpose(numpy.vstack((numpy.sum(coords * x_a, 1), numpy.sum(coords * y_a, 1), numpy.sum(coords * z_a, 1))))
        return coords

    def __inv_magnify_array3__(self, coords):
        """ internal use: applies reverse magnification to a numpy array """
        coords *= numpy.array([1.0 / self.magnification, 1.0 / self.magnification, 1.0])
        return coords

    def __inv_v_flip_array3__(self, coords):
        """ internal use: applies reverse v_mirror to a numpy array """
        coords *= numpy.array([False, self.v_mirror, False]) * (-2.0) + 1.0
        return coords

    def apply_to_coord(self, coord):
        """ applies transformation to a coordinate """
        # this could be speeded up
        # Check the east order
        coord = self.__v_flip__(coord)# first flip 
        coord = self.__rotate__(coord)# then magnify
        coord = self.__magnify__(coord)# then rotate
        coord = self.__translate__(coord) # finally translate
        return coord
    
    def reverse_on_coord(self, coord):
        """ applies reverse transformation to a coordinate """
        # this could be speeded up
        # Check the right order
        coord = self.__inv_translate__(coord) # finally translate
        coord = self.__inv_magnify__(coord)# then rotate
        coord = self.__inv_rotate__(coord)# then magtnify
        coord = self.__inv_v_flip__(coord)# first flip 
        return coord

    def apply_to_array(self, coords):
        """ internal use: applies transformation to a numpy array"""
        # this could be speeded up
        # Check the right order
        coords = self.__v_flip_array__(coords)# first flip 
        coords = self.__rotate_array__(coords)# then rotate
        coords = self.__magnify_array__(coords)# then magnify
        coords = self.__translate_array__(coords) # finally translate
        return coords
    
    def reverse_on_array(self, coord):
        """ internal use: applies reverse transformation to a numpy array """
        # this could be speeded up
        # Check the right order
        coords = self.__inv_translate_array__(coords) # finally translate
        coords = self.__inv_magnify_array__(coords)# then magnify
        coords = self.__inv_rotate_array__(coords)# then rotate
        coords = self.__inv_v_flip_array__(coords)# first flip 
        return coords    

    def apply_to_coord3(self, coord):
        """ applies transformation to a coordinate """
        # this could be speeded up
        # Check the east order
        coord = self.__v_flip3__(coord)# first flip 
        coord = self.__rotate3__(coord)# then magnify
        coord = self.__magnify3__(coord)# then rotate
        coord = self.__translate3__(coord) # finally translate
        return coord
    
    def reverse_on_coord3(self, coord):
        """ applies reverse transformation to a coordinate """
        # this could be speeded up
        # Check the right order
        coord = self.__inv_translate3__(coord) # finally translate
        coord = self.__inv_magnify3__(coord)# then rotate
        coord = self.__inv_rotate3__(coord)# then magtnify
        coord = self.__inv_v_flip3__(coord)# first flip 
        return coord

    def apply_to_array3(self, coords):
        """ internal use: applies transformation to a numpy array"""
        # this could be speeded up
        # Check the right order
        coords = self.__v_flip_array3__(coords)# first flip 
        coords = self.__rotate_array3__(coords)# then rotate
        coords = self.__magnify_array3__(coords)# then magnify
        coords = self.__translate_array3__(coords) # finally translate
        return coords
    
    def reverse_on_array3(self, coord):
        """ internal use: applies reverse transformation to a numpy array """
        # this could be speeded up
        # Check the right order
        coords = self.__inv_translate_array3__(coords) # finally translate
        coords = self.__inv_magnify_array3__(coords)# then magnify
        coords = self.__inv_rotate_array3__(coords)# then rotate
        coords = self.__inv_v_flip_array3__(coords)# first flip 
        return coords    
    
    
    def apply_to_angle_deg(self, angle):
        """ applies transformation to an absolute angle (degrees) """
        a = angle
        if self.v_mirror:
            a = -a
        a += self.rotation
        return a % 360.0
    
    def reverse_on_angle_deg(self, angle):
        """ applies reverse transformation to an absolute angle (degrees)"""
        a = angle - self.rotation
        if self.v_mirror:
            a = -a
        return a % 360.0

    def apply_to_angle_rad(self, angle):
        """ applies transformation to an absolute angle (radians) """
        a = angle
        if self.v_mirror:
            a = -a
        a += self.rotation * DEG2RAD
        return a % (2 * pi)
    
    def reverse_on_angle_rad(self, angle):
        """ applies reverse transformation to an absolute angle (radians) """
        a = angle - self.rotation * DE2RAD
        if self.v_mirror:
            a = -a
        return a % (2 * pi)

    def apply_to_length(self, length):
        """ applies transformation to a distance """
        return length * self.magnification

    def reverse_on_length(self, length):
        """ applies reverse transformation to a distance """
        return length / self.magnification

    def __neg__(self):
        """ returns the reverse transformation """
        from .translation import Translation
        from .rotation import Rotation
        from .magnification import Magnification
        from .mirror import VMirror
        
        T = Translation(- self.translation) + Magnification((0.0, 0.0), 1 / self.magnification) + Rotation((0.0, 0.0), -self.rotation)
        if self.v_mirror:
            T += VMirror(0.0)
        return T

    def __sub__(self, other):
        """ returns the concatenation of this transform and the reverse of other """
        if other is None: return copy.deepcopy(self)
        if not isinstance(other, __ReversibleTransform__):
            raise TypeError("Cannot subtract an irreversible transform")
        return self.__add__(-other)

    def __isub__(self, other):
        """ concatenates the reverse of other to this transform """
        if other is None: return self
        if not isinstance(other, __ReversibleTransform__):
            raise TypeError("Cannot subtract an irreversible transform")
        return self.__iadd__(self, -other)

    def __add__(self, other):
        """ returns the concatenation of this transform and other """
        # performs transformation "other" after "self" and returns resulting transform
        if other is None: return copy.deepcopy(self)

        if isinstance(other, NoDistortTransform):
            T = NoDistortTransform()

            if self.absolute_magnification:
                M1 = 1.0
            else:
                M1 = other.magnification
            T.magnification = self.magnification * M1

            #flip signs
            if other.v_mirror: s_1 = -1
            else:              s_1 = 1

            if not self.absolute_rotation:
                T.rotation = s_1 * self.rotation + other.rotation
                ca = other.__ca__
                sa = other.__sa__
            else:
                T.rotation = s_1 * self.rotation
                ca = 1.0
                sa = 0.0


            # tricky part: translation
            T.translation = Coord2(other.translation.x + ca * self.translation.x * M1 - s_1 * sa * self.translation.y * M1,
                                   other.translation.y + sa * self.translation.x * M1 + s_1 * ca * self.translation.y * M1)

            T.absolute_rotation = self.absolute_rotation or other.absolute_rotation
            T.absolute_magnification = self.absolute_magnification or other.absolute_magnification
            T.v_mirror = (not self.v_mirror == other.v_mirror)
        else:
            T = Transform.__add__(self, other)
        return T

    def __iadd__(self, other):
        """ concatenates other to this transform """
        if other is None: return self
        # performs transformation other after self and returns self
        if isinstance(other, NoDistortTransform):
            # tricky part: translation
            if self.absolute_magnification:
                self.magnification = self.magnification * other.magnification
                M1 = 1
            else:
                M1 = other.magnification

            #flip signs
            if other.v_mirror: s_1 = -1
            else:              s_1 = 1


            if not self.absolute_rotation:
                self.rotation = s_1 * self.rotation + other.rotation
                ca = other.__ca__
                sa = other.__sa__
            else:
                self.rotation = s_1 * self.rotation                
                ca = 1
                sa = 0

            # tricky part: translation
            self.translation = (other.translation.x + ca * self.translation.x * M1 - s_1 * sa * self.translation.y * M1,
                                other.translation.y + sa * self.translation.x * M1 + s_1 * ca * self.translation.y * M1)

            self.absolute_rotation = self.absolute_rotation or other.absolute_rotation
            self.absolute_magnification = self.absolute_magnification or other.absolute_magnification
            self.v_mirror = (not self.v_mirror == other.v_mirror)
        else:
            raise TypeError("Error: Cannot perform += operation for NoDistortTransform and other transform of type " + str(type(other)))
        return self
    
    def __eq__(self, other):
        """ check if the transforms do the same thing """
        if other is None: return self.is_identity()
        if not isinstance(other, NoDistortTransform): return False
        return ((self.rotation == other.rotation) and
                (self.translation == other.translation) and
                (self.v_mirror == other.v_mirror) and
                (self.magnification == other.magnification) and
                (self.absolute_rotation == other.absolute_rotation) and
                (self.absolute_magnification == other.absolute_magnification)
                )

    def __ne__(self, other):
        """ checks if the transforms do different things """

        if other is None: return not self.is_identity()
        if not isinstance(other, NoDistortTransform): return False
        return ((self.rotation != other.rotation) or
                (self.translation != other.translation) or
                (self.v_mirror != other.v_mirror) or
                (self.magnification != other.magnification) or
                (self.absolute_rotation != other.absolute_rotation) or 
                (self.absolute_magnification != other.absolute_magnification)
                )
        
    def is_identity(self):
        """ returns True if the transformation does nothing """
        return ((self.rotation == 0.0) and
                (self.translation.x == 0.0) and
                (self.translation.y == 0.0) and
                not (self.v_mirror) and 
                (self.magnification == 1.0)
            )

    def is_isometric(self):
        """ returns True if the transformation conserves angles and distances """
        return self.magnification == 1.0

    def is_homothetic(self):
        """ returns True if the transformation conserves angles """
        return True

    def is_orthogonal(self):
        """ returns True if the transformation does only rotate on 90degree angles """
        return (self.rotation % 90.0) == 0.0

    def is_octogonal(self):
        """ returns True if the transformation does only rotate on 45degree angles """
        return (self.rotation % 45.0) == 0.0
    
    def id_string(self):
        """ gives a hash of the transform (for naming purposes) """
        return str(hash("R" + str(int(self.rotation * 10000)) + 
                        "T" + str(int(self.translation[0] * 1000)) + "_" + str(int(self.translation[1] * 1000)) +
                        "M" + str(int(self.magnification * 1000)) +
                        "V" + str(self.v_mirror) +
                        "AM" + str(self.absolute_magnification) +
                        "AR" + str(self.absolute_rotation) 
                        ))
    
    def __str__(self):
        """ gives a string representing the transform """
        return "R=%s-T=%s-M=%s-V=%s-AM=%s-AR=%s" % (str(int(self.rotation * 10000)), 
                                        str(int(self.translation[0] * 1000)) + "_" + str(int(self.translation[1] * 1000)),
                                        str(int(self.magnification * 1000)),
                                        str(self.v_mirror),
                                        str(self.absolute_magnification),
                                        str(self.absolute_rotation))    
Example #9
0
class OutputGdsii(OutputBasic):
    """ Writes GDS output to a stream """
    userefcache = BoolProperty(default=False)
    name_filter = RestrictedProperty(
        default=TECH.GDSII.NAME_FILTER,
        restriction=RestrictType(Filter),
        doc="filter class which is applied to all names")

    def __init__(self, o_stream=sys.stdout, **kwargs):
        kwargs["allow_unmatched_kwargs"] = True
        super(OutputGdsii, self).__init__(o_stream=o_stream, **kwargs)
        if 'flatten_structure_container' in kwargs:
            self.flatten_structure_container = kwargs.get(
                'flatten_structure_container')
        elif hasattr(TECH.GDSII, 'FLATTEN_STRUCTURE_CONTAINER'):
            self.flatten_structure_container = TECH.GDSII.FLATTEN_STRUCTURE_CONTAINER
        else:
            self.flatten_structure_container = False
        self.__ref_referenced_structures__ = set()
        if sys.platform == "win32":
            import os
            import msvcrt
            msvcrt.setmode(self.o_stream.fileno(), os.O_BINARY)

    def __init_collector__(self):
        self.collector = StreamA2BHexCollector(o_stream=self.o_stream)

    def collect(self, item, **kwargs):
        self.do_collect(item, **kwargs)
        return

    #----------------------------------------------------------------------------
    #Layout-level output functions
    #----------------------------------------------------------------------------

    def collect_Library(self, library, **kwargs):
        self.__collect_library_header__(library)
        unreferenced_structures = self.library.unreferenced_structures(
            usecache=self.userefcache)
        referenced_structures = self.library.referenced_structures(
            usecache=self.userefcache)
        self.collect(unreferenced_structures, **kwargs)
        collected_referenced_structures = []
        while len(self.__ref_referenced_structures__) > 0:
            for rs in referenced_structures:
                if rs in self.__ref_referenced_structures__:
                    self.collect(rs, **kwargs)
                    collected_referenced_structures.append(rs)
            for crs in collected_referenced_structures:
                referenced_structures.remove(crs)
            self.__ref_referenced_structures__.clear()
        self.__collect_library_footer__()
        return

    def __collect_library_header__(self, library):
        self.collector += [
            __str_record__(gds_records.Header, __hex_int2__(5)),
            __str_record__(
                gds_records.BgnLib,
                __hex_date__(library.modified) +
                __hex_date__(library.accessed)),
            __str_record__(gds_records.LibName, __hex_text__(library.name)),
            __str_record__(
                gds_records.Units,
                __hex_float__(self.library.grid / self.library.unit) +
                __hex_float__(self.library.grid))
        ]
        return

    def __collect_library_footer__(self):
        self.library = None
        self.collector += [__str_record__(gds_records.EndLib)]
        return

    def __collect_structure_header__(self, item):
        sname = self.name_filter(item.name)[0]
        self.collector += [
            __str_record__(
                gds_records.BgnStr,
                __hex_date__(item.created) + __hex_date__(item.modified)),
            __str_record__(gds_records.StrName, __hex_text__(sname))
        ]

    #generate the footer for any structure
    def __collect_structure_footer__(self, item):
        self.collector += [__str_record__(gds_records.EndStr)]
        return

    #----------------------------------------------------------------------------
    #__Element__ level output functions
    #----------------------------------------------------------------------------

    #text
    def collect_Label(self, item, additional_transform=None):
        T = item.transformation + additional_transform  # make a copy because there is also the height
        layer = self.map_layer(item.layer)
        if layer is None:
            return
        coordinates = [T.__translate__(item.coordinate)]
        T.magnification *= item.height
        self.collector += [
            __str_record__(gds_records.Text),
            self.__str_layer__(layer.number),
            __str_record__(gds_records.TextType, __hex_int2__(0)),
            __str_record__(
                gds_records.Presentation,
                __hex_int2__((item.h_alignment + 4 * item.v_alignment +
                              8 * item.font % 4))),
            __str_record__(gds_records.PathType, __hex_int2__(1))
        ]
        self.collector += __list_transformation__(T)
        self.collector += [
            self.__str_coordinatelist__(coordinates),
            __str_record__(gds_records.String, __hex_text__(item.text)),
            __str_record__(gds_records.EndEl)
        ]
        return

    #references
    def collect_SRef(self, item, additional_transform=None):
        T = item.transformation + Translation(
            item.position.snap_to_grid()) + additional_transform
        coordinates = Shape((0.0, 0.0)).transform(T)
        sname = self.name_filter(item.reference.name)[0]
        self.collector += [
            __str_record__(gds_records.SRef),
            __str_record__(gds_records.SName, __hex_text__(sname))
        ]
        self.collector += __list_transformation__(T)
        self.collector += [
            self.__str_coordinatelist__(coordinates),
            __str_record__(gds_records.EndEl)
        ]
        self.__ref_referenced_structures__.add(item.reference)

    def collect_ARef(self, item, additional_transform=None):
        T = item.transformation + Translation(
            item.origin) + additional_transform
        p = Coord2(item.period).snap_to_grid()
        corner1 = Coord2(item.n_o_periods[0] * p[0], 0.0)
        corner2 = Coord2(0.0, item.n_o_periods[1] * p[1])
        coordinates = Shape([(0.0, 0.0), corner1, corner2]).transform(T)
        sname = self.name_filter(item.reference.name)[0]
        self.collector += [
            __str_record__(gds_records.ARef),
            __str_record__(gds_records.SName, __hex_text__(sname))
        ]
        self.collector += __list_transformation__(T)
        self.collector += [
            __str_record__(
                gds_records.ColRow,
                __hex_int2__(item.n_o_periods[0]) +
                __hex_int2__(item.n_o_periods[1])),
            self.__str_coordinatelist__(coordinates),
            __str_record__(gds_records.EndEl)
        ]
        self.__ref_referenced_structures__.add(item.reference)
        return

    def collect_BoxElement(self, item, additional_transform=None):
        T = item.transformation + additional_transform
        layer = self.map_layer(item.layer)
        if layer is None:
            return
        coordinates = T(ShapeRectangle(item.center, item.box_size)).tolist()
        self.collector += [
            __str_record__(gds_records.Box),
            self.__str_layer__(layer.number),
            __str_record__(gds_records.BoxType, __hex_int2__(0)),
            self.__str_coordinatelist__(coordinates),
            __str_record__(gds_records.EndEl)
        ]
        return

    def collect_path_element(self, layer, coordinates, line_width, path_type):
        L = self.map_layer(layer)
        if L is None:
            return
        self.collector += [
            __str_record__(gds_records.Path),
            self.__str_layer__(L.number),
            self.__str_datatype__(L.datatype),
            __str_record__(gds_records.PathType, __hex_int2__(path_type)),
            __str_record__(gds_records.Width,
                           __hex_int4__(self.__db_value__(line_width))),
            self.__str_shape__(coordinates),
            __str_record__(gds_records.EndEl)
        ]
        return

    def collect_boundary_element(self, layer, coordinates):
        L = self.map_layer(layer)
        if L is None:
            return

        self.collector += [
            __str_record__(gds_records.Boundary),
            self.__str_layer__(L.number),
            self.__str_datatype__(L.datatype),
            self.__str_shape__(coordinates),
            __str_record__(gds_records.EndEl)
        ]
        return

    def __collect_container_elements__(self, item, sref_level_counter):
        # FIXME. Containers are PICAZZO classes. This method should be converted to a Filter or a mixin
        from picazzo.container.container import __StructureContainer__
        from ipkiss.primitives.elements.reference import __RefElement__
        if isinstance(item, __StructureContainer__) and isinstance(
                item.elements[0], __RefElement__):
            sref = item.elements[0]
            sref_elements = sref.reference.elements
            sref_transformation = sref.transformation + Translation(
                translation=sref.position)
            sref_elements_transformed = sref_elements.transform_copy(
                transformation=sref_transformation)
            new_elements = ElementList()
            if (isinstance(sref.reference, __StructureContainer__)):
                (inner_container_elements,
                 sref_level_counter) = self.__collect_container_elements__(
                     sref.reference, sref_level_counter + 1)
                new_elements.extend(inner_container_elements)
                if len(item.elements) > 1:
                    new_elements.extend(item.elements[1:])
            else:
                new_elements.extend(sref_elements_transformed)
                if len(item.elements) > 1:
                    new_elements.extend(item.elements[1:])
            return (new_elements, sref_level_counter)
        else:
            return (item.elements, sref_level_counter)

    def collect___StructureContainer__(self, item):
        # FIXME. Containers are PICAZZO classes. This method should be converted to a Filter or a mixin
        from ipkiss.primitives.elements.reference import __RefElement__
        if self.flatten_structure_container and isinstance(
                item.elements[0], __RefElement__):
            sref = item.elements[0]
            (new_elements, sref_levels) = self.__collect_container_elements__(
                item=item, sref_level_counter=1)
            sref_transformation = sref.transformation + Translation(
                translation=sref.position)
            new_elements_transformed = new_elements.transform_copy(
                transformation=sref_transformation)
            if sref_levels >= 1:
                if len(item.elements) > 1:
                    new_elements_transformed.extend(item.elements[1:])
                item.__make_static__()
                item.elements = new_elements_transformed
                item.__make_dynamic__()
        self.collect_Structure(item)

    #----------------------------------------------------------------------------
    # unit conversion
    #----------------------------------------------------------------------------

    def __db_value__(self, value):
        #convents absolute coordinates to database units
        return round(value * self.__structure_scale__ * self.grids_per_unit)

    def __db_value_array__(
            self, value_array):  #faster, direct operation on numpy array
        result = np.round(value_array * self.__structure_scale__ *
                          self.grids_per_unit)
        return result

    #generate coordinate strings from a shape or list of coordinates
    def __str_coordinatelist__(self, coords):
        if isinstance(coords, Shape):
            db_value_coordinates = self.__db_value_array__(coords.points)
            ret_data = [
                "%s%s" % (__hex_int4__(c0), __hex_int4__(c1))
                for c0, c1 in db_value_coordinates
            ]
        else:
            ret_data = [
                "%s%s" % (__hex_int4__(self.__db_value__(
                    c[0])), __hex_int4__(self.__db_value__(c[1])))
                for c in coords
            ]
        return __str_record__(gds_records.XY, "".join(ret_data))

    def __str_shape__(self, coordinates):
        db_value_points = self.__db_value_array__(coordinates.points.ravel())
        ret_data = [__hex_int4__(p) for p in db_value_points]
        return __str_record__(gds_records.XY, "".join(ret_data))

    def __collect_shape__(self, coordinates):
        db_value_points = self.__db_value_array__(coordinates.points.ravel())
        ret_data = [__hex_int4__(p) for p in db_value_points]
        self.collector += [__str_record__(gds_records.XY, "".join(ret_data))]

    def __str_layer__(self, layer_number):
        return __str_record__(gds_records.Layer, __hex_int2__(layer_number))

    def __str_datatype__(self, datatype):
        return __str_record__(gds_records.DataType, __hex_int2__(datatype))
Example #10
0
class Path(__ShapeElement__):
    path_type = RestrictedProperty(restriction=RestrictValueList(
        constants.PATH_TYPES),
                                   default=constants.PATH_TYPE_NORMAL)
    absolute_line_width = BoolProperty(default=False)
    __min_length__ = 2

    def __init__(self,
                 layer,
                 shape,
                 line_width=1.0,
                 path_type=constants.PATH_TYPE_NORMAL,
                 transformation=None,
                 **kwargs):
        super(Path, self).__init__(layer=layer,
                                   shape=shape,
                                   line_width=line_width,
                                   path_type=path_type,
                                   transformation=transformation,
                                   **kwargs)

    def set_line_width(self, new_line_width):
        self.absolute_line_width = bool(new_line_width < 0)
        self.__line_width__ = abs(new_line_width)
        #line widths of zero must be allowed for e-beam

    line_width = SetFunctionProperty("__line_width__",
                                     set_line_width,
                                     required=True)

    def size_info(self):
        if self.line_width == 0.0:
            return self.shape.size_info.transform_copy(self.transformation)
        else:
            # this is slower, but accurate
            from ...geometry.shapes.modifiers import ShapePath
            return ShapePath(
                original_shape=self.shape,
                path_width=self.line_width,
                path_type=self.path_type).size_info.transform_copy(
                    self.transformation)
            # this is fast, but inaccurate
            #return self.shape.size_info().transform_copy(self.transformation)

    def convex_hull(self):
        if self.line_width == 0.0:
            return self.shape.convex_hull().transform(self.transformation)
        else:
            # this is slower, but accurate
            from ipkiss.geometry.shapes.modifiers import ShapePath
            return ShapePath(original_shape=self.shape,
                             path_width=self.line_width,
                             path_type=self.path_type).convex_hull().transform(
                                 self.transformation)
            # this is fast, but inaccurate
            #return self.shape.size_info().transform_copy(self.transformation)

    def flat_copy(self, level=-1):
        S = Path(layer=self.layer,
                 shape=self.shape,
                 line_width=self.line_width,
                 path_type=self.path_type,
                 transformation=self.transformation,
                 absolute_line_width=self.absolute_line_width)
        S.expand_transform()
        return S

    def expand_transform(self):
        if not self.transformation.is_identity():
            self.shape = self.shape.transform_copy(self.transformation)
            if not self.absolute_line_width:
                self.line_width = self.transformation.apply_to_length(
                    self.line_width)
            from ...geometry.transforms.identity import IdentityTransform
            self.transformation = IdentityTransform()
        return self
Example #11
0
class Library(UnitGridContainer, MixinBowl):
    name = StringProperty(required = True, doc="Unique name for the library")
    accessed = TimeProperty(doc = "Timestamp at which the library was accessed.")
    modified = TimeProperty(doc = "Timestamp at which the library was modified.")
    layout = BoolProperty(default = True, doc="Indicates whether the library contains a layout : in that case, there should be only 1 top-level structure.")
    allow_empty_structures = BoolProperty(default = True, doc="Indicates whether empty structures are allowed.")
    
    def __init__(self, name, **kwargs):
        super(Library, self).__init__(name=name, **kwargs)
        self.structures = StructureList()
        self.__referenced_structures = set()
        
    def snap_value(self,value):
        return settings.snap_value(value, self.grids_per_unit)

    def snap_coordinate(self,coordinate):
        return settings.snap_coordinate(coordinate, self.grids_per_unit)

    def snap_shape(self,coordinates):
        return settings.snap_shape(coordinates, self.grids_per_unit)

    def add(self,structure):
        if isinstance(structure, Structure) or isinstance(structure, StructureList):
            self.structures.add(structure)
        else:
            raise TypeError("Wrong type " + str(type(structure)) + "of argument in Library.structure_exists.")

    def __iadd__(self, other):
        if isinstance(other, Structure) or isinstance(other, StructureList):
            self.structures.add(other)
        elif isinstance(other, Library):
            for i in other.structures:
                self.structures.add(i)
        return self

    def structure_exists(self,structure):
        return structure in self.structures

    def clean_up(self):
        if self.allow_empty_structures: return

        # remove references to empty structures
        for s in self.structures:
            empty_e = []
            e_list = s.elements
            for i in range(len(e_list)):
                if e_list[i].is_empty: empty_e.append(i)
            del s.elements[empty_e]

        # remove empty structures
        empty_s = []
        for s in range(0,len(self.structures)):
            if self.structures[s].is_empty(): empty_s.append(s)
        del self.structures[empty_s]

    def is_empty(self):
        return len(self.structures) == 0

    def size_info(self):
        return self.top_layout().size_info()

    def flat_copy(self, level = -1):
        newlib = Library(self.name, self.unit, self.grid)
        for s in self.unreferenced_structures():
            newlib.add(s.flat_copy(level))
        newlib.collect_references()
        return newlib

    def flatten(self, level = -1):
        sl = StructureList()
        for s in self.unreferenced_structures():
            sl.add(s.flatten(level))
        self.structures = sl
        self.collect_references()
        return self


    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 set_referenced(self, struct):
        self.__referenced_structures.add(struct)
        
    def unreferenced_structures(self, usecache = False):
        """returns a list of unreferenced structures"""
        referred_to_list = self.referenced_structures(usecache = usecache)
        not_referred_to_list = StructureList()
        for s in self.structures:
            if not s in referred_to_list:
                not_referred_to_list.add(s)
        return not_referred_to_list

    def referenced_structures(self, usecache = False):
        """Build list of referred structures"""
        if usecache:
            return StructureList(self.__referenced_structures)
        referred_to_list = StructureList()
        for s in self.structures:
            referred_to_list.add(s.dependencies())
        return referred_to_list

    def collect_references(self, structure = None):
        if structure is None:
            s_list = self.structures
        else:
            s_list = StructureList(structure)
        new_s = StructureList()
        for s1 in s_list:
            d = s1.dependencies()
            for s2 in d:
                new_s.add(s2)
        self.add(new_s)

    def check_references(self):
        """check if all references belong to the library"""
        
        Referred_to_list = self.referenced_structures()
                
        for s in Referred_to_list:
            if not s in self.structures:
                LOG.error("The structure %s you refer to is not part of library %s " % (s.name, self.name))
                raise SystemExit

        Not_Referred_to_list = StructureList()
        for s in self.structures:
            if not Referred_to_list.__fast_contains__(s.name):
                Not_Referred_to_list.__fast_add__(s)
        if len(Not_Referred_to_list) == 0:
            return -2
        return 0

    def __fast_get_structure__(self, str_name):
        """ returns the structure if it exists or returns None"""
        for s in self.structures:
            if s.name == str_name: return s
        return None
    
    def __fast_add__(self, new_str):
        """add a structure without checking if the structure exists"""
        self.structures.__fast_add__(new_str)
        

    def __contains__(self, item):
        return self.structures.__contains__(item)

    def __iter__(self):
        return self.structures.__iter__()

    def __getitem__(self, index):
        return self.structures[index]
    
    def clear(self):
        self.structures.clear()
        
    def __eq__(self, other):
        if not isinstance(other, Library):
            return False
        if len(self.structures) != len(other.structures):
            return False
        for struct1, struct2 in zip(self.structures,other.structures):            
            if (struct1.name != struct2.name):  # check that all structure elements have identical names (this is not required by the __eq__ operator in Structure
                return False
            if (struct1 != struct2):
                return False
        return True

    def __ne__(self, other):
        return not self.__eq__(other)
Example #12
0
class OutputBasic(__OutputBasic__):
    layer_map = RestrictedProperty(default=TECH.GDSII.EXPORT_LAYER_MAP)
    echo = BoolProperty(default=False)

    def __init__(self, o_stream=sys.stdout, **kwargs):
        super(OutputBasic, self).__init__(o_stream=o_stream, **kwargs)
        self.library = None
        self.__current_structure__ = None
        self.__collect_method_dict__ = {}

    def __init_collector__(self):
        self.collector = ListCollector()

    def set_current_structure(self, S):
        self.__current_structure__ = S
        self.__structure_scale__ = S.unit / self.unit

    def define_filter(self):
        return TECH.GDSII.FILTER

    def do_collect(self, item, **kwargs):
        from ..primitives import library

        if isinstance(item, Library):
            self.library = item
            #for performance, to avoid repeated calls to DefinitionProperty in hot code
            self.grids_per_unit = self.library.grids_per_unit
            self.unit = self.library.unit

        if (self.library == None):
            self.library = get_current_library()

        super(OutputBasic, self).do_collect(item, **kwargs)

        return

    def collect_list(self, item, **kwargs):
        for i in item:
            self.collect(i, **kwargs)
        return

    def collect_Structure(self, item, **kwargs):
        if self.echo:
            LOG.info("Defining Structure %s with %d elements." %
                     (item.name, len(item.elements)))
        self.set_current_structure(item)

        self.__collect_structure_header__(item)
        self.collect(item.elements, **kwargs)
        self.__collect_structure_footer__(item)
        return

    def collect_Library(self, library, usecache=False, **kwargs):
        self.__collect_library_header__(library)
        unreferenced_structures = self.library.unreferenced_structures(
            usecache=usecache)
        referenced_structures = self.library.referenced_structures(
            usecache=usecache)
        self.collect(unreferenced_structures, **kwargs)
        self.collect(referenced_structures, **kwargs)
        self.__collect_library_footer__()
        return

    def __collect_library_header__(self, library):
        pass

    def __collect_library_footer__(self):
        pass

    def collect_ElementList(self, item, additional_transform=None, **kwargs):
        for s in item:
            self.collect(s,
                         additional_transform=additional_transform,
                         **kwargs)
        return

    def collect_StructureList(self, item, **kwargs):
        for s in item:
            self.collect(s, **kwargs)
        return

    def collect_Group(self, item, additional_transform=None, **kwargs):
        self.collect(item.elements,
                     additional_transform=item.transformation +
                     additional_transform,
                     **kwargs)
        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 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 __scale_value__(self, value):
        return value * self.__structure_scale__

    def map_layer(self, layer):
        L = self.layer_map.get(layer, None)
        if isinstance(L, GdsiiLayer):
            return L
        elif L is None:
            return L
        else:
            return GdsiiLayer(number=L)