def instantiate(self, values):
        """ Return a core.layout.Primitive with a set of fixed shapes
        given a dict mapping variable numbers to values, or None if there
        is no corresponding shape. """

        shape_type = self.shape_type

        mods = [m.evaluate(values) for m in self.modifiers]

        if shape_type == 'ignore':
            return None

        is_additive = True if shape_type in ('moire', 'thermal') \
            else bool(mods[0])

        rotation = 0 if shape_type in ('circle', 'moire', 'thermal') \
            else mods[-1]/180

        if shape_type == 'circle':
            shape = Circle(x=mods[2], y=mods[3], radius=mods[1] / 2)
        elif shape_type == 'line-vector':
            shape, rotation = self._vector_to_rect(mods, rotation)
        elif shape_type == 'line-center':
            shape = Rectangle(x=mods[3] - mods[1] / 2,
                              y=mods[4] + mods[2] / 2,
                              width=mods[1],
                              height=mods[2])
        elif shape_type == 'line-lower-left':
            shape = Rectangle(x=mods[3],
                              y=mods[4] + mods[2],
                              width=mods[1],
                              height=mods[2])
        elif shape_type == 'outline':
            points = [
                Point(mods[i], mods[i + 1])
                for i in range(2, len(mods[:-1]), 2)
            ]
            shape = Polygon(points)
        elif shape_type == 'polygon':
            shape = RegularPolygon(x=mods[2],
                                   y=mods[3],
                                   outer=mods[4],
                                   vertices=mods[1])
        elif shape_type == 'moire':
            mods[8] = 2 - mods[8] / 180
            shape = Moire(*mods[0:9])
        elif shape_type == 'thermal':
            mods[5] = 2 - mods[5] / 180
            shape = Thermal(*mods[0:6])

        return Primitive(is_additive, rotation, shape)
    def _extract_ad(self, tok):
        """ Extract aperture definition into shapes dict. """
        tok = tok if ',' in tok else tok + ','
        code_end = 4 if tok[3].isdigit() else 3
        code = tok[1:code_end]
        ap_type, mods = tok[code_end:].split(',')
        if mods:
            mods = [float(m) for m in mods.split('X') if m]

        # An aperture can use any of the 4 standard types,
        # (with or without a central hole), or a previously
        # defined macro.
        if ap_type == 'C':
            shape = Circle(0, 0, mods[0] / 2)
            hole_defs = len(mods) > 1 and mods[1:]
        elif ap_type == 'R':
            if len(mods) == 1:
                shape = Rectangle(-mods[0] / 2, mods[0] / 2, mods[0], mods[0])
            else:
                shape = Rectangle(-mods[0] / 2, mods[1] / 2, mods[0], mods[1])
            hole_defs = len(mods) > 2 and mods[2:]
        elif ap_type == 'O':
            shape = Obround(0, 0, mods[0], mods[1])
            hole_defs = len(mods) > 2 and mods[2:]
        elif ap_type == 'P':
            if len(mods) < 3:
                mods.append(0)
            shape = RegularPolygon(0, 0, mods[0], mods[1], mods[2])
            hole_defs = len(mods) > 3 and mods[3:]
        else:  # macro
            shape = ap_type
            if shape in self.macro_buff:
                macro = self.macro_buff[shape].instantiate(mods)
                counter = 0  # pick a unique name for the macro
                while mods and macro.name in self.layer_buff.macros:
                    macro.name = shape + str(counter)
                    counter += 1
                self.layer_buff.macros[macro.name] = macro
            hole_defs = None

        if hole_defs and (len(hole_defs) > 1):
            hole = Rectangle(-hole_defs[0] / 2, hole_defs[1] / 2, hole_defs[0],
                             hole_defs[1])
        elif hole_defs:
            hole = Circle(0, 0, hole_defs[0] / 2)
        else:
            hole = None

        self.layer_buff.apertures.update({code: Aperture(code, shape, hole)})
    def parse_rect(self, rect):
        """ Parse a rect element """

        x, y = (get_x(rect, mult=self.svg_mult),
                get_y(rect, mult=self.svg_mult))
        width, height = (get_length(rect, 'width', self.svg_mult),get_length(rect, 'height', self.svg_mult))         
        return [Rectangle(x, y, width, height)]
 def test_create_rect_from_corners(self):
     '''Test for Rectangle.from_corners()'''
     rect = Rectangle.from_corners(0, 1, 2, 4)
     self.assertEqual(rect.x, 0)
     self.assertEqual(rect.y, 1)
     self.assertEqual(rect.width, 2)
     self.assertEqual(rect.height, 3)
 def test_create_new_rectangle(self):
     """ Test the creation of a new empty rectangle. """
     rect = Rectangle(0, 1, 2, 3)
     assert rect.x == 0
     assert rect.y == 1
     assert rect.width == 2
     assert rect.height == 3
    def _convert_shapes(self, shapes, center=(0, 0), absolute=False):
        """ Convert shapes """
        result = []

        def fix_point(point):
            x, y = (point[0] + center[0], point[1] + center[1])
            if absolute:
                # freerouter often creates points outside boundary, fix it
                if x > self.max_x:
                    x = self.min_x + x - self.max_x
                elif x < self.min_x:
                    x = self.max_x - x - self.min_x
                if y > self.max_y:
                    y = self.min_y + y - self.max_y
                elif y < self.min_y:
                    y = self.max_y - y - self.min_y

            return (x, y)

        for shape in shapes:
            if isinstance(shape, specctraobj.PolylinePath):
                points = [
                    fix_point(self.to_pixels(point)) for point in shape.vertex
                ]
                result.extend(
                    self._convert_path(self.to_pixels(shape.aperture_width),
                                       points))

            elif isinstance(shape, specctraobj.Path):
                points = [
                    fix_point(self.to_pixels(point)) for point in shape.vertex
                ]
                # Path has connected start and end points
                if points[0] != points[-1] and len(points) != 2:
                    points.append(points[0])
                result.extend(
                    self._convert_path(self.to_pixels(shape.aperture_width),
                                       points))

            elif isinstance(shape, specctraobj.Polygon):
                points = [
                    fix_point(self.to_pixels(point)) for point in shape.vertex
                ]
                points = [Point(point[0], point[1]) for point in points]
                result.append(Polygon(points))

            elif isinstance(shape, specctraobj.Rectangle):
                x1, y1 = self.to_pixels(shape.vertex1)
                x2, y2 = self.to_pixels(shape.vertex2)
                width, height = abs(x1 - x2), abs(y1 - y2)
                x1, y1 = fix_point((min(x1, x2), max(y1, y2)))

                result.append(Rectangle(x1, y1, width, height))
            elif isinstance(shape, specctraobj.Circle):
                point = fix_point(self.to_pixels(shape.vertex))
                result.append(
                    Circle(point[0], point[1],
                           self.to_pixels(shape.diameter / 2.0)))
        return result
    def test_rectangle(self):
        """
        Rectangles are output correctly.
        """

        writer = KiCAD()
        rect = Rectangle(10, 20, 5, 10)
        line = writer.get_shape_line(rect)
        self.assertEqual(line, 'S 111 222 167 111 %(unit)d %(convert)d 0 N\n')
