def pins(self, width: int, grid: float) -> List[Tuple[str, Position, Rotation]]: """ Return all pins spaced with the specified grid size. """ dx = (width + 2) * grid / 2 return [(l[0], Position(-dx, l[1] * grid), Rotation(0.0)) for l in self.left] + \ [(r[0], Position(dx, r[1] * grid), Rotation(180.0)) for r in self.right]
def create_footprint() -> Footprint: footprint = Footprint('17b9f232-2b15-4281-a07d-ad0db5213f92', Name('default'), Description('')) footprint.add_pad( FootprintPad('5c4d39d3-35cc-4836-a082-693143ee9135', Side.THT, Shape.RECT, Position(0.0, 22.86), Rotation(0.0), Size(2.54, 1.5875), Drill(1.0))) footprint.add_pad( FootprintPad('6100dd55-d3b3-4139-9085-d5a75e783c37', Side.THT, Shape.ROUND, Position(0.0, 20.32), Rotation(0.0), Size(2.54, 1.5875), Drill(1.0))) polygon = Polygon('5e18e4ea-5667-42b3-b60f-fcc91b0461d3', Layer('top_placement'), Width(0.25), Fill(False), GrabArea(True)) polygon.add_vertex(Vertex(Position(-1.27, +24.36), Angle(0.0))) polygon.add_vertex(Vertex(Position(+1.27, +24.36), Angle(0.0))) polygon.add_vertex(Vertex(Position(+1.27, -24.36), Angle(0.0))) polygon.add_vertex(Vertex(Position(-1.27, -24.36), Angle(0.0))) polygon.add_vertex(Vertex(Position(-1.27, +24.36), Angle(0.0))) footprint.add_polygon(polygon) stroke_text = StrokeText('f16d1604-8a82-4688-bc58-be1c1375873f', Layer('top_names'), Height(1.0), StrokeWidth(0.2), LetterSpacing.AUTO, LineSpacing.AUTO, Align('center bottom'), Position(0.0, 25.63), Rotation(0.0), AutoRotate(True), Mirror(False), Value('{{NAME}}')) footprint.add_text(stroke_text) return footprint
def test_symbol() -> None: symbol = Symbol('01b03c10-7334-4bd5-b2bc-942c18325d2b', Name('Sym name'), Description(r'A multiline description.\n\nDescription'), Keywords('my, keywords'), Author('Test'), Version('0.2'), Created('2018-10-17T19:13:41Z'), Category('d0618c29-0436-42da-a388-fdadf7b23892')) symbol.add_pin( SymbolPin('6da06b2b-7806-4e68-bd0c-e9f18eb2f9d8', Name('1'), Position(5.08, 20.32), Rotation(180.0), Length(3.81))) polygon = Polygon('743dbf3d-98e8-46f0-9a32-00e00d0e811f', Layer('sym_outlines'), Width(0.25), Fill(False), GrabArea(True)) polygon.add_vertex(Vertex(Position(-2.54, 22.86), Angle(0.0))) polygon.add_vertex(Vertex(Position(-2.54, -25.4), Angle(0.0))) polygon.add_vertex(Vertex(Position(-2.54, 22.86), Angle(0.0))) symbol.add_polygon(polygon) symbol.add_circle( Circle('b5599e68-ff6a-464b-9a40-c6ba8ef8daf5', Layer('sym_outlines'), Width(0.254), Fill(False), GrabArea(False), Diameter(1.27), Position(5.715, 0.0))) symbol.add_text( Text('b9c4aa19-0a46-400c-9c96-e8c3dfb8f83e', Layer('sym_names'), Value('{{NAME}}'), Align('center bottom'), Height(2.54), Position(0.0, 22.86), Rotation(0.0))) assert str( symbol) == """(librepcb_symbol 01b03c10-7334-4bd5-b2bc-942c18325d2b
def test_component() -> None: component = Component( '00c36da8-e22b-43a1-9a87-c3a67e863f49', Name('Generic Connector 1x27'), Description(r'A 1x27 soldered wire connector.\n\nNext line'), Keywords('connector, 1x27'), Author('Test R.'), Version('0.2'), Created('2018-10-17T19:13:41Z'), Deprecated(False), Category('d0618c29-0436-42da-a388-fdadf7b23892'), SchematicOnly(False), DefaultValue(''), Prefix('J')) component.add_signal( Signal('f46a4643-fc68-4593-a889-3d987bfe3544', Name('1'), Role.PASSIVE, Required(False), Negated(False), Clock(False), ForcedNet(''))) gate = Gate('c1e4b542-a1b1-44d5-bec3-070776143a29', SymbolUUID('8f1a97f2-4cdf-43da-b38d-b3787c47b5ad'), Position(0.0, 0.0), Rotation(0.0), Required(True), Suffix('')) gate.add_pin_signal_map( PinSignalMap('0189aafc-f88a-4e65-8fb4-09a047a3e334', SignalUUID('46f7e0e2-74a6-442b-9a5c-1bd4ea3da59c'), TextDesignator.SYMBOL_PIN_NAME)) variant = Variant('abeeeed0-6e9a-4fdc-bc2b-e2c5b06bbe3a', Norm.EMPTY, Name('default'), Description(''), gate) component.add_variant(variant) assert str(component ) == """(librepcb_component 00c36da8-e22b-43a1-9a87-c3a67e863f49
def test_footprint_pad() -> None: footprint_pad = FootprintPad('5c4d39d3-35cc-4836-a082-693143ee9135', Side.THT, Shape.RECT, Position(0.0, 22.86), Rotation(0.0), Size(2.54, 1.5875), Drill(1.0)) assert str( footprint_pad ) == """(pad 5c4d39d3-35cc-4836-a082-693143ee9135 (side tht) (shape rect)
def test_text() -> None: text = str( Text('b9c4aa19-0a46-400c-9c96-e8c3dfb8f83e', Layer('sym_names'), Value('{{NAME}}'), Align('center bottom'), Height(2.54), Position(0.0, 22.86), Rotation(0.0))) assert text == '(text b9c4aa19-0a46-400c-9c96-e8c3dfb8f83e (layer sym_names) (value "{{NAME}}")\n' +\ ' (align center bottom) (height 2.54) (position 0.0 22.86) (rotation 0.0)\n' +\ ')'
def test_symbol_pin() -> None: symbol_pin_s_exp = str( SymbolPin('my_uuid', Name('foo'), Position(1.0, 2.0), Rotation(180.0), Length(3.81))) assert symbol_pin_s_exp == '(pin my_uuid (name "foo")\n' + \ ' (position 1.0 2.0) (rotation 180.0) (length 3.81)\n' + \ ')'
def test_component_gate() -> None: gate = Gate('c1e4b542-a1b1-44d5-bec3-070776143a29', SymbolUUID('8f1a97f2-4cdf-43da-b38d-b3787c47b5ad'), Position(0.0, 0.0), Rotation(0.0), Required(True), Suffix('')) gate.add_pin_signal_map( PinSignalMap('0189aafc-f88a-4e65-8fb4-09a047a3e334', SignalUUID('46f7e0e2-74a6-442b-9a5c-1bd4ea3da59c'), TextDesignator.SYMBOL_PIN_NAME)) assert str(gate) == """(gate c1e4b542-a1b1-44d5-bec3-070776143a29
def test_stroke_text() -> None: stroke_text = StrokeText('f16d1604-8a82-4688-bc58-be1c1375873f', Layer('top_names'), Height(1.0), StrokeWidth(0.2), LetterSpacing.AUTO, LineSpacing.AUTO, Align('center bottom'), Position(0.0, 25.63), Rotation(0.0), AutoRotate(True), Mirror(False), Value('{{NAME}}')) assert str( stroke_text ) == """(stroke_text f16d1604-8a82-4688-bc58-be1c1375873f (layer top_names)
def test_component_variant() -> None: gate = Gate('c1e4b542-a1b1-44d5-bec3-070776143a29', SymbolUUID('8f1a97f2-4cdf-43da-b38d-b3787c47b5ad'), Position(0.0, 0.0), Rotation(0.0), Required(True), Suffix('')) gate.add_pin_signal_map( PinSignalMap('0189aafc-f88a-4e65-8fb4-09a047a3e334', SignalUUID('46f7e0e2-74a6-442b-9a5c-1bd4ea3da59c'), TextDesignator.SYMBOL_PIN_NAME)) variant = Variant('abeeeed0-6e9a-4fdc-bc2b-e2c5b06bbe3a', Norm.EMPTY, Name('default'), Description(''), gate) assert str( variant) == """(variant abeeeed0-6e9a-4fdc-bc2b-e2c5b06bbe3a (norm "")
def generate_cmp( name: str, mcus: List[MCU], symbol_map: Dict[str, str], debug: bool = False, ) -> None: """ When generating components, to reduce the number of components, they are merged as follows: - For every MCU, the "ref without flash" is calculated by replacing the 11th character in the ref name with an `x` and cutting off everything after the package character. - MCUs that share the same pinout will be merged if their ref names without flash are the same - The name of the component will be generated as follows: STM32F429IEHx + STM32F429IGHx + STM32F429IIHx = STM32F429I[EGI]Hx. - To achieve a stable UUID even if new MCUs are added, the "ref without flash" is combined with the SHA1 hash of the pins. Because renaming the pinout might result in a different UUID, when upgrading the stm-pinout database, changes (but not additions) must be analyzed manually. """ components = [] for mcu in mcus: (placement, pin_mapping) = mcu.generate_placement_data(debug) cmp_version = '0.1' component = Component( uuid('cmp', mcu.component_identifier, 'cmp'), Name(name), Description(mcu.component_description), mcu.keywords, author, Version(cmp_version), Created('2020-01-30T20:55:23Z'), Deprecated(False), cmpcat, SchematicOnly(False), DefaultValue('{{PARTNUMBER or DEVICE or COMPONENT}}'), Prefix('U'), ) # Add signals signals = sorted({pin.name for pin in mcu.pins}, key=human_sort_key) for signal in signals: component.add_signal(Signal( # Use original signal name, so that changing the cleanup function # does not influence the identifier. uuid('cmp', mcu.component_identifier, 'signal-{}'.format(signal)), # Use cleaned up signal name for name Name(signal), Role.PASSIVE, Required(False), Negated(False), Clock(False), ForcedNet(''), )) # Add symbol variant gate = Gate( uuid('cmp', mcu.component_identifier, 'variant-single-gate1'), SymbolUUID(uuid('sym', mcu.symbol_identifier, 'sym')), Position(0, 0), Rotation(0.0), Required(True), Suffix(''), ) for generic, concrete in pin_mapping.items(): gate.add_pin_signal_map(PinSignalMap( uuid('sym', mcu.symbol_identifier, 'pin-{}'.format(generic)), SignalUUID(uuid('cmp', mcu.component_identifier, 'signal-{}'.format(concrete))), TextDesignator.SIGNAL_NAME, )) component.add_variant(Variant( uuid('cmp', mcu.component_identifier, 'variant-single'), Norm.EMPTY, Name('single'), Description('Symbol with all MCU pins'), gate, )) components.append(component) # Make sure all grouped components are identical assert len(set([str(c) for c in components])) == 1 components[0].serialize('out/stm_mcu/cmp') print('Wrote cmp {}'.format(name))
def generate_sym(mcus: List[MCU], symbol_map: Dict[str, str], debug: bool = False) -> None: # Determine symbol width pin_mappings = [mcu.generate_placement_data()[1].values() for mcu in mcus] max_pin_name_len = max([max(map(len, pin_map)) for pin_map in pin_mappings]) width = width_wide if max_pin_name_len >= width_wide_threshold else width_regular symbols = [] for mcu in mcus: assert mcu.symbol_identifier not in symbol_map sym_version = '0.1' # Generate pin placement data (placement, pin_mapping) = mcu.generate_placement_data(debug) if debug: print(pin_mapping) uuid_sym = uuid('sym', mcu.symbol_identifier, 'sym') symbol = Symbol( uuid_sym, Name(mcu.symbol_name), Description(mcu.symbol_description), mcu.keywords, author, Version(sym_version), Created('2020-01-30T20:55:23Z'), cmpcat, ) placement_pins = placement.pins(width, grid) placement_pins.sort(key=lambda x: (x[1].x, x[1].y)) for pin_name, position, rotation in placement.pins(width, grid): symbol.add_pin(SymbolPin( uuid('sym', mcu.symbol_identifier, 'pin-{}'.format(pin_name)), Name(pin_name), position, rotation, Length(grid), )) polygon = Polygon( uuid('sym', mcu.symbol_identifier, 'polygon'), Layer('sym_outlines'), Width(line_width), Fill(False), GrabArea(True), ) (max_y, min_y) = placement.maxmin_y(grid) dx = width * grid / 2 polygon.add_vertex(Vertex(Position(-dx, max_y), Angle(0.0))) polygon.add_vertex(Vertex(Position( dx, max_y), Angle(0.0))) polygon.add_vertex(Vertex(Position( dx, min_y), Angle(0.0))) polygon.add_vertex(Vertex(Position(-dx, min_y), Angle(0.0))) polygon.add_vertex(Vertex(Position(-dx, max_y), Angle(0.0))) symbol.add_polygon(polygon) text_name = Text( uuid('sym', mcu.symbol_identifier, 'text-name'), Layer('sym_names'), Value('{{NAME}}'), Align('left bottom'), Height(text_height), Position(-dx, max_y), Rotation(0.0), ) text_value = Text( uuid('sym', mcu.symbol_identifier, 'text-value'), Layer('sym_values'), Value('{{VALUE}}'), Align('left top'), Height(text_height), Position(-dx, min_y), Rotation(0.0), ) symbol.add_text(text_name) symbol.add_text(text_value) symbols.append(symbol) # Make sure all grouped symbols are identical assert len(set([str(s) for s in symbols])) == 1 dirpath = 'out/stm_mcu/sym' sym_dir_path = path.join(dirpath, symbols[0].uuid) if not (path.exists(sym_dir_path) and path.isdir(sym_dir_path)): makedirs(sym_dir_path) with open(path.join(sym_dir_path, '.librepcb-sym'), 'w') as f: f.write('0.1\n') with open(path.join(sym_dir_path, 'symbol.lp'), 'w') as f: f.write(str(symbols[0])) f.write('\n') symbol_map[mcus[0].symbol_identifier] = symbols[0].uuid print('Wrote sym {}'.format(symbols[0].name))
def test_rotation() -> None: rotation_s_exp = str(Rotation(180.0)) assert rotation_s_exp == '(rotation 180.0)'
def _create_footprint(footprint_identifier: str, name: str) -> Footprint: def _fpt_uuid(identifier: str) -> str: return _pkg_uuid(footprint_identifier + '-' + identifier) drill = LEAD_WIDTH_TO_DRILL[lead_width] restring = min( (0.4 if diameter >= 6.0 else 0.3), # preferred restring (pitch - drill - 0.25) / 2) # minimum required restring pad_diameter = drill + (2 * restring) # outer diameter of pad courtyard_diameter = diameter + (1.0 if diameter >= 10.0 else 0.8) def _generate_fill_polygon(identifier: str, layer: str) -> Polygon: polygon = Polygon( uuid=_fpt_uuid(identifier), layer=Layer(layer), width=Width(0.0), fill=Fill(True), grab_area=GrabArea(False), ) if ((pitch - pad_diameter) < 0.6): # not enough space, use a simplified polygon vertices = [ (0.0, (diameter / 2) - 0.2, 0.0), (0.0, (pad_diameter / 2) + 0.2, 0.0), (pitch / 2, (pad_diameter / 2) + 0.2, -180.0), (pitch / 2, -(pad_diameter / 2) - 0.2, 0.0), (0.0, -(pad_diameter / 2) - 0.2, 0.0), (0.0, -(diameter / 2) + 0.2, 180.0), (0.0, (diameter / 2) - 0.2, 0.0), ] else: vertices = [ (0.0, (diameter / 2) - 0.2, 0.0), (0.0, 0.0, 0.0), ((pitch / 2) - (pad_diameter / 2) - 0.2, 0.0, -180.0), ((pitch / 2) + (pad_diameter / 2) + 0.2, 0.0, -180.0), ((pitch / 2) - (pad_diameter / 2) - 0.2, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, -(diameter / 2) + 0.2, 180.0), (0.0, (diameter / 2) - 0.2, 0.0), ] for vertex in vertices: polygon.add_vertex( Vertex(Position(vertex[0], vertex[1]), Angle(vertex[2]))) return polygon footprint = Footprint( uuid=_fpt_uuid('footprint'), name=Name(name), description=Description(''), ) footprint.add_pad( FootprintPad( uuid=_pkg_uuid('pad-plus'), side=Side.THT, shape=Shape.RECT, position=Position(-pitch / 2, 0), rotation=Rotation(0), size=Size(pad_diameter, pad_diameter), drill=Drill(drill), )) footprint.add_pad( FootprintPad( uuid=_pkg_uuid('pad-minus'), side=Side.THT, shape=Shape.ROUND, position=Position(pitch / 2, 0), rotation=Rotation(0), size=Size(pad_diameter, pad_diameter), drill=Drill(drill), )) # placement footprint.add_circle( Circle( uuid=_fpt_uuid('circle-placement'), layer=Layer('top_placement'), width=Width(0.2), fill=Fill(False), grab_area=GrabArea(False), diameter=Diameter(diameter + 0.2), position=Position(0.0, 0.0), )) footprint.add_polygon( _generate_fill_polygon( identifier='polygon-placement-fill', layer='top_placement', )) # documentation footprint.add_circle( Circle( uuid=_fpt_uuid('circle-documentation'), layer=Layer('top_documentation'), width=Width(0.2), fill=Fill(False), grab_area=GrabArea(False), diameter=Diameter(diameter - 0.2), position=Position(0.0, 0.0), )) footprint.add_polygon( _generate_fill_polygon( identifier='polygon-documentation-fill', layer='top_documentation', )) # courtyard footprint.add_circle( Circle( uuid=_fpt_uuid('circle-courtyard'), layer=Layer('top_courtyard'), width=Width(0.2), fill=Fill(False), grab_area=GrabArea(False), diameter=Diameter(courtyard_diameter), position=Position(0.0, 0.0), )) # texts footprint.add_text( StrokeText( uuid=_fpt_uuid('text-name'), layer=Layer('top_names'), height=Height(1.0), stroke_width=StrokeWidth(0.2), letter_spacing=LetterSpacing.AUTO, line_spacing=LineSpacing.AUTO, align=Align('center bottom'), position=Position(0.0, (diameter / 2) + 0.8), rotation=Rotation(0.0), auto_rotate=AutoRotate(True), mirror=Mirror(False), value=Value('{{NAME}}'), )) footprint.add_text( StrokeText( uuid=_fpt_uuid('text-value'), layer=Layer('top_values'), height=Height(1.0), stroke_width=StrokeWidth(0.2), letter_spacing=LetterSpacing.AUTO, line_spacing=LineSpacing.AUTO, align=Align('center top'), position=Position(0.0, -(diameter / 2) - 0.8), rotation=Rotation(0.0), auto_rotate=AutoRotate(True), mirror=Mirror(False), value=Value('{{VALUE}}'), )) return footprint
def generate_cmp( dirpath: str, author: str, name: str, name_lower: str, kind: str, cmpcat: str, keywords: str, default_value: str, rows: int, min_pads: int, max_pads: int, version: str, create_date: Optional[str], ) -> None: category = 'cmp' assert rows in [1, 2] for i in range(min_pads, max_pads + 1, rows): per_row = i // rows variant = '{}x{}'.format(rows, per_row) def _uuid(identifier: str) -> str: return uuid(category, kind, variant, identifier) uuid_cmp = _uuid('cmp') uuid_pins = [ uuid('sym', kind, variant, 'pin-{}'.format(p)) for p in range(i) ] uuid_signals = [_uuid('signal-{}'.format(p)) for p in range(i)] uuid_variant = _uuid('variant-default') uuid_gate = _uuid('gate-default') uuid_symbol = uuid('sym', kind, variant, 'sym') # General info component = Component( uuid_cmp, Name('{} {}x{:02d}'.format(name, rows, per_row)), Description('A {}x{} {}.\\n\\n' 'Generated with {}'.format(rows, per_row, name_lower, generator)), Keywords('connector, {}x{}, {}'.format(rows, per_row, keywords)), Author(author), Version(version), Created(create_date or now()), Deprecated(False), Category(cmpcat), SchematicOnly(False), DefaultValue(default_value), Prefix('J'), ) for p in range(1, i + 1): component.add_signal( Signal( uuid_signals[p - 1], Name(str(p)), Role.PASSIVE, Required(False), Negated(False), Clock(False), ForcedNet(''), )) gate = Gate( uuid_gate, SymbolUUID(uuid_symbol), Position(0.0, 0.0), Rotation(0.0), Required(True), Suffix(''), ) for p in range(1, i + 1): gate.add_pin_signal_map( PinSignalMap( uuid_pins[p - 1], SignalUUID(uuid_signals[p - 1]), TextDesignator.SYMBOL_PIN_NAME, )) component.add_variant( Variant(uuid_variant, Norm.EMPTY, Name('default'), Description(''), gate)) component.serialize(dirpath) print('{}x{} {}: Wrote component {}'.format(rows, per_row, kind, uuid_cmp))
def generate_sym( dirpath: str, author: str, name: str, name_lower: str, kind: str, cmpcat: str, keywords: str, rows: int, min_pads: int, max_pads: int, version: str, create_date: Optional[str], ) -> None: category = 'sym' assert rows in [1, 2] for i in range(min_pads, max_pads + 1, rows): per_row = i // rows w = width * rows # Make double-row symbols wider! variant = '{}x{}'.format(rows, per_row) def _uuid(identifier: str) -> str: return uuid(category, kind, variant, identifier) uuid_sym = _uuid('sym') uuid_pins = [_uuid('pin-{}'.format(p)) for p in range(i)] uuid_polygon = _uuid('polygon-contour') uuid_decoration = _uuid('polygon-decoration') uuid_text_name = _uuid('text-name') uuid_text_value = _uuid('text-value') # General info symbol = Symbol( uuid_sym, Name('{} {}x{:02d}'.format(name, rows, per_row)), Description('A {}x{} {}.\\n\\n' 'Generated with {}'.format(rows, per_row, name_lower, generator)), Keywords('connector, {}x{}, {}'.format(rows, per_row, keywords)), Author(author), Version(version), Created(create_date or now()), Category(cmpcat), ) for p in range(1, i + 1): x_sign = 1 if (p % rows == 0) else -1 pin = SymbolPin( uuid_pins[p - 1], Name(str(p)), Position((w + 2.54) * x_sign, get_y(p, i, rows, spacing, True)), Rotation(180.0 if p % rows == 0 else 0), Length(3.81)) symbol.add_pin(pin) # Polygons y_max, y_min = get_rectangle_bounds(i, rows, spacing, spacing, True) polygon = Polygon(uuid_polygon, Layer('sym_outlines'), Width(line_width), Fill(False), GrabArea(True)) polygon.add_vertex(Vertex(Position(-w, y_max), Angle(0.0))) polygon.add_vertex(Vertex(Position(w, y_max), Angle(0.0))) polygon.add_vertex(Vertex(Position(w, y_min), Angle(0.0))) polygon.add_vertex(Vertex(Position(-w, y_min), Angle(0.0))) polygon.add_vertex(Vertex(Position(-w, y_max), Angle(0.0))) symbol.add_polygon(polygon) # Decorations if kind == KIND_HEADER: # Headers: Small rectangle for p in range(1, i + 1): x_sign = 1 if (p % rows == 0) else -1 y = get_y(p, i, rows, spacing, True) dx = spacing / 8 * 1.5 * x_sign dy = spacing / 8 / 1.5 x_offset = x_sign * (w - 1.27) polygon = Polygon(uuid_decoration, Layer('sym_outlines'), Width(line_width), Fill(True), GrabArea(True)) polygon.add_vertex( Vertex(Position(x_offset - dx, y + dy), Angle(0.0))) polygon.add_vertex( Vertex(Position(x_offset + dx, y + dy), Angle(0.0))) polygon.add_vertex( Vertex(Position(x_offset + dx, y - dy), Angle(0.0))) polygon.add_vertex( Vertex(Position(x_offset - dx, y - dy), Angle(0.0))) polygon.add_vertex( Vertex(Position(x_offset - dx, y + dy), Angle(0.0))) symbol.add_polygon(polygon) elif kind == KIND_SOCKET: # Sockets: Small semicircle for p in range(1, i + 1): x_sign = 1 if (p % rows == 0) else -1 y = get_y(p, i, rows, spacing, True) dy = spacing / 4 * 0.75 x_offset = x_sign * (w - 1.27 - dy * 0.75) polygon = Polygon(uuid_decoration, Layer('sym_outlines'), Width(line_width * 0.75), Fill(False), GrabArea(False)) polygon.add_vertex( Vertex(Position(x_offset, y - dy), Angle(x_sign * 135.0))) polygon.add_vertex( Vertex(Position(x_offset, y + dy), Angle(0.0))) symbol.add_polygon(polygon) # Text y_max, y_min = get_rectangle_bounds(i, rows, spacing, spacing, True) text = Text(uuid_text_name, Layer('sym_names'), Value('{{NAME}}'), Align('center bottom'), Height(sym_text_height), Position(0.0, y_max), Rotation(0.0)) symbol.add_text(text) text = Text(uuid_text_value, Layer('sym_values'), Value('{{VALUE}}'), Align('center top'), Height(sym_text_height), Position(0.0, y_min), Rotation(0.0)) symbol.add_text(text) sym_dir_path = path.join(dirpath, uuid_sym) if not (path.exists(sym_dir_path) and path.isdir(sym_dir_path)): makedirs(sym_dir_path) with open(path.join(sym_dir_path, '.librepcb-sym'), 'w') as f: f.write('0.1\n') with open(path.join(sym_dir_path, 'symbol.lp'), 'w') as f: f.write(str(symbol)) f.write('\n') print('{}x{} {}: Wrote symbol {}'.format(rows, per_row, kind, uuid_sym))