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')
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)
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) )')
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')
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
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
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
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