Example #8
0
    def test_rectangle(self):
        """ Convert rectangle shape """

        rect = Rectangle(10, 20, 5, 10)
        writer = Specctra()
        obj = writer._convert_shape(rect)
        self.assertEqual(
            to_string(writer, obj),
            '( (rect signal 104.166667 208.333333 156.250000 104.166667) )')
    def _vector_to_rect(self, mods, rotation):
        """
        Convert a vector into a Rectangle.

        Strategy
        ========
        If vect is not horizontal:
            - rotate about the origin until horizontal
            - define it as a normal rectangle
            - incorporate rotated angle into explicit rotation

        """
        start, end = (mods[2:4], mods[4:6])
        start_radius = sqrt(start[0]**2 + start[1]**2)
        end_radius = sqrt(end[0]**2 + end[1]**2)

        # Reverse the vector if its endpoint is closer
        # to the origin than its start point (avoids
        # mucking about with signage later).
        if start_radius > end_radius:
            end, start = (mods[2:4], mods[4:6])
            radius = end_radius
        else:
            radius = start_radius

        # Calc the angle of the vector with respect to the x axis.
        x, y = start
        adj = end[0] - x
        opp = end[1] - y
        hyp = sqrt(adj**2 + opp**2)
        theta = acos(adj / hyp) / pi
        if opp > 0:
            theta = 2 - theta

        # Represent vector angle as a delta.
        d_theta = 2 - theta

        # Calc the angle of the start point of the flattened vector.

        theta = 0.0 if radius == 0.0 else acos(x / radius) / pi
        if y > 0:
            theta = 2 - theta
        theta += d_theta

        # Redefine x and y at center of the rect's left side.

        y = sin((2 - theta) * pi) * radius
        x = cos((2 - theta) * pi) * radius

        # Calc the composite rotation angle.
        rotation = (rotation + theta) % 2

        return (Rectangle(x=x, y=y + mods[1] / 2, width=hyp,
                          height=mods[1]), rotation)
Example #10
0
    def test_rectangle(self):
        """ Convert rectangle shape """

        rect = Rectangle(10, 20, 5, 10)
        writer = Specctra()
        writer.resolution = specctraobj.Resolution()
        writer.resolution.unit = 'mil'
        writer.resolution.resolution = 10
        obj = writer._convert_shape(rect)
        self.assertEqual(
            to_string(writer, obj),
            '( (rect signal 104.166667 208.333333 156.250000 104.166667) )')
Example #11
0
    def test_rectangle(self):
        """
        Rectangles are output correctly.
        """

        writer = KiCAD()
        rect = Rectangle(10, 20, 5, 10)
        line = writer.get_shape_line(rect)
        self.assertEqual(line, 'S ' + str(int(10 / MULT)) + ' '
            + str(int(20 / MULT)) + ' '
            + str(int(15 / MULT)) + ' '
            + str(int(10 / MULT)) + ' '
            + '%(unit)d %(convert)d 0 N\n')
Example #12
0
    def make_body_from_symbol(self, lib, symbol_name):
        """ Construct an openjson Body from an eagle symbol in a library. """

        body = Body()

        symbol = [
            s for s in get_subattr(lib, 'symbols.symbol')
            if s.name == symbol_name
        ][0]

        for wire in symbol.wire:
            body.add_shape(
                Line((self.make_length(wire.x1), self.make_length(wire.y1)),
                     (self.make_length(wire.x2), self.make_length(wire.y2))))

        for rect in symbol.rectangle:
            x = self.make_length(rect.x1)
            y = self.make_length(rect.y1)
            width = self.make_length(rect.x2) - x
            height = self.make_length(rect.y2) - y
            body.add_shape(Rectangle(x, y + height, width, height))

        pin_map = {}

        for pin in symbol.pin:
            connect_point = (self.make_length(pin.x), self.make_length(pin.y))
            null_point = self.get_pin_null_point(connect_point, pin.length,
                                                 pin.rot)
            label = self.get_pin_label(pin, null_point)
            pin_map[pin.name] = Pin(pin.name, null_point, connect_point, label)
            body.add_pin(pin_map[pin.name])

        ann_map = {}

        for text in symbol.text:
            x = self.make_length(text.x)
            y = self.make_length(text.y)
            content = '' if text.valueOf_ is None else text.valueOf_
            rotation = self.make_angle('0' if text.rot is None else text.rot)
            if content == '>NAME':
                ann_map['name'] = Annotation(content, x, y, rotation, 'true')
            elif content == '>VALUE':
                ann_map['value'] = Annotation(content, x, y, rotation, 'true')
            else:
                body.add_shape(Label(x, y, content, 'left', rotation))

        return body, pin_map, ann_map
    def test_get_pin(self):
        """ The get_pin function returns the correct Pins """

        shape = Rectangle(0, 0, 4, 8)
        pin = get_pin(shape)
        self.assertEqual(pin.p1.x, 2)
        self.assertEqual(pin.p1.y, 4)
        self.assertEqual(pin.p2.x, pin.p1.x)
        self.assertEqual(pin.p2.y, pin.p1.y)

        shape = Circle(0, 0, 4)
        pin = get_pin(shape)
        self.assertEqual(pin.p1.x, 0)
        self.assertEqual(pin.p1.y, 0)
        self.assertEqual(pin.p2.x, pin.p1.x)
        self.assertEqual(pin.p2.y, pin.p1.y)

        self.assertEqual(get_pin(Shape()), None)
    def bodies(self, offset, instance_attributes):
        bodies = []

        attached_layers = self.get_attr('attached_layers', '',
                                        instance_attributes).split(',')
        width = self.get_int_attr('width', 0, instance_attributes)
        height = self.get_int_attr('height', 0, instance_attributes)
        radius = self.get_int_attr('radius', 0, instance_attributes)
        shape_type = self.get_attr('shape', '', instance_attributes)

        pos = Point(self.x, self.y)

        for layer_name in attached_layers:
            layer_name = layer_name
            pad = FBody()
            # invert top/bottom if the footprint is on the bottom of the board
            if offset.side == 'bottom':
                rev_sides = {'top': 'bottom', 'bottom': 'top'}
                layer_name = ' '.join([
                    rev_sides.get(piece, piece)
                    for piece in layer_name.split(' ')
                ])

            if shape_type == 'rectangle':
                pad.add_shape(
                    Rectangle((width / 2), -(height / 2), width, height))
            elif shape_type == 'rounded rectangle':
                pad.add_shape(
                    RoundedRectangle((width / 2), -(height / 2), width, height,
                                     radius))
            elif shape_type == 'circle':
                pad.add_shape(Circle(0, 0, radius))
            else:
                raise ValueError('unexpected shape type for padstack')

            pad.rotate(self.rotation)
            pad.shift(pos.x, pos.y)
            bodies.append((FootprintAttribute(0, 0, 0, False,
                                              layer_name), pad))

        return bodies
Example #15
0
 def parse_s_line(self, parts):
     """ Parse an S (Rectangle) line """
     x, y, x2, y2 = [int(i) for i in parts[1:5]]
     return Rectangle(x, y, x2 - x, y - y2)
    def parse_shape(self, shape):
        """ Extract a shape. """
        # pylint: disable=R0914
        # pylint: disable=R0911

        rotation = shape.get('rotation', 0.0)
        flip_horizontal = shape.get('flip_horizontal', False)

        shape_type = shape.get('type')
        if 'rectangle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            parsed_shape = Rectangle(x, y, width, height)
        elif 'rounded_rectangle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            radius = int(shape.get('radius'))
            parsed_shape = RoundedRectangle(x, y, width, height, radius)
        elif 'arc' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            start_angle = float(shape.get('start_angle'))
            end_angle = float(shape.get('end_angle'))
            radius = int(shape.get('radius'))
            parsed_shape = Arc(x, y, start_angle, end_angle, radius)
        elif 'circle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            radius = int(shape.get('radius'))
            parsed_shape = Circle(x, y, radius)
        elif 'label' == shape_type:
            parsed_shape = self.parse_label(shape)
        elif 'line' == shape_type:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = Line(p1, p2)
        elif 'polygon' == shape_type:
            parsed_shape = Polygon()
            for point in shape.get('points'):
                parsed_shape.add_point(self.parse_point(point))
        elif 'bezier' == shape_type:
            control1 = self.parse_point(shape.get('control1'))
            control2 = self.parse_point(shape.get('control2'))
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = BezierCurve(control1, control2, p1, p2)
        elif 'rounded_segment' == shape_type:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            width = int(shape.get('width'))
            parsed_shape = RoundedSegment(p1, p2, width)

        parsed_shape.rotation = rotation
        parsed_shape.flip_horizontal = flip_horizontal

        parsed_shape.styles = shape.get('styles') or {}
        parsed_shape.attributes = shape.get('attributes') or {}
        return parsed_shape
 def parse_s_line(self, parts):
     """ Parse an S (Rectangle) line """
     x, y, x2, y2 = [int(i) for i in parts[1:5]]
     return Rectangle(make_length(x), make_length(y), make_length(x2 - x),
                      make_length(y - y2))
 def parse_box(self, args):
     """ Returns a parsed box. """
     x1, y1, x2, y2 = [int(a) for a in args.split()]
     return ('shape', Rectangle.from_corners(x1, y1, x2, y2))
 def test_rectangle_min_point(self):
     '''Test Rectangle.min_point()'''
     rect = Rectangle(-2, -3, 8, 5)
     top_left = rect.min_point()
     self.assertEqual(top_left.x, -2)
     self.assertEqual(top_left.y, -3)
 def test_rectangle_max_point(self):
     '''Test Rectangle.max_point()'''
     rect = Rectangle(-2, -3, 8, 5)
     bottom_right = rect.max_point()
     self.assertEqual(bottom_right.x, 6)
     self.assertEqual(bottom_right.y, 2)
    def make_body_from_symbol(self, lib, symbol_name, pin_number_lookup):
        """ Construct an openjson SBody from an eagle symbol in a library. """

        body = SBody()

        symbol = [
            s for s in get_subattr(lib, 'symbols.symbol')
            if s.name == symbol_name
        ][0]

        for wire in symbol.wire:
            body.add_shape(self.make_shape_for_wire(wire))

        for rect in symbol.rectangle:
            rotation = make_angle('0' if rect.rot is None else rect.rot)
            x1, y1 = rotate_point(
                (self.make_length(rect.x1), self.make_length(rect.y1)),
                rotation)
            x2, y2 = rotate_point(
                (self.make_length(rect.x2), self.make_length(rect.y2)),
                rotation)
            ux, uy = min(x1, x2), max(y1, y2)
            lx, ly = max(x1, x2), min(y1, y2)
            body.add_shape(Rectangle(ux, uy, lx - ux, uy - ly))

        for poly in symbol.polygon:
            map(body.add_shape, self.make_shapes_for_poly(poly))

        for circ in symbol.circle:
            body.add_shape(self.make_shape_for_circle(circ))

        pin_map = {}

        for pin in symbol.pin:
            connect_point = (self.make_length(pin.x), self.make_length(pin.y))
            null_point = self.get_pin_null_point(connect_point, pin.length,
                                                 pin.rot)
            label = self.get_pin_label(pin, null_point)
            pin_map[pin.name] = Pin(pin_number_lookup(pin.name), null_point,
                                    connect_point, label)
            if pin.direction:
                pin_map[pin.name].add_attribute('eaglexml_direction',
                                                pin.direction)
            if pin.visible:
                pin_map[pin.name].add_attribute('eaglexml_visible',
                                                pin.visible)
            body.add_pin(pin_map[pin.name])

        ann_map = {}

        for text in symbol.text:
            x = self.make_length(text.x)
            y = self.make_length(text.y)
            content = '' if text.valueOf_ is None else text.valueOf_
            rotation = make_angle('0' if text.rot is None else text.rot)
            align = 'right' if is_mirrored(text.rot) else 'left'
            if rotation == 0.5:
                rotation = 1.5
            if content.lower() == '>name':
                ann_map['name'] = Annotation(content, x, y, rotation, 'true')
            elif content.lower() == '>value':
                ann_map['value'] = Annotation(content, x, y, rotation, 'true')
            else:
                body.add_shape(
                    Label(x, y, content, align=align, rotation=rotation))

        return body, pin_map, ann_map
Example #22
0
    def add_shape(self, shape, parent, parent_offset, offset):
        """ Add a shape to the image. (might be added as a smear or fill) """
        # Copy the shape so it can be mutated without affecting other instances
        shapecpy = copy.deepcopy(shape)

        # XXX(shamer): a label needs to be rendered before in-place rotations are made so the bounding box for the shape
        # are known
        if isinstance(shapecpy, Label):
            self.face.set_char_size(int(shapecpy.font_size))

            label_contours = []

            x_offset = 0
            y_offset = 0
            label_text = self.resolve_text(shapecpy.text, parent.get_attribute)
            for i, c in enumerate(label_text):
                self.face.load_char(c,
                                    flags=freetype.ft_enums.FT_LOAD_NO_BITMAP)
                slot = self.face.glyph
                outline = slot.outline

                glyph_contours = []

                start, end = 0, 0
                # Iterate over each contour separately. Characters like 'g' have multiple contours as they cannot be
                # walked with a contiguous set of arcs. The contours list contains the index of the point that the
                # contour starts on.
                for contour_idx in range(len(outline.contours)):
                    end = outline.contours[contour_idx]
                    points = [
                        Point(t[0], t[1])
                        for t in outline.points[start:end + 1]
                    ]
                    tags = outline.tags[start:end + 1]
                    # Close the contour by repeating the last point.
                    points.append(copy.deepcopy(points[0]))
                    tags.append(copy.deepcopy(tags[0]))

                    segments = [
                        [
                            points[0],
                        ],
                    ]
                    # Group points into segments. The tag identifies real vs control points.
                    for point_idx in range(1, len(points)):
                        segments[-1].append(points[point_idx])
                        if tags[point_idx] & (1 << 0) and point_idx < (
                                len(points) - 1):
                            segments.append([
                                copy.deepcopy(points[point_idx]),
                            ])

                    # take the fist and last points of each segment (the non-control points). To approximate the curves
                    # using straight lines.
                    glyph_contours.append([[segment[0], segment[-1]]
                                           for segment in segments])

                    start = end + 1

                # update the segments in the glyph with the x_offset
                for contour_segments in glyph_contours:
                    for segments in contour_segments:
                        for point in segments:
                            point.x += x_offset
                            point.y += y_offset
                label_contours.extend(glyph_contours)

                x_offset += slot.advance.x
                # adjust amount to advance with kerning offset
                if i + 1 < len(label_text):
                    next_c = label_text[i + 1]
                    x_offset += self.face.get_kerning(c, next_c).x

            # Update the segments for pre-render shifts, rotates, alignment
            for contour_segments in label_contours:
                for segments in contour_segments:
                    if shapecpy.align == 'center':
                        segments[0].shift(-(x_offset / 2), 0)
                        segments[1].shift(-(x_offset / 2), 0)

                    if shapecpy.rotation:
                        segments[0].rotate(shapecpy.rotation)
                        segments[1].rotate(shapecpy.rotation)

                    if shapecpy.flip_horizontal:
                        segments[0].flip(shapecpy.flip_horizontal)
                        segments[1].flip(shapecpy.flip_horizontal)

                    shapecpy._segments.append(segments)

            # Calculate the bounding fox the label from the segments
            min_point = [2**100, 2**100]
            max_point = [-2**100, -2**100]
            for contour_segments in label_contours:
                for segments in contour_segments:
                    min_point[0] = min(segments[0].x, segments[1].x,
                                       min_point[0])
                    max_point[0] = max(segments[0].x, segments[1].x,
                                       max_point[0])
                    min_point[1] = min(segments[0].y, segments[1].y,
                                       min_point[1])
                    max_point[1] = max(segments[0].y, segments[1].y,
                                       max_point[1])
            shapecpy._min_point = Point(min_point[0], min_point[1])
            shapecpy._max_point = Point(max_point[0], max_point[1])

        shapecpy.shift(offset.x, offset.y)
        if parent_offset.rotation != 0:
            shapecpy.rotate(parent_offset.rotation)
        if parent_offset.flip_horizontal:
            shapecpy.flip(parent_offset.flip_horizontal)
        shapecpy.shift(parent_offset.x, parent_offset.y)

        if offset.rotation != 0:
            if parent_offset.flip_horizontal:
                shapecpy.rotate(-offset.rotation, in_place=True)
            else:
                shapecpy.rotate(offset.rotation, in_place=True)
        if offset.flip_horizontal:
            shapecpy.flip(offset.flip_horizontal)

        if isinstance(shapecpy, Line):
            # FIXME(shamer): line  doesn't have an explicit width. Gets used for outlines. Defaulted to 0.15mm
            self.smears.append(Smear(shapecpy, Circle(0, 0, 0.15 * 1000000)))

        elif isinstance(shapecpy, Circle):
            self.shape_instances.append(
                ShapeInstance(Point(shapecpy.x, shapecpy.y),
                              Aperture(None, shapecpy, None)))

        elif isinstance(shapecpy, Rectangle):
            #shapecpy.x += shapecpy.width
            #shapecpy.y -= shapecpy.height / 2
            shapecpy.width = abs(shapecpy.width)
            shapecpy.height = abs(shapecpy.height)
            if shapecpy.rotation != 0:
                instance_name = 'Rect-W{width}-H{height}-RO{rotation}'.format(
                    height=shapecpy.height,
                    width=shapecpy.width,
                    rotation=shapecpy.rotation)
                # XXX(shamer): additional copy is made so the x, y can be reset for use as a ComplexInstance
                shapecpycpy = copy.deepcopy(shapecpy)
                shapecpycpy.x = 0
                shapecpycpy.y = 0
                shapecpycpy.is_centered = True
                primitives = [Primitive(1, 0.0, shapecpycpy)]
                self.complex_instances.append(
                    ComplexInstance(instance_name,
                                    Point(shapecpy.x, shapecpy.y), primitives))
            else:
                self.shape_instances.append(
                    ShapeInstance(Point(shapecpy.x, shapecpy.y),
                                  Aperture(None, shapecpy, None)))

        elif isinstance(shapecpy, RoundedRectangle):
            # Rounded rectangle is added as a macro with two rectangles to fill out the body and four circles to make up
            # the corners. `roundrect` is assumed to already be centered.
            primitives = []
            radius = abs(shapecpy.radius)
            inner_height = abs(shapecpy.height) - (radius * 2)
            inner_width = abs(shapecpy.width) - (radius * 2)
            half_width = inner_width / 2.0
            half_height = inner_height / 2.0

            high_rect = Rectangle(0,
                                  0,
                                  abs(inner_width),
                                  abs(shapecpy.height),
                                  is_centered=True)
            wide_rect = Rectangle(0,
                                  0,
                                  abs(shapecpy.width),
                                  abs(inner_height),
                                  is_centered=True)
            primitives.append(Primitive(1, 0.0, high_rect))
            primitives.append(Primitive(1, 0.0, wide_rect))
            primitives.append(
                Primitive(1, 0.0,
                          Circle(-half_width, half_height, shapecpy.radius)))
            primitives.append(
                Primitive(1, 0.0,
                          Circle(half_width, half_height, shapecpy.radius)))
            primitives.append(
                Primitive(1, 0.0,
                          Circle(half_width, -half_height, shapecpy.radius)))
            primitives.append(
                Primitive(1, 0.0,
                          Circle(-half_width, -half_height, shapecpy.radius)))

            # rotate the positioning of the rounded corners (the circles)
            for primitive in primitives:
                primitive.shape.rotate(shapecpy.rotation)

            instance_name = 'RR-H{height}-W{width}-R{radius}-RO{rotation}'.format(
                height=abs(shapecpy.height),
                width=abs(shapecpy.width),
                radius=radius,
                rotation=shapecpy.rotation)
            self.complex_instances.append(
                ComplexInstance(instance_name, Point(shapecpy.x, shapecpy.y),
                                primitives))

        elif isinstance(shapecpy, Label):
            # TODO(shamer): cache positions segments for glyphs
            # FIXME((shamer): make baseline shift

            # TODO(shamer) select the correct font based off of the label.font_family

            # Debugging, used to show the anchor point of the label
            #self.shape_instances.append(ShapeInstance(Point(shapecpy.x, shapecpy.y), Aperture(None, Circle(0, 0, 1000000 / 5), None)))

            for segments in shapecpy._segments:
                line = Line(segments[0], segments[1])
                line.shift(shapecpy.x, shapecpy.y)
                self.smears.append(Smear(line,
                                         Circle(0, 0,
                                                0.1016 * 1000000)))  # 4 Mils
Example #23
0
    def parse_shape(self, shape):
        """ Extract a shape. """
        # pylint: disable=R0914
        # pylint: disable=R0911

        rotation = shape.get('rotation', 0.0)
        flip_horizontal = shape.get('flip_horizontal', False)

        shape_type = shape.get('type')
        if 'rectangle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            parsed_shape = Rectangle(x, y, width, height)
        elif 'rounded_rectangle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            radius = int(shape.get('radius'))
            parsed_shape = RoundedRectangle(x, y, width, height, radius)
        elif 'arc' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            start_angle = float(shape.get('start_angle'))
            end_angle = float(shape.get('end_angle'))
            radius = int(shape.get('radius'))
            parsed_shape = Arc(x, y, start_angle, end_angle, radius)
        elif 'circle' == shape_type:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            radius = int(shape.get('radius'))
            parsed_shape = Circle(x, y, radius)
        elif 'label' == shape_type:
            parsed_shape = self.parse_label(shape)
        elif 'line' == shape_type:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = Line(p1, p2)
        elif 'polygon' == shape_type:
            parsed_shape = Polygon()
            for point in shape.get('points'):
                parsed_shape.add_point(self.parse_point(point))
        elif 'bezier' == shape_type:
            control1 = self.parse_point(shape.get('control1'))
            control2 = self.parse_point(shape.get('control2'))
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = BezierCurve(control1, control2, p1, p2)
        elif 'rounded_segment' == shape_type:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            width = int(shape.get('width'))
            parsed_shape = RoundedSegment(p1, p2, width)

        parsed_shape.rotation = rotation
        parsed_shape.flip_horizontal = flip_horizontal

        parsed_shape.styles = shape.get('styles') or {}
        parsed_shape.attributes = shape.get('attributes') or {}
        return parsed_shape
Example #24
0
 def parse_box(self, args):
     """ Returns a parsed box. """
     x1, y1, x2, y2 = [int(a) for a in args.split()]
     return ('shape', Rectangle.from_corners(x1, y1, x2, y2))
Example #25
0
    def parse_shape(self, shape):
        """ Extract a shape. """
        # pylint: disable=R0914
        # pylint: disable=R0911

        typ = shape.get('type')
        if 'rectangle' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            parsed_shape = Rectangle(x, y, width, height)
        elif 'rounded_rectangle' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            height = int(shape.get('height'))
            width = int(shape.get('width'))
            radius = int(shape.get('radius'))
            parsed_shape = RoundedRectangle(x, y, width, height, radius)
        elif 'arc' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            start_angle = float(shape.get('start_angle'))
            end_angle = float(shape.get('end_angle'))
            radius = int(shape.get('radius'))
            parsed_shape = Arc(x, y, start_angle, end_angle, radius)
        elif 'circle' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            radius = int(shape.get('radius'))
            parsed_shape = Circle(x, y, radius)
        elif 'label' == typ:
            x = int(shape.get('x'))
            y = int(shape.get('y'))
            rotation = float(shape.get('rotation'))
            text = shape.get('text')
            align = shape.get('align')
            parsed_shape = Label(x, y, text, align, rotation)
        elif 'line' == typ:
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = Line(p1, p2)
        elif 'polygon' == typ:
            parsed_shape = Polygon()
            for point in shape.get('points'):
                parsed_shape.add_point(self.parse_point(point))
        elif 'bezier' == typ:
            control1 = self.parse_point(shape.get('control1'))
            control2 = self.parse_point(shape.get('control2'))
            p1 = self.parse_point(shape.get('p1'))
            p2 = self.parse_point(shape.get('p2'))
            parsed_shape = BezierCurve(control1, control2, p1, p2)

        parsed_shape.styles = shape.get('styles') or {}
        parsed_shape.attributes = shape.get('attributes') or {}
        return parsed_shape
    def parse_shape(self, shape):
        """ Extract a shape. """
        # pylint: disable=R0914
        # pylint: disable=R0911

        rotation = shape.get("rotation", 0.0)
        flip_horizontal = shape.get("flip_horizontal", False)

        shape_type = shape.get("type")
        if "rectangle" == shape_type:
            x = int(shape.get("x"))
            y = int(shape.get("y"))
            height = int(shape.get("height"))
            width = int(shape.get("width"))
            parsed_shape = Rectangle(x, y, width, height)
        elif "rounded_rectangle" == shape_type:
            x = int(shape.get("x"))
            y = int(shape.get("y"))
            height = int(shape.get("height"))
            width = int(shape.get("width"))
            radius = int(shape.get("radius"))
            parsed_shape = RoundedRectangle(x, y, width, height, radius)
        elif "arc" == shape_type:
            x = int(shape.get("x"))
            y = int(shape.get("y"))
            start_angle = float(shape.get("start_angle"))
            end_angle = float(shape.get("end_angle"))
            radius = int(shape.get("radius"))
            parsed_shape = Arc(x, y, start_angle, end_angle, radius)
        elif "circle" == shape_type:
            x = int(shape.get("x"))
            y = int(shape.get("y"))
            radius = int(shape.get("radius"))
            parsed_shape = Circle(x, y, radius)
        elif "label" == shape_type:
            parsed_shape = self.parse_label(shape)
        elif "line" == shape_type:
            p1 = self.parse_point(shape.get("p1"))
            p2 = self.parse_point(shape.get("p2"))
            parsed_shape = Line(p1, p2)
        elif "polygon" == shape_type:
            parsed_shape = Polygon()
            for point in shape.get("points"):
                parsed_shape.add_point(self.parse_point(point))
        elif "bezier" == shape_type:
            control1 = self.parse_point(shape.get("control1"))
            control2 = self.parse_point(shape.get("control2"))
            p1 = self.parse_point(shape.get("p1"))
            p2 = self.parse_point(shape.get("p2"))
            parsed_shape = BezierCurve(control1, control2, p1, p2)
        elif "rounded_segment" == shape_type:
            p1 = self.parse_point(shape.get("p1"))
            p2 = self.parse_point(shape.get("p2"))
            width = int(shape.get("width"))
            parsed_shape = RoundedSegment(p1, p2, width)

        parsed_shape.rotation = rotation
        parsed_shape.flip_horizontal = flip_horizontal

        parsed_shape.styles = shape.get("styles") or {}
        parsed_shape.attributes = shape.get("attributes") or {}
        return parsed_shape
    def bodies(self, offset, instance_attributes):
        """ Generated the bodies for the Via with instance attribute overrides. Returns placment attribute and body
            pairs.

        """
        attached_layers = self.get_attr('attached_layers', '',
                                        instance_attributes).split(',')
        internal_diameter = self.get_float_attr('internal_diameter', 0,
                                                instance_attributes)
        plating_shape = self.get_attr('plating_shape', '', instance_attributes)

        # Local vars for use in closures to generate shapes
        # XXX(shamer): The assignment of width and lenght are reversed from the javascript. Not sure why this is.
        plating_width = self.get_float_attr('plating_length', 0,
                                            instance_attributes)
        plating_height = self.get_float_attr('plating_width', 0,
                                             instance_attributes)
        plating_radius = self.get_float_attr('plating_radius', 0,
                                             instance_attributes)
        plating_diameter = self.get_float_attr('plating_diameter', 0,
                                               instance_attributes)

        solder_mask_expansion = self.get_float_attr('solder_mask_expansion', 0,
                                                    instance_attributes)
        #thermal_inner_diameter = self.get_float_attr('thermal_inner_diameter', 0, instance_attributes)
        #thermal_spoke_width = self.get_float_attr('thermal_spoke_width', 0, instance_attributes)
        #antipad_diameter = self.get_float_attr('antipad_diameter', 0, instance_attributes)

        # placment attribute + body pairs making up the generated object
        bodies = []

        pad_pos = Point(self.x, self.y)
        sme_pos = Point(self.x, self.y)

        # Debugging marker for displaying the placment position for generated objects.
        #marker = FBody()
        #marker.add_shape(Circle(pad_pos.x, pad_pos.y, 1000000))
        #bodies.append((FootprintAttribute(0, 0, 0, False, 'top silkscreen'), marker))

        if plating_shape == 'square':
            solder_mask_width = (solder_mask_expansion * 2) + plating_diameter

            create_shape = lambda: Rectangle(
                pad_pos.x, pad_pos.y, plating_diameter, plating_diameter)
            create_solder_mask_expansion = lambda: Rectangle(
                sme_pos.x, sme_pos.y, solder_mask_width, solder_mask_width)

        elif plating_shape == 'circle':
            create_shape = lambda: Circle(pad_pos.x, pad_pos.y,
                                          plating_diameter / 2)

            solder_mask_radius = solder_mask_expansion + (plating_diameter / 2)
            create_solder_mask_expansion = lambda: Circle(
                sme_pos.x, sme_pos.y, solder_mask_radius)

        elif plating_shape == 'rectangle':
            solder_mask_width = (solder_mask_expansion * 2) + plating_width
            solder_mask_height = (solder_mask_expansion * 2) + plating_height

            create_shape = lambda: Rectangle(pad_pos.x, pad_pos.y,
                                             plating_width, plating_height)
            create_solder_mask_expansion = lambda: Rectangle(
                sme_pos.x, sme_pos.y, solder_mask_width, solder_mask_height)

        elif plating_shape == 'rounded rectangle':
            solder_mask_width = (solder_mask_expansion * 2) + plating_width
            solder_mask_height = (solder_mask_expansion * 2) + plating_height

            create_shape = lambda: RoundedRectangle(
                pad_pos.x, pad_pos.y, plating_width, plating_height,
                plating_radius)
            create_solder_mask_expansion = lambda: RoundedRectangle(
                sme_pos.x, sme_pos.y, solder_mask_width, solder_mask_height,
                plating_radius)

        else:
            raise ValueError(
                'unexpected shape for plated through hole "{0}"'.format(
                    plating_shape))

        # cirle of radius 'solder_mask_expansion' + ('plating_diameter' / 2) in the top and bottom silkscreen layers
        solder_mask_radius = solder_mask_expansion + (plating_diameter / 2)
        top_solder_mask = FBody()
        top_solder_mask.add_shape(create_solder_mask_expansion())
        bodies.append((FootprintAttribute(0, 0, 0, False,
                                          'top solder mask'), top_solder_mask))

        bottom_solder_mask = FBody()
        bottom_solder_mask.add_shape(create_solder_mask_expansion())
        bodies.append(
            (FootprintAttribute(0, 0, 0, False,
                                'bottom solder mask'), bottom_solder_mask))

        # circle of diameter 'internal_diameter' on the hole layer
        hole = FBody()
        hole.add_shape(Circle(pad_pos.x, pad_pos.y, internal_diameter / 2))
        bodies.append((FootprintAttribute(0, 0, 0, False, 'hole'), hole))

        # circles of diameter 'plating_diameter' on each connection layer
        for layer_name in attached_layers:
            connected_layer = FBody()
            if layer_name == 'top copper' or layer_name == 'bottom copper':
                connected_layer.add_shape(create_shape())
            else:
                connected_layer.add_shape(
                    Circle(pad_pos.x, pad_pos.y, plating_diameter / 2))
            bodies.append((FootprintAttribute(0, 0, 0, False,
                                              layer_name), connected_layer))

        return bodies