def generate_one_footprint(pincount, configuration):
    silk_x_min = x_min - configuration['silk_fab_offset']
    silk_y_min = y_min - configuration['silk_fab_offset']
    silk_y_max = y_max + configuration['silk_fab_offset']

    x_mid = (pincount - 1) * pitch / 2.0
    x_max = (pincount - 1) * pitch + 1.95
    silk_x_max = x_max + configuration['silk_fab_offset']

    # Through-hole type shrouded header, Top entry type
    mpn = "B{n}B-PH-K".format(n=pincount)  #JST part number format string
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pincount,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator"
        .format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    # create Silkscreen
    kicad_mod.append(
        RectLine(start=[silk_x_min, silk_y_min],
                 end=[silk_x_max, silk_y_max],
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))

    silk_inner_left = -1.45
    silk_inner_right = x_max - 0.5

    poly_silk_p1_protrusion = [{
        'x': -0.3,
        'y': silk_y_min
    }, {
        'x': -0.3,
        'y': silk_y_min - 0.2
    }, {
        'x': -0.6,
        'y': silk_y_min - 0.2
    }, {
        'x': -0.6,
        'y': silk_y_min
    }]
    kicad_mod.append(
        PolygoneLine(polygone=poly_silk_p1_protrusion,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        Line(start=[-0.3, silk_y_min - 0.1],
             end=[-0.6, silk_y_min - 0.1],
             layer='F.SilkS',
             width=configuration['silk_line_width']))

    if configuration['allow_silk_below_part'] == 'tht' or configuration[
            'allow_silk_below_part'] == 'both':
        poly_silk_inner_outline = [{
            'x': 0.5,
            'y': silk_y_min
        }, {
            'x': 0.5,
            'y': -1.2
        }, {
            'x': silk_inner_left,
            'y': -1.2
        }, {
            'x': silk_inner_left,
            'y': 2.3
        }, {
            'x': silk_inner_right,
            'y': 2.3
        }, {
            'x': silk_inner_right,
            'y': -1.2
        }, {
            'x': x_max - 2.45,
            'y': -1.2
        }, {
            'x': x_max - 2.45,
            'y': silk_y_min
        }]
        kicad_mod.append(
            PolygoneLine(polygone=poly_silk_inner_outline,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))

        kicad_mod.append(
            Line(start=[silk_x_min, -0.5],
                 end=[silk_inner_left, -0.5],
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))
        kicad_mod.append(
            Line(start=[silk_x_min, 0.8],
                 end=[silk_inner_left, 0.8],
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))

        kicad_mod.append(
            Line(start=[silk_x_max, -0.5],
                 end=[silk_inner_right, -0.5],
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))
        kicad_mod.append(
            Line(start=[silk_x_max, 0.8],
                 end=[silk_inner_right, 0.8],
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))

        for i in range(0, pincount - 1):
            middle_x = 1 + i * 2
            start_x = middle_x - 0.1
            end_x = middle_x + 0.1
            poly_silk_inner_protrusion = [{
                'x': start_x,
                'y': 2.3
            }, {
                'x': start_x,
                'y': 1.8
            }, {
                'x': end_x,
                'y': 1.8
            }, {
                'x': end_x,
                'y': 2.3
            }]
            kicad_mod.append(
                PolygoneLine(polygone=poly_silk_inner_protrusion,
                             layer='F.SilkS',
                             width=configuration['silk_line_width']))
            kicad_mod.append(
                Line(start=[middle_x, 2.3],
                     end=[middle_x, 1.8],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    ########################### Pin 1 marker ################################
    poly_pin1_marker = [{
        'x': silk_x_min - pin1_marker_offset + pin1_marker_linelen,
        'y': silk_y_min - pin1_marker_offset
    }, {
        'x': silk_x_min - pin1_marker_offset,
        'y': silk_y_min - pin1_marker_offset
    }, {
        'x':
        silk_x_min - pin1_marker_offset,
        'y':
        silk_y_min - pin1_marker_offset + pin1_marker_linelen
    }]
    kicad_mod.append(
        PolygoneLine(polygone=poly_pin1_marker,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    if fab_pin1_marker_type == 1:
        kicad_mod.append(
            PolygoneLine(polygone=poly_pin1_marker,
                         layer='F.Fab',
                         width=configuration['fab_line_width']))

    if fab_pin1_marker_type == 2:
        poly_pin1_marker_type2 = [{
            'x': -1,
            'y': y_min
        }, {
            'x': 0,
            'y': y_min + 1
        }, {
            'x': 1,
            'y': y_min
        }]
        kicad_mod.append(
            PolygoneLine(polygone=poly_pin1_marker_type2,
                         layer='F.Fab',
                         width=configuration['fab_line_width']))

    ########################## Fab Outline ###############################
    kicad_mod.append(
        RectLine(start=[x_min, y_min],
                 end=[x_max, y_max],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))
    ############################# CrtYd ##################################
    part_x_min = x_min
    part_x_max = x_max
    part_y_min = y_min
    part_y_max = y_max

    cx1 = roundToBase(
        part_x_min - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = roundToBase(
        part_y_min - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cx2 = roundToBase(
        part_x_max + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        part_y_max + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ############################# Pads ##################################
    pad_size = [
        pitch - pad_to_pad_clearance,
        drill_size + 2 * pad_copper_y_solder_length
    ]
    if pad_size[0] - drill_size < 2 * min_annular_ring:
        pad_size[0] = drill_size + 2 * min_annular_ring

    # kicad_mod.append(Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    #                     at=[0, 0], size=pad_size,
    #                     drill=drill_size, layers=Pad.LAYERS_THT))

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(
        PadArray(initial=1,
                 start=[0, 0],
                 x_spacing=pitch,
                 pincount=pincount,
                 size=pad_size,
                 drill=drill_size,
                 type=Pad.TYPE_THT,
                 shape=Pad.SHAPE_OVAL,
                 layers=Pad.LAYERS_THT,
                 **optional_pad_params))

    ######################### Text Fields ###############################
    text_center_y = 1.5
    body_edge = {
        'left': part_x_min,
        'right': part_x_max,
        'top': part_y_min,
        'bottom': part_y_max
    }
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position=text_center_y)

    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    mpn = part_base.format(n=pins)
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s}, shrouded ({:s}),  generated with kicad-footprint-generator".format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #calculate dimensions
    A = (pins - 1) * pitch
    B = A + 5.84



    #coordinate locations (latch is not drawn but is 2.3mm above y5 and width varies)
    #    x1 x5 x3           x4 x6 x2
    # y1 ______             ______
    # y3 | O  |_____________|    |
    # y5 |  ___________________  |
    #    |  | 1 2 3 4 5 6 7 8  | |
    # y4 |  |__________________| |
    # y2 |_______________________|

    #draw the component outline
    x1 = A/2 - B/2
    x2 = x1 + B
    x3 = x1 + 2.9
    x4 = x2 - 2.9
    x5 = -2
    x6 = pitch * (pins - 1) + 2
    y2 = 5.2
    y1 = y2 - 9.7
    y3 = y1 + 1.2
    y4 = 4.3
    y5 = y4 - 6.4
    body_edge={'left':x1, 'right':x2, 'top':y1, 'bottom':y2}

    #draw outline on F.Fab layer
    kicad_mod.append(PolygoneLine(polygone=[{'x':x1,'y':y2},
                                            {'x':x1,'y':y1},
                                            {'x':x3,'y':y1},
                                            {'x':x3,'y':y3},
                                            {'x':x4,'y':y3},
                                            {'x':x4,'y':y1},
                                            {'x':x2,'y':y1},
                                            {'x':x2,'y':y2},
                                            {'x':x1,'y':y2}],
                                        layer='F.Fab',width=configuration['fab_line_width']))

    #draw rectangle on F.Fab for shroud walls
    kicad_mod.append(RectLine(start=[x5,y4],end=[x6,y5],layer='F.Fab',width=configuration['fab_line_width']))

	#draw pin1 mark on F.Fab
    kicad_mod.append(PolygoneLine(polygone=[{'x':x1,'y':-1},{'x':(x1+1),'y':0}],layer='F.Fab',width=configuration['fab_line_width']))
    kicad_mod.append(PolygoneLine(polygone=[{'x':x1,'y':1},{'x':(x1+1),'y':0}],layer='F.Fab',width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(x1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(y1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(x2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(y2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    #draw silk outline
    off = configuration['silk_fab_offset']
    x1 -= off
    y1 -= off
    x2 += off
    y2 += off
    x3 += off
    y3 -= off
    x4 -= off

    kicad_mod.append(PolygoneLine(polygone=[{'x':x1,'y':y2},
                                            {'x':x1,'y':y1},
                                            {'x':x3,'y':y1},
                                            {'x':x3,'y':y3},
                                            {'x':x4,'y':y3},
                                            {'x':x4,'y':y1},
                                            {'x':x2,'y':y1},
                                            {'x':x2,'y':y2},
                                            {'x':x1,'y':y2}],
                                        layer='F.SilkS', width=configuration['silk_line_width']))

    #add pin1 mark on silk
    px = x1 - 0.2
    m = 0.3

    marker = [{'x': px,'y': 0},{'x': px-2*m,'y': m},{'x': px-2*m,'y': -m},{'x': px,'y': 0}]

    kicad_mod.append(PolygoneLine(polygone=marker,layer="F.SilkS", width=configuration['silk_line_width']))

    #generate tht pads (1.65mm drill with 2.35x3mm oval pads)
    pad_size = [pitch - pad_to_pad_clearance, drill + 2*pad_copper_y_solder_length]
    if pad_size[0] - drill < 2*min_annular_ring:
        pad_size[0] = drill + 2*min_annular_ring
    if pad_size[0] - drill > 2*pad_copper_y_solder_length:
        pad_size[0] = drill + 2*pad_copper_y_solder_length

    shape=Pad.SHAPE_OVAL
    if pad_size[1] == pad_size[0]:
        shape=Pad.SHAPE_CIRCLE

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(
        pincount=pins, x_spacing=pitch,
        type=Pad.TYPE_THT, shape=shape,
        size=pad_size, drill=drill, layers=Pad.LAYERS_THT,
        **optional_pad_params))

    #generate mounting post
    post = Pad(at=mh_at, type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=mh_drill, drill=mh_drill, layers=Pad.LAYERS_NPTH)
    kicad_mod.append(post)

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position=2.5)

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pincount, configuration):
    if pincount in [6, 8]:
        number_of_rows = 2
        pin_per_row = int(pincount / 2)
    else:
        number_of_rows = 1
        pin_per_row = pincount

    mpn = part_base.format(n=pincount)

    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pin_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator".format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    conn_width = jwpf_widths[pincount]
    conn_length = jwpf_lengths[pincount]

    mount_hole_offset_y = 2.05 if number_of_rows == 1 else 2.45


    # Add texts
    x_mid = (number_of_rows-1) * row_spacing / 2
    y_mid = (pin_per_row - 1) * pitch / 2.0

    # Connector outline
    y1 = y_mid - conn_length / 2
    y2 = y_mid + conn_length / 2

    x1 = -5.4 # measured from 3D model alignment
    x2 = x1 + conn_width

    body_edge={'left':x1, 'right':x2, 'top':y1, 'bottom':y2}

    y_ref = -3 if number_of_rows == 1 else -4

    pad_size = [pad_drill + 2*pad_copper_x_solder_length, pitch - pad_to_pad_clearance]
    if number_of_rows > 1:
        if pad_size[0] - pad_drill > 2*pad_copper_x_solder_length:
            pad_size[0] = pad_drill + 2*pad_copper_x_solder_length
        if pad_size[0] - pad_drill < 2*min_annular_ring:
            pad_size[0] = pad_drill + 2*min_annular_ring
    if pad_size[1] - pad_drill < 2*min_annular_ring:
        pad_size[1] = pad_drill + 2*min_annular_ring

    if pad_size[0] == pad_size[1]:
        pad_shape = Pad.SHAPE_CIRCLE
    else:
        pad_shape = Pad.SHAPE_OVAL

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    # Create pins
    for i in range(number_of_rows):
        kicad_mod.append(PadArray(
            initial=1+i*pin_per_row, start=[i*row_spacing, 0],
            pincount=pin_per_row, y_spacing=pitch,
            type=Pad.TYPE_THT, shape=pad_shape,
            size=pad_size, drill=pad_drill, layers=Pad.LAYERS_THT,
            **optional_pad_params))

    # Add mounting hole
    mx = -mount_hole_offset_x
    my = (pin_per_row - 1) * pitch + mount_hole_offset_y
    kicad_mod.append(Pad(at=[mx, my], size=mount_hole_size, drill=mount_hole_size, shape=Pad.SHAPE_CIRCLE, type=Pad.TYPE_NPTH, layers=Pad.LAYERS_NPTH))

    # Tab dimensions
    tw = 7
    tt = 0.5

    ########################### CrtYd #################################
    cx1 = roundToBase(x1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(y1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(x2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(y2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    def draw_outline(offset=0, layer='F.Fab', width=configuration['fab_line_width']):
        O = offset
        R = 1.0

        if pincount == 2:
            poly = [
                {'x': x2 + O - R, 'y': y1 - O},
                {'x': x1 - O, 'y': y1 - O},
                {'x': x1 - O, 'y': y2 + O},
                {'x': x2 + O - R, 'y': y2 + O},
            ]

            kicad_mod.append(PolygoneLine(polygone=poly, layer=layer, width=width))
        else:
            # top line
            kicad_mod.append(Line(start=[tt+x1-O+R, y1-O], end=[x2+O-R, y1-O], layer=layer, width=width))
            # bottom line
            kicad_mod.append(Line(start=[tt+x1-O+R, y2+O], end=[x2+O-R, y2+O], layer=layer, width=width))

            # left line (including tab)
            poly = [
                {'x': tt+x1-O, 'y': y1-O+R},
                {'x': tt+x1-O, 'y': y_mid - tw/2.0 - O},
                {'x': x1-O, 'y': y_mid - tw/2.0 - O},
                {'x': x1-O, 'y': y_mid + tw/2.0 + O},
                {'x': tt+x1-O, 'y': y_mid + tw/2.0 + O},
                {'x': tt+x1-O, 'y': y2+O-R}
            ]

            kicad_mod.append(PolygoneLine(polygone=poly, width=width, layer=layer))

            # top left
            kicad_mod.append(Arc(center=[tt+x1-O+R, y1-O+R], start=[tt+x1-O, y1-O+R], angle=90.0, layer=layer, width=width))
            # bottom left
            kicad_mod.append(Arc(center=[tt+x1-O+R, y2+O-R], start=[tt+x1-O+R, y2+O], angle=90.0, layer=layer, width=width))


        # right line
        kicad_mod.append(Line(start=[x2+O, y1-O+R], end=[x2+O, y2+O-R], layer=layer, width=width))

        # top right
        kicad_mod.append(Arc(center=[x2+O-R, y1-O+R], start=[x2+O-R, y1-O], angle=90.0, layer=layer, width=width))

        # bottom right
        kicad_mod.append(Arc(center=[x2+O-R, y2+O-R], start=[x2+O, y2+O-R], angle=90.0, layer=layer, width=width))


    draw_outline()
    draw_outline(offset=configuration['silk_fab_offset'], layer='F.SilkS', width=configuration['silk_line_width'])

    # Add pin-1 marker on F.SilkS
    Q = 0.35 # offset
    L = 1.5
    p1 = [
        {'x': x1 - Q, 'y': y1 - Q + L},
        {'x': x1 - Q, 'y': y1 - Q},
        {'x': x1 - Q + L, 'y': y1 - Q},
    ]

    kicad_mod.append(PolygoneLine(polygone=p1, layer='F.SilkS', width=configuration['silk_line_width']))

    # Add pin-1 marker on F.Fab
    D = -0.5 - pad_size[1] / 2
    M = 0.75
    p1 = [
        {'x': -M/2, 'y': D - M},
        {'x': M/2, 'y': D - M},
        {'x': 0, 'y': D},
        {'x': -M/2, 'y': D - M},
    ]

    kicad_mod.append(PolygoneLine(polygone=p1, layer='F.Fab', width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='left')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    mpn = part_code.format(n=pins)
    off = configuration['silk_fab_offset']
    pad_silk_off = configuration['silk_line_width']/2 + configuration['silk_pad_clearance']

    pad_silk_off = configuration['silk_line_width']/2 + configuration['silk_pad_clearance']
    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    footprint_name = footprint_name.replace("__",'_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Molex {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))



    #vertical center of connector
    y2 = 3.25 + mount_size / 2
    y1 = y2 - 7.05
    yt = y2 - 8

    #Major dimensions
    B = ( pins - 1 ) * pitch
    A = B + 4.7

    #calculate major dimensions
    x1 = (B - A) / 2
    x2 = x1 + A

    body_edge={
        'left':x1,
        'right':x2,
        'bottom':y2,
        'top': y1
        }
    bounding_box = body_edge.copy()
    bounding_box['top'] = yt

    #pins

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(
        PadArray(
                pincount=pins,
                initial = 1,
                start = [0, 0],
                x_spacing = pitch,
                type = Pad.TYPE_THT,
                layers = Pad.LAYERS_THT,
                shape = pad_shape,
                size = pad_size,
                drill = drill,
                **optional_pad_params
                )
    )

    #mounting hole
    if pins > 1:
        kicad_mod.append(Pad(at=[-1.5,3.25],type=Pad.TYPE_NPTH,layers=Pad.LAYERS_NPTH,shape=Pad.SHAPE_CIRCLE,size=mount_size,drill=mount_size))

    #connector outline

    #tab thickness
    t = 1.2

    def outline(offset=0):
        outline = [
        {'x': B/2, 'y': y2 + offset},
        {'x': x1 - offset, 'y': y2 + offset},
        {'x': x1 - offset, 'y': yt - offset},
        {'x': x1 + t + offset, 'y': yt - offset},
        {'x': x1 + t + offset, 'y': y1 - offset},
        {'x': B/2, 'y': y1 - offset},
        ]

        return outline

    kicad_mod.append(PolygoneLine(polygone=outline(),layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(PolygoneLine(polygone=outline(),x_mirror=B/2,
        layer='F.Fab', width=configuration['fab_line_width']))

    kicad_mod.append(PolygoneLine(polygone=outline(offset=off),
        layer='F.SilkS', width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=outline(offset=off),x_mirror=B/2,
        layer='F.SilkS', width=configuration['silk_line_width']))

    #draw lines between pads on F.Fab
    for i in range(pins - 1):
        x = (i + 0.5) * pitch

        kicad_mod.append(Line(start=[x,y1], end=[x,y2],
            layer='F.Fab', width=configuration['fab_line_width']))

    #pin-1 indicator
    kicad_mod.append(Circle(center=[0,-3.75], radius=0.25,
        layer='F.SilkS', width=configuration['silk_line_width']))

    sl=2
    pin = [
        {'y': body_edge['top'], 'x': -sl/2},
        {'y': body_edge['top'] + sl/sqrt(2), 'x': 0},
        {'y': body_edge['top'], 'x': sl/2}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin,
        width=configuration['fab_line_width'], layer='F.Fab'))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom'] + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position=-3.75)

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
    def generateFootprint(self, device_params):
        fab_line_width = self.configuration.get('fab_line_width', 0.1)
        silk_line_width = self.configuration.get('silk_line_width', 0.12)

        lib_name = self.configuration['lib_name_format_string'].format(category=category)

        if 'body_size_x' in device_params:
            size_x = device_params['body_size_x']
        else:
            size_x = (device_params['body_size_x_max'] + device_params['body_size_x_min'])/2

        if 'body_size_y' in device_params:
            size_y = device_params['body_size_y']
        else:
            size_y = (device_params['body_size_y_max'] + device_params['body_size_y_min'])/2

        pincount = device_params['num_pins_x']*2 + device_params['num_pins_y']*2

        ipc_reference = 'ipc_spec_j_lead'

        ipc_data_set = self.ipc_defintions[ipc_reference][ipc_density]
        ipc_round_base = self.ipc_defintions[ipc_reference]['round_base']

        pad_details = self.calcPadDetails(device_params, ipc_data_set, ipc_round_base)


        suffix = device_params.get('suffix', '').format(pad_x=pad_details['left']['size'][0],
            pad_y=pad_details['left']['size'][1])
        suffix_3d = suffix if device_params.get('include_suffix_in_3dpath', 'True') == 'True' else ""

        model3d_path_prefix = self.configuration.get('3d_model_prefix','${KISYS3DMOD}')
        name_format = self.configuration['fp_name_format_string']

        fp_name = name_format.format(
            man=device_params.get('manufacturer',''),
            mpn=device_params.get('part_number',''),
            pkg=device_params['device_type'],
            pincount=pincount,
            size_y=size_y,
            size_x=size_x,
            pitch=device_params['pitch'],
            suffix=suffix
            ).replace('__','_').lstrip('_')

        fp_name_2 = name_format.format(
            man=device_params.get('manufacturer',''),
            mpn=device_params.get('part_number',''),
            pkg=device_params['device_type'],
            pincount=pincount,
            size_y=size_y,
            size_x=size_x,
            pitch=device_params['pitch'],
            suffix=suffix_3d
            ).replace('__','_').lstrip('_')

        model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'\
            .format(
                model3d_path_prefix=model3d_path_prefix, lib_name=lib_name,
                fp_name=fp_name_2)
        #print(fp_name)
        #print(pad_details)

        kicad_mod = Footprint(fp_name)

                # init kicad footprint
        kicad_mod.setDescription(
            "{manufacturer} {mpn} {package}, {pincount} Pin ({datasheet}), generated with kicad-footprint-generator {scriptname}"\
            .format(
                manufacturer = device_params.get('manufacturer',''),
                package = device_params['device_type'],
                mpn = device_params.get('part_number',''),
                pincount = pincount,
                datasheet = device_params['size_source'],
                scriptname = os.path.basename(__file__).replace("  ", " ")
                ).lstrip())

        kicad_mod.setTags(self.configuration['keyword_fp_string']\
            .format(
                man=device_params.get('manufacturer',''),
                package=device_params['device_type'],
                category=category
            ).lstrip())
        kicad_mod.setAttribute('smd')

        pad_shape_details = {}
        pad_shape_details['shape'] = Pad.SHAPE_ROUNDRECT
        pad_shape_details['radius_ratio'] = configuration.get('round_rect_radius_ratio', 0)
        if 'round_rect_max_radius' in configuration:
            pad_shape_details['maximum_radius'] = configuration['round_rect_max_radius']

        init = 1
        kicad_mod.append(PadArray(
            initial= init,
            type=Pad.TYPE_SMT,
            layers=Pad.LAYERS_SMT,
            pincount=int(math.ceil(device_params['num_pins_x']/2)),
            x_spacing=-device_params['pitch'], y_spacing=0,
            **pad_details['first'], **pad_shape_details))

        init += int(math.ceil(device_params['num_pins_x']/2))
        kicad_mod.append(PadArray(
            initial= init,
            type=Pad.TYPE_SMT,
            layers=Pad.LAYERS_SMT,
            pincount=device_params['num_pins_y'],
            x_spacing=0, y_spacing=device_params['pitch'],
            **pad_details['left'], **pad_shape_details))

        init += device_params['num_pins_y']
        kicad_mod.append(PadArray(
            initial= init,
            type=Pad.TYPE_SMT,
            layers=Pad.LAYERS_SMT,
            pincount=device_params['num_pins_x'],
            y_spacing=0, x_spacing=device_params['pitch'],
            **pad_details['bottom'], **pad_shape_details))

        init += device_params['num_pins_x']
        kicad_mod.append(PadArray(
            initial= init,
            type=Pad.TYPE_SMT,
            layers=Pad.LAYERS_SMT,
            pincount=device_params['num_pins_y'],
            x_spacing=0, y_spacing=-device_params['pitch'],
            **pad_details['right'], **pad_shape_details))

        init += device_params['num_pins_y']
        kicad_mod.append(PadArray(
            initial= init,
            type=Pad.TYPE_SMT,
            layers=Pad.LAYERS_SMT,
            pincount=int(math.floor(device_params['num_pins_x']/2)),
            y_spacing=0, x_spacing=-device_params['pitch'],
            **pad_details['top'], **pad_shape_details))


        body_edge = {
            'left': -size_x/2,
            'right': size_x/2,
            'top': -size_y/2,
            'bottom': size_y/2
            }

        bounding_box = {
            'left': pad_details['left']['center'][0] - pad_details['left']['size'][0]/2,
            'right': pad_details['right']['center'][0] + pad_details['right']['size'][0]/2,
            'top': pad_details['top']['start'][1] - pad_details['top']['size'][1]/2,
            'bottom': pad_details['bottom']['center'][1] + pad_details['bottom']['size'][1]/2
        }


        pad_width = pad_details['top']['size'][0]
        p1_x = pad_details['first']['start'][0]

        # ############################ SilkS ##################################

        silk_pad_offset = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2
        silk_offset = configuration['silk_fab_offset']

        sx1 = -(device_params['pitch']*(device_params['num_pins_x']-1)/2.0
            + pad_width/2.0 + silk_pad_offset)

        sy1 = -(device_params['pitch']*(device_params['num_pins_y']-1)/2.0
            + pad_width/2.0 + silk_pad_offset)

        poly_silk = [
            {'x': sx1, 'y': body_edge['top']-silk_offset},
            {'x': body_edge['left']-silk_offset, 'y': body_edge['top']-silk_offset},
            {'x': body_edge['left']-silk_offset, 'y': sy1}
        ]
        kicad_mod.append(PolygoneLine(
            polygone=poly_silk,
            width=configuration['silk_line_width'],
            layer="F.SilkS", x_mirror=0))
        kicad_mod.append(PolygoneLine(
            polygone=poly_silk,
            width=configuration['silk_line_width'],
            layer="F.SilkS", y_mirror=0))
        kicad_mod.append(PolygoneLine(
            polygone=poly_silk,
            width=configuration['silk_line_width'],
            layer="F.SilkS", x_mirror=0, y_mirror=0))

        silk_off_45 = silk_offset/sqrt(2)
        poly_silk_tl = [
            {'x': sx1, 'y': body_edge['top']-silk_offset},
            {'x': body_edge['left']+device_params['body_chamfer']-silk_off_45, 'y': body_edge['top']-silk_offset},
            {'x': body_edge['left']-silk_offset, 'y': body_edge['top']+device_params['body_chamfer']-silk_off_45},
            {'x': body_edge['left']-silk_offset, 'y': sy1}
        ]
        kicad_mod.append(PolygoneLine(
            polygone=poly_silk_tl,
            width=configuration['silk_line_width'],
            layer="F.SilkS"))

        # # ######################## Fabrication Layer ###########################

        fab_bevel_size = min(configuration['fab_bevel_size_absolute'], configuration['fab_bevel_size_relative']*min(size_x, size_y))
        fab_bevel_y = fab_bevel_size/sqrt(2)
        poly_fab = [
            {'x': p1_x, 'y': body_edge['top']+fab_bevel_y},
            {'x': p1_x+fab_bevel_size/2, 'y': body_edge['top']},
            {'x': body_edge['right'], 'y': body_edge['top']},
            {'x': body_edge['right'], 'y': body_edge['bottom']},
            {'x': body_edge['left'], 'y': body_edge['bottom']},
            {'x': body_edge['left'], 'y': body_edge['top']+device_params['body_chamfer']},
            {'x': body_edge['left']+device_params['body_chamfer'], 'y': body_edge['top']},
            {'x': p1_x-fab_bevel_size/2, 'y': body_edge['top']},
            {'x': p1_x, 'y': body_edge['top']+fab_bevel_y}
        ]

        kicad_mod.append(PolygoneLine(
            polygone=poly_fab,
            width=configuration['fab_line_width'],
            layer="F.Fab"))

        # # ############################ CrtYd ##################################

        off = ipc_data_set['courtyard']
        grid = configuration['courtyard_grid']
        off_45 = off*math.tan(math.radians(45.0/2))

        cy1=roundToBase(bounding_box['top']-off, grid)
        cy2=roundToBase(body_edge['top']-off, grid)
        cy3=-roundToBase(
            device_params['pitch']*(device_params['num_pins_y']-1)/2.0
            + pad_width/2.0 + off, grid)
        cy4=roundToBase(body_edge['top']+device_params['body_chamfer']-off_45, grid)



        cx1=-roundToBase(
            device_params['pitch']*(device_params['num_pins_x']-1)/2.0
            + pad_width/2.0 + off, grid)
        cx2=roundToBase(body_edge['left']-off, grid)
        cx3=roundToBase(bounding_box['left']-off, grid)
        cx4=roundToBase(body_edge['left']+device_params['body_chamfer']-off_45, grid)


        crty_poly_tl = [
            {'x':0, 'y':cy1},
            {'x':cx1, 'y':cy1},
            {'x':cx1, 'y':cy2},
            {'x':cx2, 'y':cy2},
            {'x':cx2, 'y':cy3},
            {'x':cx3, 'y':cy3},
            {'x':cx3, 'y':0}
        ]

        kicad_mod.append(PolygoneLine(polygone=crty_poly_tl,
            layer='F.CrtYd', width=configuration['courtyard_line_width'],
            x_mirror=0))
        kicad_mod.append(PolygoneLine(polygone=crty_poly_tl,
            layer='F.CrtYd', width=configuration['courtyard_line_width'],
            y_mirror=0))
        kicad_mod.append(PolygoneLine(polygone=crty_poly_tl,
            layer='F.CrtYd', width=configuration['courtyard_line_width'],
            x_mirror=0, y_mirror=0))

        crty_poly_tl_ch = [
            {'x':0, 'y':cy1},
            {'x':cx1, 'y':cy1},
            {'x':cx1, 'y':cy2},
            {'x':cx4, 'y':cy2},
            {'x':cx2, 'y':cy4},
            {'x':cx2, 'y':cy3},
            {'x':cx3, 'y':cy3},
            {'x':cx3, 'y':0}
        ]
        kicad_mod.append(PolygoneLine(polygone=crty_poly_tl_ch,
            layer='F.CrtYd', width=configuration['courtyard_line_width']))

        # ######################### Text Fields ###############################

        addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
            courtyard={'top': cy1, 'bottom': -cy1}, fp_name=fp_name, text_y_inside_position='center')

        ##################### Output and 3d model ############################

        kicad_mod.append(Model(filename=model_name))

        output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
        if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
            os.makedirs(output_dir)
        filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=fp_name)

        file_handler = KicadFileHandler(kicad_mod)
        file_handler.writeFile(filename)
def generate_one_footprint(pins, params, configuration):
    pad_silk_off = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2
    mpn = part_code.format(n=pins*number_of_rows)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)
    footprint_name += params['fp_name_suffix']

    kicad_mod = Footprint(footprint_name)
    desc_format_str = "Molex {:s}, {:s}{:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(desc_format_str.format(series_long, mpn, params['description'], pins, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))



    # Dimensions
    P = (pins - 1) * pitch
    B = pins * pitch + 0.90 # connector length
    W = 21.00 # connector width

    tab_side_w = 1.46

    yt1 = 0 - (B - P) / 2 # left
    yt2 = yt1 - tab_side_w
    yb1 = P + (B - P) / 2 # right
    yb2 = yb1 + tab_side_w
    xr1 = ret_dx + 13.56 # bottom
    xl1 = xr1 - W # top
    xl2 = xl1 - 7.6

    body_edge={
        'left':xl1,
        'right':xr1,
        'bottom':yb1,
        'top': yt1
        }
    bounding_box = {
        'top': -(ret_dy + ret_size/2),
        'bottom': P + (ret_dy + ret_size/2),
        'left': -pad_size[0]/2,
        'right': body_edge['right']
    }

    ##################################  Pins ##################################
    for row_idx in range(2):
        kicad_mod.append(PadArray(pincount=pins, start=[row_idx*offset_second_pad, 0],
            y_spacing=pitch, size=pad_size, drill=drill,
            shape=Pad.SHAPE_RECT, type=Pad.TYPE_THT, layers=Pad.LAYERS_THT,
            tht_pad1_shape=Pad.SHAPE_RECT))

    d_small = 0.3
    s_small = d_small + 2*min_annular_ring
    thermal_to_pad_edge = s_small/2 + 0.15

    if params['thermals']:
        for yi in range(pins):
            n = yi + 1
            pad_center_x = offset_second_pad/2
            pad_center_y = yi*pitch
            pad_l = offset_second_pad + pad_size[0]
            dy = (pad_size[1] - 2*thermal_to_pad_edge)/2
            dx = (pad_l - 2*thermal_to_pad_edge)/4

            #draw rectangle on F.Fab layer

            # kicad_mod.append(RectLine(
            #     start=[pad_center_x - pad_l/2, pad_center_y - pad_size[1]/2],
            #     end=[pad_center_x + pad_l/2, pad_center_y + pad_size[1]/2],
            #     layer='F.Fab', width=configuration['fab_line_width']))

            kicad_mod.append(PadArray(center=[pad_center_x, pad_center_y],
                pincount=3, x_spacing=dx*2,
                drill=d_small, size=s_small, initial=n, increment=0,
                shape=Pad.SHAPE_CIRCLE, type=Pad.TYPE_THT, layers=Pad.LAYERS_THT))
            kicad_mod.append(PadArray(center=[pad_center_x, pad_center_y - dy],
                pincount=5, x_spacing=dx,
                drill=d_small, size=s_small, initial=n, increment=0,
                type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, layers=Pad.LAYERS_THT))
            kicad_mod.append(PadArray(center=[pad_center_x, pad_center_y + dy],
                pincount=5, x_spacing=dx,
                drill=d_small, size=s_small, initial=n, increment=0,
                type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, layers=Pad.LAYERS_THT))

    kicad_mod.append(Pad(at=[ret_dx, -ret_dy], type=Pad.TYPE_THT,
        shape=Pad.SHAPE_CIRCLE, size=ret_size, drill=ret_drill, layers=Pad.LAYERS_THT))
    kicad_mod.append(Pad(at=[ret_dx, P+ret_dy], type=Pad.TYPE_THT,
        shape=Pad.SHAPE_CIRCLE, size=ret_size, drill=ret_drill, layers=Pad.LAYERS_THT))

    kicad_mod.append(RectLine(start=[-pad_size[0]/2, -pad_size[1]/2],
        end=[offset_second_pad + pad_size[0]/2,pad_size[1]/2],offset=pad_silk_off,
        width=configuration['silk_line_width'], layer='B.SilkS'))

    ############################ Outline ##############################
    #kicad_mod.append(RectLine(start=[xl1, yt1], end=[xr1, yb1], layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(RectLine(start=[xl1, yt2], end=[xr1, yb2], layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(Line(start=[xl1, yt1], end=[xr1, yt1], layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(Line(start=[xl1, yb1], end=[xr1, yb1], layer='F.Fab', width=configuration['fab_line_width']))

    off = configuration['silk_fab_offset']
    silk1 = [
        {'y': -pad_size[1]/2 - pad_silk_off, 'x': xl1-off},
        {'y': yt2-off, 'x': xl1-off},
        {'y': yt2-off, 'x': ret_dx-ret_size/2},
    ]
    kicad_mod.append(PolygoneLine(polygone=silk1, layer='F.SilkS', width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=silk1, layer='F.SilkS', width=configuration['silk_line_width'], y_mirror=P/2))
    silk2 = [
        {'y': yt2-off, 'x': ret_dx+ret_size/2},
        {'y': yt2-off, 'x': xr1+off},
        {'y': P/2, 'x': xr1+off},
    ]
    kicad_mod.append(PolygoneLine(polygone=silk2, layer='F.SilkS', width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=silk2, layer='F.SilkS', width=configuration['silk_line_width'], y_mirror=P/2))

    for i in range(pins - 1):
        kicad_mod.append(Line(start=[xl1-off, i*pitch+pad_size[1]/2+pad_silk_off],
            end=[xl1-off, (i+1)*pitch-pad_size[1]/2-pad_silk_off],
            layer='F.SilkS', width=configuration['silk_line_width']))

    for i in range(pins):
        w_pin = 3.8
        kicad_mod.append(RectLine(start=[xl1, i*pitch-w_pin/2], end=[xl2, i*pitch+w_pin/2],
        layer='F.Fab', width=configuration['fab_line_width']))

    ############################ Pin 1 ################################
    # Pin 1 designator
    pin1_sl = 2.4
    pin1 = [
        {'x': body_edge['left'], 'y': -pin1_sl/2},
        {'x': body_edge['left'] - pin1_sl/sqrt(2), 'y': 0},
        {'x': body_edge['left'], 'y': pin1_sl/2}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin1, layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(PolygoneLine(polygone=pin1, layer='F.Fab', width=configuration['fab_line_width'],
        x_mirror=(body_edge['left']+xl2)/2))

    pin1 = [
        {'y': -pad_size[1]/2 - pad_silk_off, 'x': xl1-off},
        {'y': -pad_size[1]/2 - pad_silk_off, 'x': -pad_size[0]/2}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin1, layer='F.SilkS', width=configuration['silk_line_width']))

    # pin1 = [
    #     {'x': 0, 'y': 8},
    #     {'x': 0.5, 'y': 9},
    #     {'x': -0.5, 'y': 9},
    #     {'x': 0, 'y': 8},
    # ]
    # kicad_mod.append(PolygoneLine(polygone=pin1, layer='F.SilkS', width=configuration['silk_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom'] + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins_per_row, variant, configuration):
    peg = variant_params[variant]['mount_pins'] == 'plastic_peg'

    silk_pad_off = configuration['silk_pad_clearance']+configuration['silk_line_width']/2

    mpn = variant_params[variant]['part_code']['mpn'].format(n=pins_per_row*2)
    old_mpn = variant_params[variant]['part_code']['eng_num'].format(n=pins_per_row*2)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=old_mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    descr_format_str = "Molex {:s}, old mpn/engineering number: {:s}, example for new mpn: {:s}, {:d} Pins per row, Mounting: {:s} ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(descr_format_str.format(
        series_long, old_mpn, mpn, pins_per_row,
        variant_params[variant]['descriptive_name'], variant_params[variant]['datasheet']))
    tags = configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation])
    tags += variant_params[variant]['mount_pins']
    kicad_mod.setTags(tags)


    #calculate fp dimensions

    #connector length
    A = pins_per_row * pitch + 1.2

    #pin centers
    B = (pins_per_row - 1) * pitch

    #plasic pin-lock
    C = A + 4

    #connector width
    W = 9.6

    #corner positions
    x1 = -(A-B)/2
    x2 = x1 + A

    y2 = row + 1.85
    y1 = y2 - W

    #tab length
    tab_l = 3.4
    #tab width
    tab_w = 1.4

    body_edge={
        'left':x1,
        'right':x2,
        'bottom':y2,
        'top': y1
        }
    bounding_box = body_edge.copy()
    bounding_box['bottom'] = body_edge['bottom'] + tab_w

    off = configuration['silk_fab_offset']

    #generate the pads
    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    for row_idx in range(2):
        kicad_mod.append(PadArray(
            pincount=pins_per_row, initial=row_idx*pins_per_row+1,
            start=[0, row_idx*row], x_spacing=pitch,
            type=Pad.TYPE_THT, shape=pad_shape,
            size=pad_size, drill=drill, layers=Pad.LAYERS_THT,
            **optional_pad_params))

    #add PCB locators if needed
    pad_silk_offset = configuration['silk_pad_clearance']+configuration['silk_line_width']/2
    if peg:
        loc = 3.00
        mounting_pin_y = row - 0.46
        lx1 = B/2-C/2
        lx2 = B/2+C/2
        kicad_mod.append(Pad(at=[lx1, mounting_pin_y],type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=loc,drill=loc, layers=Pad.LAYERS_NPTH))
        kicad_mod.append(Pad(at=[lx2, mounting_pin_y],type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=loc,drill=loc, layers=Pad.LAYERS_NPTH))

        bounding_box['left'] = lx1-loc/2
        bounding_box['right'] = lx2+loc/2
        ######################## Fab ############################
        mount_pin_radius = loc/2

        kicad_mod.append(Arc(center=[lx1,mounting_pin_y],
            start=[lx1,mounting_pin_y+mount_pin_radius], angle=180,
            layer='F.Fab', width=configuration['fab_line_width']))

        kicad_mod.append(Line(start=[lx1,mounting_pin_y-mount_pin_radius],
            end=[x1,mounting_pin_y-mount_pin_radius],
            layer='F.Fab', width=configuration['fab_line_width']))
        kicad_mod.append(Line(start=[lx1,mounting_pin_y+mount_pin_radius],
            end=[x1,mounting_pin_y+mount_pin_radius],
            layer='F.Fab', width=configuration['fab_line_width']))


        kicad_mod.append(Arc(center=[lx2,mounting_pin_y],
            start=[lx2,mounting_pin_y-mount_pin_radius], angle=180,
            layer='F.Fab', width=configuration['fab_line_width']))

        kicad_mod.append(Line(start=[lx2,mounting_pin_y-mount_pin_radius],
            end=[x2,mounting_pin_y-mount_pin_radius],
            layer='F.Fab', width=configuration['fab_line_width']))
        kicad_mod.append(Line(start=[lx2,mounting_pin_y+mount_pin_radius],
            end=[x2,mounting_pin_y+mount_pin_radius],
            layer='F.Fab', width=configuration['fab_line_width']))

        ######################## Silk ############################
        mount_pin_radius = loc/2 + silk_pad_off
        kicad_mod.append(Arc(center=[lx1,mounting_pin_y],
            start=[lx1,mounting_pin_y+mount_pin_radius], angle=180,
            layer='F.SilkS', width=configuration['silk_line_width']))

        kicad_mod.append(Line(start=[lx1,mounting_pin_y-mount_pin_radius],
            end=[x1-off,mounting_pin_y-mount_pin_radius],
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(Line(start=[lx1,mounting_pin_y+mount_pin_radius],
            end=[x1-off,mounting_pin_y+mount_pin_radius],
            layer='F.SilkS', width=configuration['silk_line_width']))


        kicad_mod.append(Arc(center=[lx2,mounting_pin_y],
            start=[lx2,mounting_pin_y-mount_pin_radius], angle=180,
            layer='F.SilkS', width=configuration['silk_line_width']))

        kicad_mod.append(Line(start=[lx2,mounting_pin_y-mount_pin_radius],
            end=[x2+off,mounting_pin_y-mount_pin_radius],
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(Line(start=[lx2,mounting_pin_y+mount_pin_radius],
            end=[x2+off,mounting_pin_y+mount_pin_radius],
            layer='F.SilkS', width=configuration['silk_line_width']))

    #draw the outline of the shape
    kicad_mod.append(RectLine(start=[x1,y1],end=[x2,y2],layer='F.Fab',width=configuration['fab_line_width']))

    #draw the outline of the tab
    kicad_mod.append(PolygoneLine(polygone=[
        {'x': B/2 - tab_l/2,'y': y2},
        {'x': B/2 - tab_l/2,'y': y2 + tab_w},
        {'x': B/2 + tab_l/2,'y': y2 + tab_w},
        {'x': B/2 + tab_l/2,'y': y2},
    ], layer='F.Fab', width=configuration['fab_line_width']))

    #draw the outline of each pin slot (alternating shapes)
    #slot size
    S = 3.3

    def square_slot(x,y):
        kicad_mod.append(RectLine(start=[x-S/2,y-S/2], end=[x+S/2,y+S/2],
            layer='F.Fab', width=configuration['fab_line_width']))

    def notch_slot(x,y):
        kicad_mod.append(PolygoneLine(polygone=[
        {'x': x-S/2, 'y': y+S/2},
        {'x': x-S/2, 'y': y-S/4},
        {'x': x-S/4, 'y': y-S/2},
        {'x': x+S/4, 'y': y-S/2},
        {'x': x+S/2, 'y': y-S/4},
        {'x': x+S/2, 'y': y+S/2},
        {'x': x-S/2, 'y': y+S/2},
        ], layer='F.Fab', width=configuration['fab_line_width']))

    q = 1
    notch = True
    for i in range(pins_per_row):
        if notch:
            y_square = row/2 - 4.2/2
            y_notch = row/2 + 4.2/2
        else:
            y_square = row/2 + 4.2/2
            y_notch = row/2 - 4.2/2

        square_slot(i * pitch, y_square)
        notch_slot(i*pitch, y_notch)

        q -= 1

        if (q == 0):
            q = 2
            notch = not notch


    #draw the outline of the connector on the silkscreen
    outline = [
    {'x': B/2,'y': y1-off},
    {'x': x1-off,'y': y1-off},
    {'x': x1-off,'y': y2+off},
    {'x': B/2 - tab_l/2 - off,'y': y2+off},
    {'x': B/2 - tab_l/2 - off,'y': y2 + off + tab_w},
    {'x': B/2, 'y': y2 + off + tab_w},
    ]

    kicad_mod.append(PolygoneLine(polygone=outline, layer="F.SilkS", width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=outline, x_mirror=B/2, layer="F.SilkS", width=configuration['silk_line_width']))

    #pin-1 marker

    L = 2.5
    O = 0.35

    pin = [
        {'x': x1 + L,'y': y1 - O},
        {'x': x1 - O,'y': y1 - O},
        {'x': x1 - O,'y': y1 + L},
    ]

    kicad_mod.append(PolygoneLine(polygone=pin, layer="F.SilkS", width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=pin, width=configuration['fab_line_width'], layer='F.Fab'))

    ########################### CrtYd #################################
    CrtYd_offset = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']

    cx1 = roundToBase(bounding_box['left'] - CrtYd_offset, CrtYd_grid)
    cy1 = roundToBase(bounding_box['top'] - CrtYd_offset, CrtYd_grid)

    cx2 = roundToBase(bounding_box['right'] + CrtYd_offset, CrtYd_grid)
    cy2 = roundToBase(bounding_box['bottom'] + CrtYd_offset, CrtYd_grid)


    if peg:
        cx3 = roundToBase(body_edge['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
        cx4 = roundToBase(body_edge['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
        mount_pin_radius = loc/2
        cy3=roundToBase(mounting_pin_y - mount_pin_radius - configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

        poly_crtyd = [
            {'x': cx3, 'y': cy1},
            {'x': cx3, 'y': cy3},
            {'x': cx1, 'y': cy3},
            {'x': cx1, 'y': cy2},
            {'x': cx2, 'y': cy2},
            {'x': cx2, 'y': cy3},
            {'x': cx4, 'y': cy3},
            {'x': cx4, 'y': cy1},
            {'x': cx3, 'y': cy1}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_crtyd,
            layer='F.CrtYd', width=configuration['courtyard_line_width']))
    else:
        kicad_mod.append(RectLine(
            start=[cx1, cy1], end=[cx2, cy2],
            layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #8
0
def generate_one_footprint(pins, configuration):
    mpn = part_code.format(n=pins * 2)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins,
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "Molex {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
        .format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    A = (pins - 1) * pitch
    B = A + 1.8
    C = A + 3

    #connector width
    W = 3.2

    #side thickness
    T = 0.4

    #corner positions
    x1 = (A - C) / 2
    x2 = x1 + C

    y2 = 1.15
    y1 = y2 - W

    off = configuration['silk_fab_offset']
    pad_silk_off = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2

    body_edge = {'left': x1, 'right': x2, 'bottom': y2, 'top': y1}
    bounding_box = body_edge.copy()

    # generate the pads
    kicad_mod.append(
        PadArray(start=[0, 0],
                 pincount=pins,
                 x_spacing=pitch,
                 type=Pad.TYPE_THT,
                 shape=pad_shape,
                 size=pad_size,
                 drill=drill,
                 layers=Pad.LAYERS_THT))

    # outline on Fab
    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    # outline on SilkScreen
    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 offset=off,
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))

    inline = [
        {
            'x': A / 2,
            'y': y2 - T
        },
        {
            'x': x1 + T,
            'y': y2 - T
        },
        {
            'x': x1 + T,
            'y': 0
        },
        {
            'x': x1 + T / 2,
            'y': 0
        },
        {
            'x': x1 + T / 2,
            'y': -2 * T
        },
        {
            'x': x1 + T,
            'y': -2 * T
        },
        {
            'x': x1 + T,
            'y': y1 + T
        },
        {
            'x': A / 2,
            'y': y1 + T
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=inline,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=inline,
                     x_mirror=A / 2,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    #pin-1 mark

    L = 1
    kicad_mod.append(
        Line(start=[x1 - 0.4, y2 + 0.4],
             end=[x1 - 0.4, y2 + 0.4 - L],
             layer='F.SilkS',
             width=configuration['silk_line_width']))
    kicad_mod.append(
        Line(start=[x1 - 0.4, y2 + 0.4],
             end=[x1 - 0.4 + L, y2 + 0.4],
             layer='F.SilkS',
             width=configuration['silk_line_width']))

    sl = 1
    pin = [{
        'y': body_edge['bottom'],
        'x': -sl / 2
    }, {
        'y': body_edge['bottom'] - sl / sqrt(2),
        'x': 0
    }, {
        'y': body_edge['bottom'],
        'x': sl / 2
    }]
    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     width=configuration['fab_line_width'],
                     layer='F.Fab'))

    ########################### CrtYd #################################
    cx1 = roundToBase(
        bounding_box['left'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = roundToBase(
        bounding_box['top'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cx2 = roundToBase(
        bounding_box['right'] + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        bounding_box['bottom'] +
        configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pincount, configuration):

    mpn = eng_mpn.format(n=pincount)
    new_mpn = new_mpn_example.format(n=pincount)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pincount,
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    descr_format_str = "Molex {:s}, old/engineering part number: {:s} example for new part number: {:s}, {:d} Pins ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(
        descr_format_str.format(series_long, mpn, new_mpn, pincount,
                                datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    # calculate working values
    end_pos_x = (pincount - 1) * pitch
    centre_x = (end_pos_x - start_pos_x) / 2.0
    nudge = configuration['silk_fab_offset']
    silk_w = configuration['silk_line_width']
    fab_w = configuration['fab_line_width']

    body_edge = {
        'left': start_pos_x - pitch / 2,
        'right': end_pos_x + pitch / 2,
        'bottom': 1.88 + 1
    }
    body_edge['top'] = body_edge['bottom'] - 5.8

    # create pads
    # kicad_mod.append(Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    #                     at=[0, 0], size=pad_size,
    #                     drill=drill, layers=Pad.LAYERS_THT))

    kicad_mod.append(
        PadArray(initial=1,
                 start=[start_pos_x, 0],
                 x_spacing=pitch,
                 pincount=pincount,
                 size=pad_size,
                 drill=drill,
                 type=Pad.TYPE_THT,
                 shape=Pad.SHAPE_OVAL,
                 layers=Pad.LAYERS_THT))

    # create fab outline
    kicad_mod.append(RectLine(start=[body_edge['left'], body_edge['top']],\
        end=[body_edge['right'], body_edge['bottom']], layer='F.Fab', width=fab_w))

    # create silkscreen
    kicad_mod.append(RectLine(start=[body_edge['left']-nudge, body_edge['top']-nudge],\
        end=[body_edge['right']+nudge, body_edge['bottom']+nudge], layer='F.SilkS', width=silk_w))

    # pin 1 markers
    kicad_mod.append(Line(start=[body_edge['left']-0.4, -2.0],\
        end=[body_edge['left']-0.4, 2.0], layer='F.SilkS', width=silk_w))

    sl = 1
    poly_pin1_marker = [{
        'x': body_edge['left'],
        'y': -sl / 2
    }, {
        'x': body_edge['left'] + sl / sqrt(2),
        'y': 0
    }, {
        'x': body_edge['left'],
        'y': sl / 2
    }]
    kicad_mod.append(
        PolygoneLine(polygone=poly_pin1_marker, layer='F.Fab', width=fab_w))

    yr1 = body_edge['bottom'] + nudge
    yr2 = yr1 - 1
    yr3 = yr2 - 0.53
    if pincount <= 6:
        # one ramp
        kicad_mod.append(PolygoneLine(polygone=[[start_pos_x, yr1], [start_pos_x, yr2],\
            [end_pos_x, yr2], [end_pos_x, yr1]], layer='F.SilkS', width=silk_w))
        kicad_mod.append(PolygoneLine(polygone=[[start_pos_x, yr2], [start_pos_x+0.25, yr3],\
            [end_pos_x-0.25, yr3], [end_pos_x, yr2] ],layer='F.SilkS', width=silk_w))
        kicad_mod.append(PolygoneLine(polygone=[[start_pos_x+0.25, yr1],\
            [start_pos_x+0.25, yr2]], layer='F.SilkS', width=silk_w))
        kicad_mod.append(PolygoneLine(polygone=[[end_pos_x-0.25, yr1],\
            [end_pos_x-0.25, yr2]], layer='F.SilkS', width=silk_w))

    else:
        # two ramps
        poly1 = [{
            'x': start_pos_x,
            'y': yr1
        }, {
            'x': start_pos_x,
            'y': yr2
        }, {
            'x': start_pos_x + 2 * pitch,
            'y': yr2
        }, {
            'x': start_pos_x + 2 * pitch,
            'y': yr1
        }]
        poly2 = [{
            'x': start_pos_x,
            'y': yr2
        }, {
            'x': start_pos_x + 0.25,
            'y': yr3
        }, {
            'x': start_pos_x + 2 * pitch,
            'y': yr3
        }, {
            'x': start_pos_x + 2 * pitch,
            'y': yr2
        }]
        poly3 = [{
            'x': start_pos_x + 0.25,
            'y': yr1
        }, {
            'x': start_pos_x + 0.25,
            'y': yr2
        }]

        kicad_mod.append(
            PolygoneLine(polygone=poly1, layer='F.SilkS', width=silk_w))
        kicad_mod.append(
            PolygoneLine(polygone=poly2, layer='F.SilkS', width=silk_w))
        kicad_mod.append(
            PolygoneLine(polygone=poly3, layer='F.SilkS', width=silk_w))

        kicad_mod.append(
            PolygoneLine(polygone=poly1,
                         x_mirror=centre_x,
                         layer='F.SilkS',
                         width=silk_w))
        kicad_mod.append(
            PolygoneLine(polygone=poly2,
                         x_mirror=centre_x,
                         layer='F.SilkS',
                         width=silk_w))
        kicad_mod.append(
            PolygoneLine(polygone=poly3,
                         x_mirror=centre_x,
                         layer='F.SilkS',
                         width=silk_w))

    for i in range(0, pincount):
        middle_x = start_pos_x + i * pitch
        start_x = middle_x - 1.6 / 2
        end_x = middle_x + 1.6 / 2
        y1 = body_edge['top'] - nudge
        y2 = y1 + 0.6
        kicad_mod.append(PolygoneLine(polygone=[[start_x, y1], [start_x, y2],\
            [end_x, y2], [end_x, y1]], layer='F.SilkS', width=silk_w))

    ########################### CrtYd #################################
    cx1 = roundToBase(
        body_edge['left'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = roundToBase(
        body_edge['top'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cx2 = roundToBase(
        body_edge['right'] + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        body_edge['bottom'] + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    #calculate fp dimensions
    A = (pins - 1) * pitch
    B = A + 5.2

    #generate the name
    mpn = part_base.format(n=number_of_rows * pins)
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator"
        .format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    pad_size = [pitch - pad_to_pad_clearance, row_pitch - pad_to_pad_clearance]
    if pad_size[0] - drill < 2 * min_annular_ring:
        pad_size[0] = drill + 2 * min_annular_ring

    if pad_size[1] - drill > 2 * pad_copper_y_solder_length:
        pad_size[1] = drill + 2 * pad_copper_y_solder_length
    if pad_size[1] - drill < 2 * min_annular_ring:
        pad_size[1] = drill + 2 * min_annular_ring

    if pad_size[0] == pad_size[1]:
        pad_shape = Pad.SHAPE_CIRCLE
    else:
        pad_shape = Pad.SHAPE_OVAL

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    for row_idx in range(2):
        kicad_mod.append(
            PadArray(initial=ROW_NAMES[row_idx] + '1',
                     start=[0, -(row_idx) * row_pitch],
                     x_spacing=pitch,
                     pincount=pins,
                     increment=incrementPadNumber,
                     size=pad_size,
                     drill=drill,
                     type=Pad.TYPE_THT,
                     shape=pad_shape,
                     layers=Pad.LAYERS_THT,
                     tht_pad1_id=ROW_NAMES[0] + '1',
                     **optional_pad_params))

    #draw the component outline
    x1 = A / 2 - B / 2
    x2 = x1 + B
    y1 = -2.5 - 0.62
    y2 = y1 + 17.8
    body_edge = {'left': x1, 'right': x2, 'top': y1, 'bottom': y2}

    #draw the main outline around the footprint
    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(x1 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    if y1 < -row_pitch - pad_size[1] / 2:
        cy1 = roundToBase(y1 - configuration['courtyard_offset']['connector'],
                          configuration['courtyard_grid'])
    else:
        cy1 = roundToBase(
            -row_pitch - pad_size[1] / 2 -
            configuration['courtyard_offset']['connector'],
            configuration['courtyard_grid'])

    cx2 = roundToBase(x2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy2 = roundToBase(y2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    #offset off
    off = configuration['silk_fab_offset']

    x1 -= off
    y1 -= off
    x2 += off
    y2 += off

    #outline
    side = [
        {
            'x': -1,
            'y': y1
        },
        {
            'x': x1,
            'y': y1
        },
        {
            'x': x1,
            'y': y2
        },
        {
            'x': A / 2,
            'y': y2
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=side,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=side,
                     x_mirror=A / 2,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))

    #add mounting holes
    if pins == 3:
        m = Pad(at=[pitch, 7],
                layers=["*.Cu", "*.Mask"],
                shape=Pad.SHAPE_CIRCLE,
                type=Pad.TYPE_THT,
                size=mh_size,
                drill=mh_drill)
        kicad_mod.append(m)
    else:
        m1 = Pad(at=[0, 7],
                 layers=["*.Cu", '*.Mask'],
                 shape=Pad.SHAPE_CIRCLE,
                 type=Pad.TYPE_THT,
                 size=mh_size,
                 drill=mh_drill)
        m2 = Pad(at=[A, 7],
                 layers=["*.Cu", '*.Mask'],
                 shape=Pad.SHAPE_CIRCLE,
                 type=Pad.TYPE_THT,
                 size=mh_size,
                 drill=mh_drill)

        kicad_mod.append(m1)
        kicad_mod.append(m2)

    #add p1 marker
    px = -3
    m = 0.3

    marker = [
        {
            'x': px,
            'y': 0
        },
        {
            'x': px - 2 * m,
            'y': m
        },
        {
            'x': px - 2 * m,
            'y': -m
        },
        {
            'x': px,
            'y': 0
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=marker,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))

    sl = 1
    marker = [{
        'x': body_edge['left'],
        'y': sl / 2
    }, {
        'x': body_edge['left'] + sl / sqrt(2),
        'y': 0
    }, {
        'x': body_edge['left'],
        'y': -sl / 2
    }]
    kicad_mod.append(
        PolygoneLine(polygone=marker,
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='center')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    mpn = part_code.format(n=pins)
    pad_silk_off = configuration['silk_line_width'] / 2 + configuration[
        'silk_pad_clearance']
    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)

    footprint_name = footprint_name.replace("__", '_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "Molex {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
        .format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    A = (pins - 1) * pitch
    B = A + 2.9

    # create pads
    #createNumberedPadsTHT(kicad_mod, pincount, pitch, drill, {'x':x_dia, 'y':y_dia})

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(
        PadArray(start=[0, 0],
                 pincount=pins,
                 x_spacing=pitch,
                 type=Pad.TYPE_THT,
                 shape=pad_shape,
                 size=pad_size,
                 drill=drill,
                 layers=Pad.LAYERS_THT,
                 **optional_pad_params))

    x1 = -(B - A) / 2
    y1 = -2.2
    x2 = x1 + B
    y2 = 1.2

    body_edge = {'left': x1, 'right': x2, 'bottom': y2, 'top': y1}
    bounding_box = body_edge.copy()

    kicad_mod.append(
        RectLine(start={
            'x': x1,
            'y': y1
        },
                 end={
                     'x': x2,
                     'y': y2
                 },
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    #line offset
    off = 0.1

    x1 -= off
    y1 -= off

    x2 += off
    y2 += off

    #draw the main outline around the footprint
    kicad_mod.append(
        RectLine(start={
            'x': x1,
            'y': y1
        },
                 end={
                     'x': x2,
                     'y': y2
                 },
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))

    #add pin-1 marker
    p1_off = configuration['silk_fab_offset'] + 0.3
    L = 1.5
    pin = [{
        'y': body_edge['bottom'] - L,
        'x': body_edge['left'] - p1_off
    }, {
        'y': body_edge['bottom'] + p1_off,
        'x': body_edge['left'] - p1_off
    }, {
        'y': body_edge['bottom'] + p1_off,
        'x': body_edge['left'] + L
    }]
    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    sl = 1
    pin = [{
        'y': body_edge['bottom'],
        'x': -sl / 2
    }, {
        'y': body_edge['bottom'] - sl / sqrt(2),
        'x': 0
    }, {
        'y': body_edge['bottom'],
        'x': sl / 2
    }]
    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     width=configuration['fab_line_width'],
                     layer='F.Fab'))

    #side-wall thickness S

    S = 0.3

    #bottom line
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x1,
            'y': 0
        }, {
            'x': x1 + S,
            'y': 0
        }, {
            'x': x1 + S,
            'y': y2 - S
        }, {
            'x': x2 - S,
            'y': y2 - S
        }, {
            'x': x2 - S,
            'y': 0
        }, {
            'x': x2,
            'y': 0
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    #left mark

    #gap g
    g = 0.75

    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x1,
            'y': -g
        }, {
            'x': x1 + S,
            'y': -g
        }, {
            'x': x1 + S,
            'y': y1 + S * 1.5
        }, {
            'x': x1 + 2 * S,
            'y': y1 + S * 1.5
        }, {
            'x': x1 + 2 * S,
            'y': y1
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x2,
            'y': -g
        }, {
            'x': x2 - S,
            'y': -g
        }, {
            'x': x2 - S,
            'y': y1 + S * 1.5
        }, {
            'x': x2 - 2 * S,
            'y': y1 + S * 1.5
        }, {
            'x': x2 - 2 * S,
            'y': y1
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    #middle line
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x1 + 2 * S,
            'y': y1 + 1.5 * S
        }, {
            'x': 0.2 * pitch,
            'y': y1 + 1.5 * S
        }, {
            'x': 0.2 * pitch,
            'y': y1 + 0.5 * S
        }, {
            'x': 0.8 * pitch,
            'y': y1 + 0.5 * S
        }, {
            'x': 0.8 * pitch,
            'y': y1 + 1.5 * S
        }, {
            'x': A - 0.8 * pitch,
            'y': y1 + 1.5 * S
        }, {
            'x': A - 0.8 * pitch,
            'y': y1 + 0.5 * S
        }, {
            'x': A - 0.2 * pitch,
            'y': y1 + 0.5 * S
        }, {
            'x': A - 0.2 * pitch,
            'y': y1 + 1.5 * S
        }, {
            'x': x2 - 2 * S,
            'y': y1 + 1.5 * S
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(
        bounding_box['left'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = roundToBase(
        bounding_box['top'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cx2 = roundToBase(
        bounding_box['right'] + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        bounding_box['bottom'] +
        configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins_per_row, configuration):
    mpn = part_code.format(n=pins_per_row * number_of_rows)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins_per_row,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "Molex {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
        .format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    A = (pins_per_row - 1) * pitch
    B = A + 2 * 1.75
    C = A + 2 * 2.45

    #connector width
    W = 4.9
    chamfer_pin_n = {'x': 1, 'y': 1}

    off = configuration['silk_fab_offset']
    pad_silk_off = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2

    body_edge = {}
    body_edge['left'] = (A - C) / 2
    body_edge['right'] = body_edge['left'] + C
    body_edge['top'] = -3.1
    body_edge['bottom'] = body_edge['top'] + W

    bounding_box = body_edge.copy()

    # generate the pads
    kicad_mod.append(
        PadArray(start=[0, 0],
                 pincount=pins_per_row,
                 x_spacing=pitch,
                 type=Pad.TYPE_THT,
                 shape=pad_shape,
                 size=pad_size,
                 drill=drill,
                 layers=Pad.LAYERS_THT))

    def generateOutline(off=0, grid=0):
        poly = [
            {
                'x': body_edge['left'] - off,
                'y': body_edge['top'] - off
            },
            {
                'x': body_edge['left'] - off,
                'y': body_edge['bottom'] + off
            },
            {
                'x': body_edge['right'] - chamfer_pin_n['x'] + off,
                'y': body_edge['bottom'] + off
            },
            {
                'x': body_edge['right'] + off,
                'y': body_edge['bottom'] - chamfer_pin_n['y'] + off
            },
            {
                'x': body_edge['right'] + off,
                'y': body_edge['top'] - off
            },
            {
                'x': body_edge['left'] - off,
                'y': body_edge['top'] - off
            },
        ]
        if grid == 0:
            return poly
        else:
            return [{
                'x': roundToBase(p['x'], grid),
                'y': roundToBase(p['y'], grid)
            } for p in poly]

    # outline on Fab
    kicad_mod.append(
        PolygoneLine(polygone=generateOutline(),
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    # outline on SilkScreen
    kicad_mod.append(
        PolygoneLine(polygone=generateOutline(off=off),
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    #pin-1 mark
    sl = 2
    o = off + 0.3
    pin = [{
        'y': body_edge['bottom'] - sl,
        'x': body_edge['left'] - o
    }, {
        'y': body_edge['bottom'] + o,
        'x': body_edge['left'] - o
    }, {
        'y': body_edge['bottom'] + o,
        'x': body_edge['left'] + sl
    }]
    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    sl = 1
    pin = [{
        'y': body_edge['bottom'],
        'x': -sl / 2
    }, {
        'y': body_edge['bottom'] - sl / sqrt(2),
        'x': 0
    }, {
        'y': body_edge['bottom'],
        'x': sl / 2
    }]
    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     width=configuration['fab_line_width'],
                     layer='F.Fab'))

    ########################### CrtYd #################################
    poly_crtyd = generateOutline(
        configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = poly_crtyd[0]['y']
    cy2 = poly_crtyd[1]['y']
    kicad_mod.append(
        PolygoneLine(polygone=poly_crtyd,
                     layer='F.CrtYd',
                     width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def make_module(pins_per_row, configuration):
    pad_silk_off = configuration['silk_line_width'] / 2 + configuration[
        'silk_pad_clearance']
    off = configuration['silk_fab_offset']

    mpn = part_code.format(pins_per_row * 2)

    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins_per_row,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)

    footprint_name = footprint_name.replace("__", '_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "Molex {:s}, {:s}, {:d} Circuits ({:s}), generated with kicad-footprint-generator"
        .format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    W = 5.3
    Wi = 4.2

    body_edge = {}
    body_edge['left'] = -(W - pitch_row) / 2
    body_edge['right'] = body_edge['left'] + W

    A = (pins_per_row - 1) * pitch
    B = (A - 8) if A >= 8 else 0
    C = (A - 4.6) if A >= 4.6 else 0
    D = A + 2.6
    E = A + 3.6

    body_edge['top'] = -(E - A) / 2
    body_edge['bottom'] = body_edge['top'] + E

    bounding_box = body_edge.copy()

    ############################## Pins ###############################
    for i in range(pins_per_row):
        y = i * pitch
        kicad_mod.append(
            Pad(at=[0, y],
                number='a{:d}'.format(i + 1),
                type=Pad.TYPE_THT,
                shape=Pad.SHAPE_CIRCLE,
                size=pad_size,
                drill=drill,
                layers=Pad.LAYERS_THT))
        kicad_mod.append(
            Pad(at=[pitch_row, y],
                number='b{:d}'.format(i + 1),
                type=Pad.TYPE_THT,
                shape=Pad.SHAPE_CIRCLE,
                size=pad_size,
                drill=drill,
                layers=Pad.LAYERS_THT))

    ############################ Outline ##############################
    kicad_mod.append(
        RectLine(start=[body_edge['left'], body_edge['top']],
                 end=[body_edge['right'], body_edge['bottom']],
                 layer="F.Fab",
                 width=configuration['fab_line_width']))

    kicad_mod.append(
        RectLine(start=[body_edge['left'], body_edge['top']],
                 end=[body_edge['right'], body_edge['bottom']],
                 layer="F.SilkS",
                 width=configuration['silk_line_width'],
                 offset=off))

    # inside
    CW = 1
    xil = body_edge['left'] + (W - Wi) / 2
    xir = xil + Wi
    yit = body_edge['top'] + (E - D) / 2
    yt1 = A / 2 - C / 2
    yb1 = A / 2 + C / 2
    yt2 = A / 2 - B / 2

    poly_left_t = [
        {
            'x': pitch_row - CW / 2,
            'y': body_edge['top'] - off
        },
        {
            'x': pitch_row - CW / 2,
            'y': yit
        },
        {
            'x': xil,
            'y': yit
        },
        {
            'x': xil,
            'y': yt1
        },
        {
            'x': body_edge['left'] - off,
            'y': yt1
        },
    ]
    if C == 0:
        del poly_left_t[-1]

    kicad_mod.append(
        PolygoneLine(polygone=poly_left_t,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=poly_left_t,
                     y_mirror=A / 2,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))

    poly_right_t = [
        {
            'x': pitch_row + CW / 2,
            'y': body_edge['top'] - off
        },
        {
            'x': pitch_row + CW / 2,
            'y': yit
        },
        {
            'x': xir,
            'y': yit
        },
        {
            'x': xir,
            'y': yt2
        },
        {
            'x': body_edge['right'] + off,
            'y': yt2
        },
    ]
    if B == 0:
        del poly_right_t[-1]
    else:
        kicad_mod.append(
            Line(start={
                'x': body_edge['right'] + off,
                'y': yt1
            },
                 end={
                     'x': xir,
                     'y': yt1
                 },
                 layer="F.SilkS",
                 width=configuration['silk_line_width']))
        kicad_mod.append(
            Line(start={
                'x': body_edge['right'] + off,
                'y': yb1
            },
                 end={
                     'x': xir,
                     'y': yb1
                 },
                 layer="F.SilkS",
                 width=configuration['silk_line_width']))

    kicad_mod.append(
        PolygoneLine(polygone=poly_right_t,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=poly_right_t,
                     y_mirror=A / 2,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))

    ########################### Pin 1 #################################

    p1s_sl = 2
    p1s_off = off + 0.3
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': body_edge['left'] + p1s_sl,
            'y': body_edge['top'] - p1s_off
        }, {
            'x': body_edge['left'] - p1s_off,
            'y': body_edge['top'] - p1s_off
        }, {
            'x': body_edge['left'] - p1s_off,
            'y': body_edge['top'] + p1s_sl
        }],
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))

    p1f_sl = 1
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': body_edge['left'],
            'y': p1f_sl / 2
        }, {
            'x': body_edge['left'] + p1f_sl / sqrt(2),
            'y': 0
        }, {
            'x': body_edge['left'],
            'y': -p1f_sl / 2
        }],
                     layer="F.Fab",
                     width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(
        bounding_box['left'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = roundToBase(
        bounding_box['top'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cx2 = roundToBase(
        bounding_box['right'] + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        bounding_box['bottom'] +
        configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='right')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)

    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins_per_row, params, configuration):
    mpn = part_code.format(n=pins_per_row, shield=params['mpn_option'])

    CrtYd_off = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']
    off = configuration['silk_fab_offset']
    pad_silk_off = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2
    body_edge = {}
    bounding_box = {}

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    if params['shield_pad']:
        footprint_name = configuration['fp_name_format_string_shielded'].format(man=manufacturer,
            series=series,
            mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row,
            pitch=pitch, orientation=orientation_str, shield_pins=1)
    else:
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    footprint_name = footprint_name.replace('__','_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setAttribute('smd')
    kicad_mod.setDescription("Molex {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    A = (pins_per_row-1)*pitch
    B = A + 2.5
    C = A + 5.45
    D = A + 6.75
    E = A + 5.2

    pad_to_pad_inside = 1.95+0.25
    pad_y = (pad_to_pad_inside + pad_size[1])/2

    boss_x = B/2
    boss_y = -pad_y + pad_size[1]/2 + 0.25

    shield_pad_x = C/2
    shield_pad_y = boss_y + 2

    body_chamfer = 0.3


    body_edge['left'] = -D/2 if params['shield_pad'] else -E/2
    body_edge['right'] = -body_edge['left']
    body_edge['top'] = -4.98/2
    body_edge['bottom'] = -body_edge['top']

    bounding_box['left'] = (-shield_pad_x - shield_pad_size/2) if params['shield_pad'] else body_edge['left']
    bounding_box['right'] = -bounding_box['left']
    bounding_box['top'] = -pad_y - pad_size[1]/2
    bounding_box['bottom'] = -bounding_box['top']


    ################################ Pads #####################################

    kicad_mod.append(PadArray(initial=1, increment=2,
        center=[0, -pad_y], x_spacing=pitch, pincount=pins_per_row,
        size=pad_size, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT))
    kicad_mod.append(PadArray(initial=2, increment=2,
        center=[0, pad_y], x_spacing=pitch, pincount=pins_per_row,
        size=pad_size, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT))

    kicad_mod.append(Pad(number ='""', type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
                        at=[boss_x, boss_y],
                        size=boss_drill, drill=boss_drill,
                        layers=Pad.LAYERS_NPTH))
    kicad_mod.append(Pad(number ='""', type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
                        at=[-boss_x, boss_y],
                        size=boss_drill, drill=boss_drill,
                        layers=Pad.LAYERS_NPTH))

    if params['shield_pad']:
        kicad_mod.append(Pad(number = pin_number_shield,
                            type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE,
                            at=[shield_pad_x, shield_pad_y],
                            size=shield_pad_size, drill=shield_pad_drill,
                            layers=Pad.LAYERS_THT))
        kicad_mod.append(Pad(number = pin_number_shield,
                            type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE,
                            at=[-shield_pad_x, shield_pad_y],
                            size=shield_pad_size, drill=shield_pad_drill,
                            layers=Pad.LAYERS_THT))

    ########################### Outline ################################
    poly_fab = [
        {'x': 0, 'y': body_edge['top']},
        {'x': body_edge['left']+body_chamfer, 'y': body_edge['top']},
        {'x': body_edge['left'], 'y': body_edge['top']+body_chamfer},
        {'x': body_edge['left'], 'y': body_edge['bottom']-body_chamfer},
        {'x': body_edge['left']+body_chamfer, 'y': body_edge['bottom']},
        {'x': 0, 'y': body_edge['bottom']}
    ]
    kicad_mod.append(PolygoneLine(polygone=poly_fab,
        layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(PolygoneLine(polygone=poly_fab, x_mirror=0,
        layer='F.Fab', width=configuration['fab_line_width']))

    pad_x_outside_edge = A/2 + pad_size[0]/2 + pad_silk_off
    if not params['shield_pad']:
        poly_silk = [
            {'x': -pad_x_outside_edge, 'y': body_edge['top']-off},
            {'x': body_edge['left']+body_chamfer-off, 'y': body_edge['top']-off},
            {'x': body_edge['left']-off, 'y': body_edge['top']+body_chamfer-off},
            {'x': body_edge['left']-off, 'y': body_edge['bottom']-body_chamfer+off},
            {'x': body_edge['left']+body_chamfer-off, 'y': body_edge['bottom']+off},
            {'x': -pad_x_outside_edge, 'y': body_edge['bottom']+off}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_silk,
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly_silk, x_mirror=0,
            layer='F.SilkS', width=configuration['silk_line_width']))

    else:
        r = (shield_pad_size/2 + pad_silk_off)
        x = (D-C)/2
        dy = sqrt(r**2 - x**2)
        poly_silk_top = [
            {'x': -pad_x_outside_edge, 'y': body_edge['top']-off},
            {'x': body_edge['left']+body_chamfer-off, 'y': body_edge['top']-off},
            {'x': body_edge['left']-off, 'y': body_edge['top']+body_chamfer-off},
            {'x': body_edge['left']-off, 'y': shield_pad_y-dy},
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_silk_top,
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly_silk_top, x_mirror=0,
            layer='F.SilkS', width=configuration['silk_line_width']))

        poly_silk_bottom = [
            {'x': body_edge['left']-off, 'y': shield_pad_y+dy},
            {'x': body_edge['left']-off, 'y': body_edge['bottom']-body_chamfer+off},
            {'x': body_edge['left']+body_chamfer-off, 'y': body_edge['bottom']+off},
            {'x': -pad_x_outside_edge, 'y': body_edge['bottom']+off}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_silk_bottom,
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly_silk_bottom, x_mirror=0,
            layer='F.SilkS', width=configuration['silk_line_width']))

    ########################### Pin 1 #################################
    p1s_sl = 0.4
    p1s_y = -pad_y - pad_size[1]/2 - pad_silk_off
    p1_x = -A/2
    p1s_poly = [
        {'x': p1_x, 'y':p1s_y},
        {'x': p1_x-p1s_sl/2, 'y':p1s_y-p1s_sl/sqrt(2)},
        {'x': p1_x+p1s_sl/2, 'y':p1s_y-p1s_sl/sqrt(2)},
        {'x': p1_x, 'y':p1s_y}
    ]
    kicad_mod.append(PolygoneLine(polygone=p1s_poly,
        layer='F.SilkS', width=configuration['silk_line_width']))

    p1f_sl = 2*pitch
    p1f_poly = [
        {'x': p1_x-p1f_sl/2, 'y':body_edge['top']},
        {'x': p1_x, 'y':body_edge['top']+p1f_sl/sqrt(2)},
        {'x': p1_x+p1f_sl/2, 'y':body_edge['top']}
    ]
    kicad_mod.append(PolygoneLine(polygone=p1f_poly,
        layer='F.Fab', width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom'] + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2},
        fp_name=footprint_name, text_y_inside_position='center')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='use confing .yaml files to create footprints.')
    parser.add_argument('--global_config', type=str, nargs='?', help='the config file defining how the footprint will look like. (KLC)', default='../../tools/global_config_files/config_KLCv3.0.yaml')
    parser.add_argument('--series_config', type=str, nargs='?', help='the config file defining series parameters.', default='../conn_config_KLCv3.yaml')
    args = parser.parse_args()

    with open(args.global_config, 'r') as config_stream:
        try:
            configuration = yaml.safe_load(config_stream)
        except yaml.YAMLError as exc:
            print(exc)

    with open(args.series_config, 'r') as config_stream:
        try:
            configuration.update(yaml.safe_load(config_stream))
        except yaml.YAMLError as exc:
            print(exc)
    for variant in variant_params:
        for pins_per_row in pins_per_row_range:
            generate_one_footprint(pins_per_row, variant_params[variant], configuration)
def generate_one_footprint(pins_per_row, variant, configuration):
    silk_pad_off = configuration['silk_pad_clearance']+configuration['silk_line_width']/2

    mpn = variant_params[variant]['part_code']['mpn'].format(n=pins_per_row*2)
    old_mpn = variant_params[variant]['part_code']['eng_num'].format(n=pins_per_row*2)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=old_mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    descr_format_str = "Molex {:s}, old mpn/engineering number: {:s}, example for new mpn: {:s}, {:d} Pins per row, Mounting: {:s} ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(descr_format_str.format(
        series_long, old_mpn, mpn, pins_per_row,
        variant_params[variant]['descriptive_name'], variant_params[variant]['datasheet']))
    tags = configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation])
    tags += variant_params[variant]['mount_pins']
    kicad_mod.setTags(tags)

    peg = variant_params[variant]['mount_pins'] == 'plastic_peg'

    #calculate fp dimensions

    #connector length
    A = pins_per_row * pitch + 1.2

    #pin centers
    B = (pins_per_row - 1) * pitch

    #plasic pin-lock
    C = A + 4

    #connector width
    W = 9.6

    #corner positions
    x1 = -(A-B)/2
    x2 = x1 + A

    y1 = -7.3 - 6.6
    y2 = y1 + 12.8
    body_edge={
        'left':x1,
        'right':x2,
        'bottom':y2,
        'top': y1
        }
    bounding_box = body_edge.copy()
    bounding_box['bottom'] = row + pad_size[1]/2

    #generate the pads
    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    for row_idx in range(2):
        kicad_mod.append(PadArray(
            pincount=pins_per_row, initial=row_idx*pins_per_row+1,
            start=[0, row_idx*row], x_spacing=pitch,
            type=Pad.TYPE_THT, shape=pad_shape,
            size=pad_size, drill=drill, layers=Pad.LAYERS_THT,
            **optional_pad_params))


    off = configuration['silk_fab_offset']
    #draw the 'peg' version
    #http://www.molex.com/pdm_docs/sd/026013127_sd.pdf
    #draw the outline of the shape
    kicad_mod.append(RectLine(start=[x1,y1],end=[x2,y2],
        layer='F.Fab', width=configuration['fab_line_width']))

    if peg:
        loc = 3.00
        if pins_per_row > 2: # two mounting holes
            kicad_mod.append(Pad(at=[0,-7.3],type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=loc,drill=loc, layers=Pad.LAYERS_NPTH))
            #kicad_mod.append(Circle(center=[0,-7.3],radius=loc/2+0.1))
            kicad_mod.append(Pad(at=[B,-7.3],type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=loc,drill=loc, layers=Pad.LAYERS_NPTH))
            #kicad_mod.append(Circle(center=[B,-7.3],radius=loc/2+0.1))
        else: #single hole
            kicad_mod.append(Pad(at=[B/2,-7.3],type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=loc,drill=loc, layers=Pad.LAYERS_NPTH))
            #kicad_mod.append(Circle(center=[B/2,-7.3],radius=loc/2+0.1))


        #draw the outline of the connector on the silkscreen
        poly = [
        {'x': -2,'y': y2+off},
        {'x': x1-off,'y': y2+off},
        {'x': x1-off,'y': y1-off},
        {'x': B/2,'y': y1-off},
        ]

        kicad_mod.append(PolygoneLine(polygone=poly,
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly, x_mirror=B/2,
            layer='F.SilkS', width=configuration['silk_line_width']))

    #draw the 'screw' version
    #http://www.molex.com/pdm_docs/sd/039291027_sd.pdf
    else:
        loc = 3.2
        kicad_mod.append(Pad(at=[-4.5,  -4.2],type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=loc, drill=loc, layers=Pad.LAYERS_NPTH))
        kicad_mod.append(Pad(at=[B+4.5, -4.2],type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=loc, drill=loc, layers=Pad.LAYERS_NPTH))
        bounding_box['left'] = -15.4/2
        bounding_box['right'] = B + 15.4/2

        #draw the connector outline on silkscreen layer
        poly = [
        {'x': x1,'y': y2-6.2},
        {'x': -15.4/2,'y': y2-6.2},
        {'x': -15.4/2,'y': y2},
        {'x': x1,'y': y2}
        ]

        kicad_mod.append(PolygoneLine(polygone=poly,
            layer='F.Fab', width=configuration['fab_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly, x_mirror=B/2,
            layer='F.Fab', width=configuration['fab_line_width']))

        poly = [
        {'x': B/2,'y': y1-off},
        {'x': x1-off,'y': y1-off},
        {'x': x1-off,'y': y2-6.2-off},
        {'x': -15.4/2 - off,'y': y2-6.2-off},
        {'x': -15.4/2 - off,'y': y2+off},
        {'x': -2,'y': y2+off},
        ]

        kicad_mod.append(PolygoneLine(polygone=poly))
        kicad_mod.append(PolygoneLine(polygone=poly, x_mirror=B/2,
            layer='F.SilkS', width=configuration['silk_line_width']))





    #draw the pins_per_row on the Silkscreen layer
    o = pad_size[1]/2+silk_pad_off
    w = 0.3
    for i in range(pins_per_row):
        x = i * pitch
        ya = o
        yb = row - o
        kicad_mod.append(Line(start=[x-w,ya],end=[x-w,yb],
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(Line(start=[x+w,ya],end=[x+w,yb],
            layer='F.SilkS', width=configuration['silk_line_width']))

    #draw lines between each pin
    off = 0.1
    for i in range(pins_per_row-1):
        xa = i * pitch + pad_size[0] / 2 + silk_pad_off
        xb = (i+1) * pitch - pad_size[0] / 2 - silk_pad_off

        kicad_mod.append(Line(start=[xa,y2+off],end=[xb,y2+off],
            layer='F.SilkS', width=configuration['silk_line_width']))

    #pin-1 marker
    x =  -2
    m = 0.3

    arrow = [
    {'x': x,'y': 0},
    {'x': x-2*m,'y': +m},
    {'x': x-2*m,'y': -m},
    {'x': x,'y': 0},
    ]

    kicad_mod.append(PolygoneLine(polygone=arrow,
        layer='F.SilkS', width=configuration['silk_line_width']))


    sl = 2
    pin = [
        {'x': -sl/2, 'y': body_edge['bottom']},
        {'x': 0, 'y': body_edge['bottom']-sl/sqrt(2)},
        {'x': sl/2, 'y': body_edge['bottom']},
    ]
    kicad_mod.append(PolygoneLine(polygone=pin,
        width=configuration['fab_line_width'], layer='F.Fab'))

    ########################### CrtYd #################################
    CrtYd_offset = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']

    cx1 = roundToBase(bounding_box['left'] - CrtYd_offset, CrtYd_grid)
    cy1 = roundToBase(bounding_box['top'] - CrtYd_offset, CrtYd_grid)

    cx2 = roundToBase(bounding_box['right'] + CrtYd_offset, CrtYd_grid)
    cy2 = roundToBase(bounding_box['bottom'] + CrtYd_offset, CrtYd_grid)

    if peg:
        kicad_mod.append(RectLine(
            start=[cx1, cy1], end=[cx2, cy2],
            layer='F.CrtYd', width=configuration['courtyard_line_width']))
    else:
        cxb_left = roundToBase(body_edge['left'] - CrtYd_offset, CrtYd_grid)
        cxp_left = roundToBase(-pad_size[0]/2 - CrtYd_offset, CrtYd_grid)

        cyb_bottom = roundToBase(body_edge['bottom'] + CrtYd_offset, CrtYd_grid)
        cyb_mount_top = roundToBase(body_edge['bottom'] -6.2 - CrtYd_offset, CrtYd_grid)

        poly_crtyd = [
                {'x': B/2, 'y': cy1},
                {'x': cxb_left, 'y': cy1},
                {'x': cxb_left, 'y': cyb_mount_top},
                {'x': cx1, 'y': cyb_mount_top},
                {'x': cx1, 'y': cyb_bottom},
                {'x': cxp_left, 'y': cyb_bottom},
                {'x': cxp_left, 'y': cy2},
                {'x': B/2, 'y': cy2},
            ]
        kicad_mod.append(PolygoneLine(
            polygone=poly_crtyd,
            layer='F.CrtYd', width=configuration['courtyard_line_width']))
        kicad_mod.append(PolygoneLine(
            polygone=poly_crtyd, x_mirror=B/2 if B/2 != 0 else 0.000000001,
            layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #16
0
def generate_one_footprint(pins, configuration, keying):
    #calculate fp dimensions
    pins_per_row = int(pins / number_of_rows)
    A = (pins_per_row - 1) * pitch
    B = A + 5.2

    mpn = part_base.format(n=pins, s=keying)
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_dual_pitch_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins_per_row,
        mounting_pad="",
        pitch_x=pitch,
        pitch_y=row_pitch,
        orientation=orientation_str)

    print('Building footprint: {}'.format(footprint_name))
    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator"
        .format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    pad_size = [pitch - pad_to_pad_clearance, row_pitch - pad_to_pad_clearance]
    if pad_size[0] - drill < 2 * min_annular_ring:
        pad_size[0] = drill + 2 * min_annular_ring

    if pad_size[1] - drill > 2 * pad_copper_y_solder_length:
        pad_size[1] = drill + 2 * pad_copper_y_solder_length
    if pad_size[1] - drill < 2 * min_annular_ring:
        pad_size[1] = drill + 2 * min_annular_ring

    if pad_size[0] == pad_size[1]:
        pad_shape = Pad.SHAPE_CIRCLE
    else:
        pad_shape = Pad.SHAPE_OVAL

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    for row_idx in range(2):
        #if pin1_row_to_mh == 'near':
        if keying == 'X':
            position_y = (row_idx) * row_pitch
        elif keying == 'Y':
            position_y = -(row_idx) * row_pitch

        kicad_mod.append(
            PadArray(initial=row_idx * pins_per_row + 1,
                     start=[0, position_y],
                     x_spacing=pitch,
                     pincount=pins_per_row,
                     increment=1,
                     size=pad_size,
                     drill=drill,
                     type=Pad.TYPE_THT,
                     shape=pad_shape,
                     layers=Pad.LAYERS_THT,
                     **optional_pad_params))

    #draw the component outline
    x1 = A / 2 - B / 2
    x2 = x1 + B
    y1 = -4.48
    #if pin1_row_to_mh == 'near':
    if keying == 'Y':
        y1 -= row_pitch
    y2 = y1 + 14.4
    body_edge = {'left': x1, 'right': x2, 'top': y1, 'bottom': y2}

    #draw the main outline around the footprint
    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(x1 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy1 = roundToBase(y1 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    cx2 = roundToBase(x2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy2 = roundToBase(y2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    #offset off
    off = configuration['silk_fab_offset']

    x1 -= off
    y1 -= off
    x2 += off
    y2 += off

    #outline
    ol = RectLine(start=[x1, y1],
                  end=[x2, y2],
                  layer="F.SilkS",
                  width=configuration['silk_line_width'])
    kicad_mod.append(ol)

    #courtyard

    #add mounting holes
    mh_y = 3.3
    #if pin1_row_to_mh != 'near':
    if keying == 'X':
        mh_y += row_pitch

    m1 = Pad(at=[0, mh_y],
             layers=Pad.LAYERS_THT,
             shape=Pad.SHAPE_CIRCLE,
             type=Pad.TYPE_THT,
             size=3,
             drill=2)
    m2 = Pad(at=[A, mh_y],
             layers=Pad.LAYERS_THT,
             shape=Pad.SHAPE_CIRCLE,
             type=Pad.TYPE_THT,
             size=3,
             drill=2)

    kicad_mod.append(m1)
    kicad_mod.append(m2)

    #add p1 marker
    px = -3
    m = 0.3

    marker = [
        {
            'x': px,
            'y': 0
        },
        {
            'x': px - 2 * m,
            'y': m
        },
        {
            'x': px - 2 * m,
            'y': -m
        },
        {
            'x': px,
            'y': 0
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=marker,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))

    sl = 1
    marker = [{
        'x': body_edge['left'],
        'y': sl / 2
    }, {
        'x': body_edge['left'] + sl / sqrt(2),
        'y': 0
    }, {
        'x': body_edge['left'],
        'y': -sl / 2
    }]
    kicad_mod.append(
        PolygoneLine(polygone=marker,
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    #line offset o
    o = 1
    ya = o
    yb = -o - row_pitch
    #if pin1_row_to_mh != 'near':
    if keying == 'X':
        ya += row_pitch
        yb = -o
    #draw lines between pin pairs
    for i in range(pins_per_row - 1):
        x = (i + 0.5) * pitch
        kicad_mod.append(
            Line(start=[x, ya],
                 end=[x, yb],
                 width=configuration['fab_line_width'],
                 layer='F.Fab'))

    #draw the inside of the connector
    #connector thickness t
    t = 0.45
    #notch size n
    n = 1.2
    inside = [{
        'x': A / 2 - n / 2,
        'y': y1
    }, {
        'x': A / 2 - n / 2,
        'y': y1 + t
    }, {
        'x': x1 + t,
        'y': y1 + t
    }, {
        'x': x1 + t,
        'y': y2 - t
    }, {
        'x': x1 + t + n,
        'y': y2 - t
    }, {
        'x': x1 + t + n,
        'y': y2 - 2 * t
    }, {
        'x': A / 2,
        'y': y2 - 2 * t
    }]

    kicad_mod.append(
        PolygoneLine(polygone=inside,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=inside,
                     x_mirror=A / 2,
                     layer="F.SilkS",
                     width=configuration['silk_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    mpn = part_code.format(n=pins)
    pad_silk_off = configuration['silk_line_width']/2 + configuration['silk_pad_clearance']
    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    footprint_name = footprint_name.replace("__",'_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Molex {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    A = (pins - 1) * pitch
    B = A + 2.9

    # create pads
    #createNumberedPadsTHT(kicad_mod, pincount, pitch, drill, {'x':x_dia, 'y':y_dia})

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(start=[0,0], pincount=pins, x_spacing=pitch,
        type=Pad.TYPE_THT, shape=pad_shape, size=pad_size,
        drill=drill, layers=Pad.LAYERS_THT,
        **optional_pad_params))


    x1 = -(B-A) / 2
    y1 = -2.2
    x2 = x1 + B
    y2 = 1.2

    body_edge={
        'left':x1,
        'right':x2,
        'bottom':y2,
        'top': y1
        }
    bounding_box = body_edge.copy()

    kicad_mod.append(RectLine(
        start={'x': x1,'y': y1}, end={'x': x2,'y': y2},
        layer='F.Fab', width=configuration['fab_line_width']))

    #line offset
    off = 0.1

    x1 -= off
    y1 -= off

    x2 += off
    y2 += off

    #draw the main outline around the footprint
    kicad_mod.append(RectLine(start={'x':x1,'y':y1},end={'x':x2,'y':y2},
        layer='F.SilkS', width=configuration['silk_line_width']))

    #add pin-1 marker
    p1_off = configuration['silk_fab_offset'] + 0.3
    L = 1.5
    pin = [
        {'y': body_edge['bottom'] - L, 'x': body_edge['left'] - p1_off},
        {'y': body_edge['bottom'] + p1_off, 'x': body_edge['left'] - p1_off},
        {'y': body_edge['bottom'] + p1_off, 'x': body_edge['left'] + L}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin,
        layer='F.SilkS', width=configuration['silk_line_width']))

    sl=1
    pin = [
        {'y': body_edge['bottom'], 'x': -sl/2},
        {'y': body_edge['bottom'] - sl/sqrt(2), 'x': 0},
        {'y': body_edge['bottom'], 'x': sl/2}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin,
        width=configuration['fab_line_width'], layer='F.Fab'))

    #side-wall thickness S

    S = 0.3

    #bottom line
    kicad_mod.append(PolygoneLine(
        polygone=[
            {'x':x1,'y':0},
            {'x':x1+S,'y':0},
            {'x':x1+S,'y':y2-S},
            {'x':x2-S,'y':y2-S},
            {'x':x2-S,'y':0},
            {'x':x2,'y':0}],
        layer='F.SilkS', width=configuration['silk_line_width']))

    #left mark

    #gap g
    g = 0.75

    kicad_mod.append(PolygoneLine(
        polygone=[
            {'x':x1,'y':-g},
            {'x':x1+S,'y':-g},
            {'x':x1+S,'y':y1+S*1.5},
            {'x':x1+2*S,'y':y1+S*1.5},
            {'x':x1+2*S,'y':y1}],
        layer='F.SilkS', width=configuration['silk_line_width']))

    kicad_mod.append(PolygoneLine(
        polygone=[
            {'x':x2,'y':-g},
            {'x':x2-S,'y':-g},
            {'x':x2-S,'y':y1+S*1.5},
            {'x':x2-2*S,'y':y1+S*1.5},
            {'x':x2-2*S,'y':y1}],
        layer='F.SilkS', width=configuration['silk_line_width']))

    #middle line
    kicad_mod.append(PolygoneLine(
        polygone=[
            {'x':x1+2*S,'y':y1+1.5*S},
            {'x':0.2*pitch,'y':y1+1.5*S},
            {'x':0.2*pitch,'y':y1+0.5*S},
            {'x':0.8*pitch,'y':y1+0.5*S},
            {'x':0.8*pitch,'y':y1+1.5*S},
            {'x':A-0.8*pitch,'y':y1+1.5*S},
            {'x':A-0.8*pitch,'y':y1+0.5*S},
            {'x':A-0.2*pitch,'y':y1+0.5*S},
            {'x':A-0.2*pitch,'y':y1+1.5*S},
            {'x':x2-2*S,'y':y1+1.5*S}],
        layer='F.SilkS', width=configuration['silk_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom'] + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, series_params, configuration):
    #calculate dimensions
    A = (pins - 1) * pitch
    B = A + 3.9

    #generate name
    mpn = part_base.format(n=pins, suffix=series_params[1])

    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins,
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator"
        .format(series_params[2], mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #coordinate locations
    #    x1 x3                  x4 x2
    # y3    ____________________
    # y1 __|____________________|__
    #    | 1  2  3  4  5  6  7  8 |
    # y2 |________________________|

    #draw the component outline
    x1 = A / 2 - B / 2
    x2 = x1 + B
    y2 = 4.8
    y1 = y2 - 6.8
    y3 = y1 - 1.7
    body_edge = {'left': x1, 'right': x2, 'top': y1, 'bottom': y2}

    #draw outline on F.Fab layer
    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    #draw rectangle on F.Fab for latch
    x3 = -0.75
    x4 = pitch * (pins - 1) + 0.75
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x3,
            'y': y1
        }, {
            'x': x3,
            'y': y3
        }, {
            'x': x4,
            'y': y3
        }, {
            'x': x4,
            'y': y1
        }],
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    #draw pin1 mark on F.Fab
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x1,
            'y': -1
        }, {
            'x': (x1 + 1),
            'y': 0
        }],
                     layer='F.Fab',
                     width=configuration['fab_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x1,
            'y': 1
        }, {
            'x': (x1 + 1),
            'y': 0
        }],
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(x1 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy1 = roundToBase(y3 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    cx2 = roundToBase(x2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy2 = roundToBase(y2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    #draw silk outline
    off = configuration['silk_fab_offset']
    x1 -= off
    y1 -= off
    x2 += off
    y2 += off
    x3 -= off
    y3 -= off
    x4 += off

    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x1,
            'y': y2
        }, {
            'x': x1,
            'y': y1
        }, {
            'x': x3,
            'y': y1
        }, {
            'x': x3,
            'y': y3
        }, {
            'x': x4,
            'y': y3
        }, {
            'x': x4,
            'y': y1
        }, {
            'x': x2,
            'y': y1
        }, {
            'x': x2,
            'y': y2
        }, {
            'x': x1,
            'y': y2
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    #add pin1 mark on silk
    px = x1 - 0.2
    m = 0.3

    marker = [{
        'x': px,
        'y': 0
    }, {
        'x': px - 2 * m,
        'y': m
    }, {
        'x': px - 2 * m,
        'y': -m
    }, {
        'x': px,
        'y': 0
    }]
    kicad_mod.append(
        PolygoneLine(polygone=marker,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    pad_size = [
        pitch - pad_to_pad_clearance, drill + 2 * pad_copper_y_solder_length
    ]
    if pad_size[0] - drill < 2 * min_annular_ring:
        pad_size[0] = drill + 2 * min_annular_ring
    if pad_size[0] - drill > 2 * pad_copper_y_solder_length:
        pad_size[0] = drill + 2 * pad_copper_y_solder_length

    shape = Pad.SHAPE_OVAL
    if pad_size[1] == pad_size[0]:
        shape = Pad.SHAPE_CIRCLE

    pa = PadArray(pincount=pins,
                  x_spacing=pitch,
                  type=Pad.TYPE_THT,
                  shape=shape,
                  size=pad_size,
                  drill=drill,
                  layers=Pad.LAYERS_THT)
    kicad_mod.append(pa)

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(fpid, rows, datasheet, configuration):
    pins = []
    if fpid == "IAxxxxS" and rows == "SIP" :
        casetolerance = 0.5
        casemaxwidth = 6.09
        casemaxlength = 19.30
        x_max = 1.40
        x_min = x_max - (casemaxwidth - casetolerance)
        y_min = -1.53
        y_max = y_min + (casemaxlength - casetolerance)
        pins = [1, 2, 4, 5, 6]
        xpos = [1, 1, 1, 1, 1]
        ypos = [1, 2, 4, 5, 6]
    elif fpid == "IA48xxS" and rows == "SIP" :
        casetolerance = 0.5
        casemaxwidth = 7.20
        casemaxlength = 19.30
        x_max = 1.40
        x_min = x_max - (casemaxwidth - casetolerance)
        y_min = -1.53
        y_max = y_min + (casemaxlength - casetolerance)
        pins = [1, 2, 4, 5, 6]
        xpos = [1, 1, 1, 1, 1]
        ypos = [1, 2, 4, 5, 6]
    elif fpid == "IAxxxxD" and rows == "DIP" :
        casetolerance = 0.5
        casemaxwidth = 10.16
        casemaxlength = 20.32
        x_min = -(casemaxwidth-casetolerance-xpitch)/2
        x_max = x_min + (casemaxwidth - casetolerance)
        y_min = -(casemaxlength-casetolerance-15.24)/2
        y_max = y_min + (casemaxlength - casetolerance)
        pins = [1, 2, 3, 4, 5, 6]
        xpos = [1, 1, 2, 2, 2, 2]
        ypos = [1, 7, 1, 4, 6, 7]
    elif fpid == "IA48xxD" and rows == "DIP" :
        casetolerance = 0.5
        casemaxwidth = 10.16
        casemaxlength = 20.32
        x_min = -(casemaxwidth-casetolerance-xpitch)/2
        x_max = x_min + (casemaxwidth - casetolerance)
        y_min = -(casemaxlength-casetolerance-15.24)/2
        y_max = y_min + (casemaxlength - casetolerance)
        pins = [1, 2, 3, 4, 5, 6]
        xpos = [1, 1, 2, 2, 2, 2]
        ypos = [1, 7, 1, 4, 6, 7]
    elif fpid == "IHxxxxS" and rows == "SIP" :
        casetolerance = 0.5
        casemaxwidth = 7.20
        casemaxlength = 19.5
        x_max = 1.25
        x_min = x_max - (casemaxwidth - casetolerance)
        y_min = -2.29
        y_max = y_min + (casemaxlength - casetolerance)
        pins = [1, 2, 4, 5, 6]
        xpos = [1, 1, 1, 1, 1]
        ypos = [1, 2, 4, 5, 6]
    elif fpid == "IHxxxxSH" and rows == "SIP" :
        casetolerance = 0.5
        casemaxwidth = 7.62
        casemaxlength = 19.5
        x_max = 1.25
        x_min = x_max - (casemaxwidth - casetolerance)
        y_min = -2.29
        y_max = y_min + (casemaxlength - casetolerance)
        pins = [1, 2, 4, 5, 6]
        xpos = [1, 1, 1, 1, 1]
        ypos = [1, 2, 5, 6, 7]
    elif fpid == "IHxxxxD" and rows == "DIP" :
        casetolerance = 0.5
        casemaxwidth = 10.16
        casemaxlength = 20.32
        x_min = -(casemaxwidth-casetolerance-xpitch)/2
        x_max = x_min + (casemaxwidth - casetolerance)
        y_min = -(casemaxlength-casetolerance-15.24)/2
        y_max = y_min + (casemaxlength - casetolerance)
        pins = [1, 2, 3, 4, 5, 6]
        xpos = [1, 1, 2, 2, 2, 2]
        ypos = [1, 7, 1, 4, 6, 7]
    elif fpid == "IHxxxxDH" and rows == "DIP" :
        casetolerance = 0.5
        casemaxwidth = 10.16
        casemaxlength = 20.32
        x_min = -(casemaxwidth-casetolerance-xpitch)/2
        x_max = x_min + (casemaxwidth - casetolerance)
        y_min = -(casemaxlength-casetolerance-15.24)/2
        y_max = y_min + (casemaxlength - casetolerance)
        pins = [1, 2, 3, 4, 5, 6]
        xpos = [1, 1, 2, 2, 2, 2]
        ypos = [1, 7, 1, 5, 7, 6]
    elif fpid == "ITQxxxxS-H" and rows == "SIP" :
        casetolerance = 0.5
        casewidth = 9.20
        caselength = 21.85
        x_max = 3.20
        x_min = x_max - casewidth
        y_min = -(caselength - 17.78)/2
        y_max = y_min + caselength
        pins = [1, 2, 3, 6, 7, 8]
        xpos = [1, 1, 1, 1, 1, 1]
        ypos = [1, 2, 3, 6, 7, 8]
    elif fpid == "ITxxxxxS" and rows == "SIP" :
        casetolerance = 0.5
        casewidth = 9.20
        caselength = 21.85
        x_max = 3.20
        x_min = x_max - casewidth
        y_min = -(caselength - 17.78)/2
        y_max = y_min + caselength
        pins = [1, 2, 3, 6, 7]
        xpos = [1, 1, 1, 1, 1]
        ypos = [1, 2, 3, 6, 7]
    elif fpid == "ITXxxxxSA" and rows == "SIP" :
        casetolerance = 0.5
        casewidth = 9.20
        caselength = 21.85
        x_max = 3.20
        x_min = x_max - casewidth
        y_min = -(caselength - 17.78)/2
        y_max = y_min + caselength
        pins = [1, 2, 6, 7, 8]
        xpos = [1, 1, 1, 1, 1]
        ypos = [1, 2, 6, 7, 8]

    silk_x_min = x_min - configuration['silk_fab_offset']
    silk_x_max = x_max + configuration['silk_fab_offset']
    silk_y_min = y_min - configuration['silk_fab_offset']
    silk_y_max = y_max + configuration['silk_fab_offset']

    footprint_name = "Converter_DCDC_XP_POWER-{:s}_THT".format(fpid)
    ser = ""
    if fpid.startswith("IA_"):
        ser="SF_IA"
    elif fpid.startswith("IH_"):
        ser="SF_IH"
    elif fpid.startswith("ITX_"):
        ser="SF_ITX"
    elif fpid.startswith("ITQ_"):
        ser="SF_ITQ"

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("XP_POWER {:s} {:s}, {:s}, ({:s}), generated with kicad-footprint-generator".format(ser,fpid, rows, datasheet))
    kicad_mod.setTags("XP_POWER {:s} {:s} {:s} DCDC-Converter".format(ser,fpid,rows))

    # create Silkscreen
    kicad_mod.append(RectLine(start=[silk_x_min,silk_y_min], end=[silk_x_max,silk_y_max],
        layer='F.SilkS', width=configuration['silk_line_width']))

    ########################### Pin 1 marker ################################
    poly_pin1_marker = [
        {'x':silk_x_min-pin1_marker_offset+pin1_marker_linelen, 'y':silk_y_min-pin1_marker_offset},
        {'x':silk_x_min-pin1_marker_offset, 'y':silk_y_min-pin1_marker_offset},
        {'x':silk_x_min-pin1_marker_offset, 'y':silk_y_min-pin1_marker_offset+pin1_marker_linelen}
    ]
    kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker, layer='F.SilkS', width=configuration['silk_line_width']))
    if fab_pin1_marker_type == 1:
        kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker, layer='F.Fab', width=configuration['fab_line_width']))

    if fab_pin1_marker_type == 2:
        poly_pin1_marker_type2 = [
            {'x':-1, 'y':y_min},
            {'x':0, 'y':y_min+1},
            {'x':1, 'y':y_min}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker_type2, layer='F.Fab', width=configuration['fab_line_width']))

    ########################## Fab Outline ###############################
    kicad_mod.append(RectLine(start=[x_min,y_min], end=[x_max,y_max],
        layer='F.Fab', width=configuration['fab_line_width']))
    ############################# CrtYd ##################################
    part_x_min = x_min
    part_x_max = x_max
    part_y_min = y_min
    part_y_max = y_max

    #Note, we use the connector courtyard clearance of 0.5 mm because the unusually large case tolerance of 0.5mm of XP Powers DC DC converters
    cx1 = roundToBase(part_x_min-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(part_y_min-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(part_x_max+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(part_y_max+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))


    ############################# Pads ##################################
    pad_size = [ypitch - pad_to_pad_clearance, drill_size + 2*pad_copper_y_solder_length]

    if pad_size[0] - drill_size < 2*min_annular_ring:
        pad_size[0] = drill_size + 2*min_annular_ring

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    for i in range(len(pins)):
        pshape = Pad.SHAPE_OVAL
        if pins[i] == 1:
            pshape = Pad.SHAPE_RECT
        kicad_mod.append(Pad(number=pins[i], type=Pad.TYPE_THT, shape=pshape, at=[(xpos[i]-1)*xpitch, (ypos[i]-1)*ypitch], size=pad_size, drill=drill_size, layers=Pad.LAYERS_THT,
        **optional_pad_params))

    ######################### Text Fields ###############################
    text_center_y = 1.5
    body_edge={'left':part_x_min, 'right':part_x_max, 'top':part_y_min, 'bottom':part_y_max}
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position=text_center_y)

    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=ser)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
    print(filename)
def generate_one_footprint(pins_per_row, variant, configuration):
    silk_pad_off = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2

    mpn = variant_params[variant]['part_code']['mpn'].format(n=pins_per_row *
                                                             2)
    old_mpn = variant_params[variant]['part_code']['eng_num'].format(
        n=pins_per_row * 2)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=old_mpn,
        num_rows=number_of_rows,
        pins_per_row=pins_per_row,
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    descr_format_str = "Molex {:s}, old mpn/engineering number: {:s}, example for new mpn: {:s}, {:d} Pins per row, Mounting: {:s} ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(
        descr_format_str.format(series_long, old_mpn, mpn, pins_per_row,
                                variant_params[variant]['descriptive_name'],
                                variant_params[variant]['datasheet']))
    tags = configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation])
    tags += variant_params[variant]['mount_pins']
    kicad_mod.setTags(tags)

    peg = variant_params[variant]['mount_pins'] == 'plastic_peg'

    #calculate fp dimensions

    #connector length
    A = pins_per_row * pitch + 1.2

    #pin centers
    B = (pins_per_row - 1) * pitch

    #plasic pin-lock
    C = A + 4

    #connector width
    W = 9.6

    #corner positions
    x1 = -(A - B) / 2
    x2 = x1 + A

    y1 = -7.3 - 6.6
    y2 = y1 + 12.8
    body_edge = {'left': x1, 'right': x2, 'bottom': y2, 'top': y1}
    bounding_box = body_edge.copy()
    bounding_box['bottom'] = row + pad_size[1] / 2

    #generate the pads
    kicad_mod.append(
        PadArray(pincount=pins_per_row,
                 x_spacing=pitch,
                 type=Pad.TYPE_THT,
                 shape=pad_shape,
                 size=pad_size,
                 drill=drill,
                 layers=Pad.LAYERS_THT))
    kicad_mod.append(
        PadArray(pincount=pins_per_row,
                 initial=pins_per_row + 1,
                 start=[0, row],
                 x_spacing=pitch,
                 type=Pad.TYPE_THT,
                 shape=pad_shape,
                 size=pad_size,
                 drill=drill,
                 layers=Pad.LAYERS_THT))

    off = configuration['silk_fab_offset']
    #draw the 'peg' version
    #http://www.molex.com/pdm_docs/sd/026013127_sd.pdf
    #draw the outline of the shape
    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    if peg:
        loc = 3.00
        if pins_per_row > 2:  # two mounting holes
            kicad_mod.append(
                Pad(at=[0, -7.3],
                    type=Pad.TYPE_NPTH,
                    shape=Pad.SHAPE_CIRCLE,
                    size=loc,
                    drill=loc,
                    layers=Pad.LAYERS_NPTH))
            #kicad_mod.append(Circle(center=[0,-7.3],radius=loc/2+0.1))
            kicad_mod.append(
                Pad(at=[B, -7.3],
                    type=Pad.TYPE_NPTH,
                    shape=Pad.SHAPE_CIRCLE,
                    size=loc,
                    drill=loc,
                    layers=Pad.LAYERS_NPTH))
            #kicad_mod.append(Circle(center=[B,-7.3],radius=loc/2+0.1))
        else:  #single hole
            kicad_mod.append(
                Pad(at=[B / 2, -7.3],
                    type=Pad.TYPE_NPTH,
                    shape=Pad.SHAPE_CIRCLE,
                    size=loc,
                    drill=loc,
                    layers=Pad.LAYERS_NPTH))
            #kicad_mod.append(Circle(center=[B/2,-7.3],radius=loc/2+0.1))

        #draw the outline of the connector on the silkscreen
        poly = [
            {
                'x': -2,
                'y': y2 + off
            },
            {
                'x': x1 - off,
                'y': y2 + off
            },
            {
                'x': x1 - off,
                'y': y1 - off
            },
            {
                'x': B / 2,
                'y': y1 - off
            },
        ]

        kicad_mod.append(
            PolygoneLine(polygone=poly,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))
        kicad_mod.append(
            PolygoneLine(polygone=poly,
                         x_mirror=B / 2 if B / 2 != 0 else 0.000000001,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))

    #draw the 'screw' version
    #http://www.molex.com/pdm_docs/sd/039291027_sd.pdf
    else:
        loc = 3.2
        kicad_mod.append(
            Pad(at=[-4.5, -4.2],
                type=Pad.TYPE_NPTH,
                shape=Pad.SHAPE_CIRCLE,
                size=loc,
                drill=loc,
                layers=Pad.LAYERS_NPTH))
        kicad_mod.append(
            Pad(at=[B + 4.5, -4.2],
                type=Pad.TYPE_NPTH,
                shape=Pad.SHAPE_CIRCLE,
                size=loc,
                drill=loc,
                layers=Pad.LAYERS_NPTH))
        bounding_box['left'] = -15.4 / 2
        bounding_box['right'] = B + 15.4 / 2

        #draw the connector outline on silkscreen layer
        poly = [{
            'x': x1,
            'y': y2 - 6.2
        }, {
            'x': -15.4 / 2,
            'y': y2 - 6.2
        }, {
            'x': -15.4 / 2,
            'y': y2
        }, {
            'x': x1,
            'y': y2
        }]

        kicad_mod.append(
            PolygoneLine(polygone=poly,
                         layer='F.Fab',
                         width=configuration['fab_line_width']))
        kicad_mod.append(
            PolygoneLine(polygone=poly,
                         x_mirror=B / 2 if B / 2 != 0 else 0.000000001,
                         layer='F.Fab',
                         width=configuration['fab_line_width']))

        poly = [
            {
                'x': B / 2,
                'y': y1 - off
            },
            {
                'x': x1 - off,
                'y': y1 - off
            },
            {
                'x': x1 - off,
                'y': y2 - 6.2 - off
            },
            {
                'x': -15.4 / 2 - off,
                'y': y2 - 6.2 - off
            },
            {
                'x': -15.4 / 2 - off,
                'y': y2 + off
            },
            {
                'x': -2,
                'y': y2 + off
            },
        ]

        kicad_mod.append(PolygoneLine(polygone=poly))
        kicad_mod.append(
            PolygoneLine(polygone=poly,
                         x_mirror=B / 2 if B / 2 != 0 else 0.000000001,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))

    #draw the pins_per_row on the Silkscreen layer
    o = pad_size[1] / 2 + silk_pad_off
    w = 0.3
    for i in range(pins_per_row):
        x = i * pitch
        ya = o
        yb = row - o
        kicad_mod.append(
            Line(start=[x - w, ya],
                 end=[x - w, yb],
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))
        kicad_mod.append(
            Line(start=[x + w, ya],
                 end=[x + w, yb],
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))

    #draw lines between each pin
    off = 0.1
    for i in range(pins_per_row - 1):
        xa = i * pitch + pad_size[0] / 2 + silk_pad_off
        xb = (i + 1) * pitch - pad_size[0] / 2 - silk_pad_off

        kicad_mod.append(
            Line(start=[xa, y2 + off],
                 end=[xb, y2 + off],
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))

    #pin-1 marker
    x = -2
    m = 0.3

    arrow = [
        {
            'x': x,
            'y': 0
        },
        {
            'x': x - 2 * m,
            'y': +m
        },
        {
            'x': x - 2 * m,
            'y': -m
        },
        {
            'x': x,
            'y': 0
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=arrow,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    sl = 2
    pin = [
        {
            'x': -sl / 2,
            'y': body_edge['bottom']
        },
        {
            'x': 0,
            'y': body_edge['bottom'] - sl / sqrt(2)
        },
        {
            'x': sl / 2,
            'y': body_edge['bottom']
        },
    ]
    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     width=configuration['fab_line_width'],
                     layer='F.Fab'))

    ########################### CrtYd #################################
    CrtYd_offset = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']

    cx1 = roundToBase(bounding_box['left'] - CrtYd_offset, CrtYd_grid)
    cy1 = roundToBase(bounding_box['top'] - CrtYd_offset, CrtYd_grid)

    cx2 = roundToBase(bounding_box['right'] + CrtYd_offset, CrtYd_grid)
    cy2 = roundToBase(bounding_box['bottom'] + CrtYd_offset, CrtYd_grid)

    if peg:
        kicad_mod.append(
            RectLine(start=[cx1, cy1],
                     end=[cx2, cy2],
                     layer='F.CrtYd',
                     width=configuration['courtyard_line_width']))
    else:
        cxb_left = roundToBase(body_edge['left'] - CrtYd_offset, CrtYd_grid)
        cxp_left = roundToBase(-pad_size[0] / 2 - CrtYd_offset, CrtYd_grid)

        cyb_bottom = roundToBase(body_edge['bottom'] + CrtYd_offset,
                                 CrtYd_grid)
        cyb_mount_top = roundToBase(body_edge['bottom'] - 6.2 - CrtYd_offset,
                                    CrtYd_grid)

        poly_crtyd = [
            {
                'x': B / 2,
                'y': cy1
            },
            {
                'x': cxb_left,
                'y': cy1
            },
            {
                'x': cxb_left,
                'y': cyb_mount_top
            },
            {
                'x': cx1,
                'y': cyb_mount_top
            },
            {
                'x': cx1,
                'y': cyb_bottom
            },
            {
                'x': cxp_left,
                'y': cyb_bottom
            },
            {
                'x': cxp_left,
                'y': cy2
            },
            {
                'x': B / 2,
                'y': cy2
            },
        ]
        kicad_mod.append(
            PolygoneLine(polygone=poly_crtyd,
                         layer='F.CrtYd',
                         width=configuration['courtyard_line_width']))
        kicad_mod.append(
            PolygoneLine(polygone=poly_crtyd,
                         x_mirror=B / 2 if B / 2 != 0 else 0.000000001,
                         layer='F.CrtYd',
                         width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins_per_row, configuration):
    mpn = part_code.format(n=pins_per_row*number_of_rows)
    alt_mpn = [code.format(n=pins_per_row*number_of_rows) for code in alternative_codes]

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Molex {:s}, {:s} (compatible alternatives: {:s}), {:d} Pins per row ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, ', '.join(alt_mpn), pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #calculate fp dimensions
    A = (pins_per_row - 1) * pitch
    B = A + 3.1
    C = A + 4

    #connector thickness
    T = 5.75

    #corners
    x1 = -2
    x2 = x1 + C

    T = 3.65

    y1 = -1.5
    y2 = y1 + T

    off = configuration['silk_fab_offset']
    pad_silk_off = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2

    body_edge={
        'left':x1,
        'right':x2,
        'bottom':y2,
        'top': y1
        }
    bounding_box = body_edge.copy()

    #add simple outline to F.Fab layer
    kicad_mod.append(RectLine(start=[x1,y1],end=[x2,y2],layer='F.Fab', width=configuration['fab_line_width']))

    #wall-thickness W
    w = 0.4

    #offset
    o = configuration['silk_fab_offset']
    x1 -= o
    y1 -= o
    x2 += o
    y2 += o

    #generate the pads
    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(
        pincount=pins_per_row, x_spacing=pitch, type=Pad.TYPE_THT,
        shape=pad_shape, size=pad_size, drill=drill, layers=Pad.LAYERS_THT,
        **optional_pad_params))

    #draw the courtyard

    #draw the connector outline
    out = RectLine(start=[x1,y1], end=[x2,y2],
        width=configuration['silk_line_width'], layer="F.SilkS")
    kicad_mod.append(out)

    #pin-1 marker
    y =  -2
    m = 0.3

    O = 0.3
    L = 2
    pin = [
        {'x': x1 + L, 'y': y1 - O},
        {'x': x1 - O, 'y': y1 - O},
        {'x': x1 - O, 'y': y1 + L},
        ]

    kicad_mod.append(PolygoneLine(polygone=pin,
        width=configuration['silk_line_width'], layer="F.SilkS"))

    p1m_sl = 1
    pin =[
        {'x': -p1m_sl/2, 'y': body_edge['top']},
        {'x': 0, 'y': body_edge['top'] + p1m_sl/sqrt(2)},
        {'x': p1m_sl/2, 'y': body_edge['top']}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin, width=configuration['fab_line_width'], layer='F.Fab'))

    kicad_mod.append(Line(start=[x1,2*w],end=[x1+w,2*w],
        width=configuration['silk_line_width'], layer="F.SilkS"))
    kicad_mod.append(Line(start=[x2,2*w],end=[x2-w,2*w],
        width=configuration['silk_line_width'], layer="F.SilkS"))

    #add the 'wall'
    wall = [
    {'x': A/2,'y': y1+w},
    {'x': x1+w,'y': y1+w},
    {'x': x1+w,'y': 0},
    {'x': x1+2*w,'y': 0},
    {'x': x1+2*w,'y': w},
    {'x': x1+w,'y': w},
    {'x': x1+w,'y': y2},
    ]

    kicad_mod.append(PolygoneLine(polygone=wall,
        width=configuration['silk_line_width'], layer="F.SilkS"))
    kicad_mod.append(PolygoneLine(polygone=wall,x_mirror=A/2,
        width=configuration['silk_line_width'], layer="F.SilkS"))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom'] + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
    def generateFootprint(self, device_params):
        fab_line_width = self.configuration.get('fab_line_width', 0.1)
        silk_line_width = self.configuration.get('silk_line_width', 0.12)

        lib_name = self.configuration['lib_name_format_string'].format(
            category=category)

        if 'body_size_x' in device_params:
            size_x = device_params['body_size_x']
        else:
            size_x = (device_params['body_size_x_max'] +
                      device_params['body_size_x_min']) / 2

        if 'body_size_y' in device_params:
            size_y = device_params['body_size_y']
        else:
            size_y = (device_params['body_size_y_max'] +
                      device_params['body_size_y_min']) / 2

        pincount = device_params['num_pins_x'] * 2 + device_params[
            'num_pins_y'] * 2

        ipc_reference = 'ipc_spec_j_lead'

        ipc_data_set = self.ipc_defintions[ipc_reference][ipc_density]
        ipc_round_base = self.ipc_defintions[ipc_reference]['round_base']

        pad_details = self.calcPadDetails(device_params, ipc_data_set,
                                          ipc_round_base)

        suffix = device_params.get('suffix', '').format(
            pad_x=pad_details['left']['size'][0],
            pad_y=pad_details['left']['size'][1])
        suffix_3d = suffix if device_params.get('include_suffix_in_3dpath',
                                                'True') == 'True' else ""

        model3d_path_prefix = self.configuration.get('3d_model_prefix',
                                                     '${KISYS3DMOD}')
        name_format = self.configuration['fp_name_format_string']

        fp_name = name_format.format(man=device_params.get('manufacturer', ''),
                                     mpn=device_params.get('part_number', ''),
                                     pkg=device_params['device_type'],
                                     pincount=pincount,
                                     size_y=size_y,
                                     size_x=size_x,
                                     pitch=device_params['pitch'],
                                     suffix=suffix).replace('__',
                                                            '_').lstrip('_')

        fp_name_2 = name_format.format(
            man=device_params.get('manufacturer', ''),
            mpn=device_params.get('part_number', ''),
            pkg=device_params['device_type'],
            pincount=pincount,
            size_y=size_y,
            size_x=size_x,
            pitch=device_params['pitch'],
            suffix=suffix_3d).replace('__', '_').lstrip('_')

        model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'\
            .format(
                model3d_path_prefix=model3d_path_prefix, lib_name=lib_name,
                fp_name=fp_name_2)
        #print(fp_name)
        #print(pad_details)

        kicad_mod = Footprint(fp_name)

        # init kicad footprint
        kicad_mod.setDescription(
            "{manufacturer} {mpn} {package}, {pincount} Pin ({datasheet}), generated with kicad-footprint-generator {scriptname}"\
            .format(
                manufacturer = device_params.get('manufacturer',''),
                package = device_params['device_type'],
                mpn = device_params.get('part_number',''),
                pincount = pincount,
                datasheet = device_params['size_source'],
                scriptname = os.path.basename(__file__).replace("  ", " ")
                ).lstrip())

        kicad_mod.setTags(self.configuration['keyword_fp_string']\
            .format(
                man=device_params.get('manufacturer',''),
                package=device_params['device_type'],
                category=category
            ).lstrip())
        kicad_mod.setAttribute('smd')

        pad_shape_details = {}
        pad_shape_details['shape'] = Pad.SHAPE_ROUNDRECT
        pad_shape_details['radius_ratio'] = configuration.get(
            'round_rect_radius_ratio', 0)
        if 'round_rect_max_radius' in configuration:
            pad_shape_details['maximum_radius'] = configuration[
                'round_rect_max_radius']

        init = 1
        kicad_mod.append(
            PadArray(initial=init,
                     type=Pad.TYPE_SMT,
                     layers=Pad.LAYERS_SMT,
                     pincount=int(math.ceil(device_params['num_pins_x'] / 2)),
                     x_spacing=-device_params['pitch'],
                     y_spacing=0,
                     **pad_details['first'],
                     **pad_shape_details))

        init += int(math.ceil(device_params['num_pins_x'] / 2))
        kicad_mod.append(
            PadArray(initial=init,
                     type=Pad.TYPE_SMT,
                     layers=Pad.LAYERS_SMT,
                     pincount=device_params['num_pins_y'],
                     x_spacing=0,
                     y_spacing=device_params['pitch'],
                     **pad_details['left'],
                     **pad_shape_details))

        init += device_params['num_pins_y']
        kicad_mod.append(
            PadArray(initial=init,
                     type=Pad.TYPE_SMT,
                     layers=Pad.LAYERS_SMT,
                     pincount=device_params['num_pins_x'],
                     y_spacing=0,
                     x_spacing=device_params['pitch'],
                     **pad_details['bottom'],
                     **pad_shape_details))

        init += device_params['num_pins_x']
        kicad_mod.append(
            PadArray(initial=init,
                     type=Pad.TYPE_SMT,
                     layers=Pad.LAYERS_SMT,
                     pincount=device_params['num_pins_y'],
                     x_spacing=0,
                     y_spacing=-device_params['pitch'],
                     **pad_details['right'],
                     **pad_shape_details))

        init += device_params['num_pins_y']
        kicad_mod.append(
            PadArray(initial=init,
                     type=Pad.TYPE_SMT,
                     layers=Pad.LAYERS_SMT,
                     pincount=int(math.floor(device_params['num_pins_x'] / 2)),
                     y_spacing=0,
                     x_spacing=-device_params['pitch'],
                     **pad_details['top'],
                     **pad_shape_details))

        body_edge = {
            'left': -size_x / 2,
            'right': size_x / 2,
            'top': -size_y / 2,
            'bottom': size_y / 2
        }

        bounding_box = {
            'left':
            pad_details['left']['center'][0] -
            pad_details['left']['size'][0] / 2,
            'right':
            pad_details['right']['center'][0] +
            pad_details['right']['size'][0] / 2,
            'top':
            pad_details['top']['start'][1] - pad_details['top']['size'][1] / 2,
            'bottom':
            pad_details['bottom']['center'][1] +
            pad_details['bottom']['size'][1] / 2
        }

        pad_width = pad_details['top']['size'][0]
        p1_x = pad_details['first']['start'][0]

        # ############################ SilkS ##################################

        silk_pad_offset = configuration[
            'silk_pad_clearance'] + configuration['silk_line_width'] / 2
        silk_offset = configuration['silk_fab_offset']

        sx1 = -(device_params['pitch'] *
                (device_params['num_pins_x'] - 1) / 2.0 + pad_width / 2.0 +
                silk_pad_offset)

        sy1 = -(device_params['pitch'] *
                (device_params['num_pins_y'] - 1) / 2.0 + pad_width / 2.0 +
                silk_pad_offset)

        poly_silk = [{
            'x': sx1,
            'y': body_edge['top'] - silk_offset
        }, {
            'x': body_edge['left'] - silk_offset,
            'y': body_edge['top'] - silk_offset
        }, {
            'x': body_edge['left'] - silk_offset,
            'y': sy1
        }]
        kicad_mod.append(
            PolygoneLine(polygone=poly_silk,
                         width=configuration['silk_line_width'],
                         layer="F.SilkS",
                         x_mirror=0))
        kicad_mod.append(
            PolygoneLine(polygone=poly_silk,
                         width=configuration['silk_line_width'],
                         layer="F.SilkS",
                         y_mirror=0))
        kicad_mod.append(
            PolygoneLine(polygone=poly_silk,
                         width=configuration['silk_line_width'],
                         layer="F.SilkS",
                         x_mirror=0,
                         y_mirror=0))

        silk_off_45 = silk_offset / sqrt(2)
        poly_silk_tl = [{
            'x': sx1,
            'y': body_edge['top'] - silk_offset
        }, {
            'x':
            body_edge['left'] + device_params['body_chamfer'] - silk_off_45,
            'y':
            body_edge['top'] - silk_offset
        }, {
            'x':
            body_edge['left'] - silk_offset,
            'y':
            body_edge['top'] + device_params['body_chamfer'] - silk_off_45
        }, {
            'x': body_edge['left'] - silk_offset,
            'y': sy1
        }]
        kicad_mod.append(
            PolygoneLine(polygone=poly_silk_tl,
                         width=configuration['silk_line_width'],
                         layer="F.SilkS"))

        # # ######################## Fabrication Layer ###########################

        fab_bevel_size = min(
            configuration['fab_bevel_size_absolute'],
            configuration['fab_bevel_size_relative'] * min(size_x, size_y))
        fab_bevel_y = fab_bevel_size / sqrt(2)
        poly_fab = [{
            'x': p1_x,
            'y': body_edge['top'] + fab_bevel_y
        }, {
            'x': p1_x + fab_bevel_size / 2,
            'y': body_edge['top']
        }, {
            'x': body_edge['right'],
            'y': body_edge['top']
        }, {
            'x': body_edge['right'],
            'y': body_edge['bottom']
        }, {
            'x': body_edge['left'],
            'y': body_edge['bottom']
        }, {
            'x': body_edge['left'],
            'y': body_edge['top'] + device_params['body_chamfer']
        }, {
            'x': body_edge['left'] + device_params['body_chamfer'],
            'y': body_edge['top']
        }, {
            'x': p1_x - fab_bevel_size / 2,
            'y': body_edge['top']
        }, {
            'x': p1_x,
            'y': body_edge['top'] + fab_bevel_y
        }]

        kicad_mod.append(
            PolygoneLine(polygone=poly_fab,
                         width=configuration['fab_line_width'],
                         layer="F.Fab"))

        # # ############################ CrtYd ##################################

        off = ipc_data_set['courtyard']
        grid = configuration['courtyard_grid']
        off_45 = off * math.tan(math.radians(45.0 / 2))

        cy1 = roundToBase(bounding_box['top'] - off, grid)
        cy2 = roundToBase(body_edge['top'] - off, grid)
        cy3 = -roundToBase(
            device_params['pitch'] * (device_params['num_pins_y'] - 1) / 2.0 +
            pad_width / 2.0 + off, grid)
        cy4 = roundToBase(
            body_edge['top'] + device_params['body_chamfer'] - off_45, grid)

        cx1 = -roundToBase(
            device_params['pitch'] * (device_params['num_pins_x'] - 1) / 2.0 +
            pad_width / 2.0 + off, grid)
        cx2 = roundToBase(body_edge['left'] - off, grid)
        cx3 = roundToBase(bounding_box['left'] - off, grid)
        cx4 = roundToBase(
            body_edge['left'] + device_params['body_chamfer'] - off_45, grid)

        crty_poly_tl = [{
            'x': 0,
            'y': cy1
        }, {
            'x': cx1,
            'y': cy1
        }, {
            'x': cx1,
            'y': cy2
        }, {
            'x': cx2,
            'y': cy2
        }, {
            'x': cx2,
            'y': cy3
        }, {
            'x': cx3,
            'y': cy3
        }, {
            'x': cx3,
            'y': 0
        }]

        kicad_mod.append(
            PolygoneLine(polygone=crty_poly_tl,
                         layer='F.CrtYd',
                         width=configuration['courtyard_line_width'],
                         x_mirror=0))
        kicad_mod.append(
            PolygoneLine(polygone=crty_poly_tl,
                         layer='F.CrtYd',
                         width=configuration['courtyard_line_width'],
                         y_mirror=0))
        kicad_mod.append(
            PolygoneLine(polygone=crty_poly_tl,
                         layer='F.CrtYd',
                         width=configuration['courtyard_line_width'],
                         x_mirror=0,
                         y_mirror=0))

        crty_poly_tl_ch = [{
            'x': 0,
            'y': cy1
        }, {
            'x': cx1,
            'y': cy1
        }, {
            'x': cx1,
            'y': cy2
        }, {
            'x': cx4,
            'y': cy2
        }, {
            'x': cx2,
            'y': cy4
        }, {
            'x': cx2,
            'y': cy3
        }, {
            'x': cx3,
            'y': cy3
        }, {
            'x': cx3,
            'y': 0
        }]
        kicad_mod.append(
            PolygoneLine(polygone=crty_poly_tl_ch,
                         layer='F.CrtYd',
                         width=configuration['courtyard_line_width']))

        # ######################### Text Fields ###############################

        addTextFields(kicad_mod=kicad_mod,
                      configuration=configuration,
                      body_edges=body_edge,
                      courtyard={
                          'top': cy1,
                          'bottom': -cy1
                      },
                      fp_name=fp_name,
                      text_y_inside_position='center')

        ##################### Output and 3d model ############################

        kicad_mod.append(Model(filename=model_name))

        output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
        if not os.path.isdir(
                output_dir
        ):  #returns false if path does not yet exist!! (Does not check path validity)
            os.makedirs(output_dir)
        filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                            fp_name=fp_name)

        file_handler = KicadFileHandler(kicad_mod)
        file_handler.writeFile(filename)
def generate_one_footprint(pins, params, configuration):
    pad_silk_off = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2
    off = configuration['silk_fab_offset']

    mpn = params['mpn'].format(n=pins*number_of_rows)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)
    footprint_name += params['fp_name_suffix']

    kicad_mod = Footprint(footprint_name)
    desc_format_str = "Molex {:s}, {:s}{:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(desc_format_str.format(series_long, mpn, params['description'], pins, params['datasheet']))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))



    # Dimensions
    P = (pins - 1) * pitch
    B = P + 2*6.79 # connector length
    W = 11.53 # connector width

    TW = 1.85
    TL = 3.05

    body_edge={}
    body_edge['left'] = (P-B)/2
    body_edge['right'] = body_edge['left'] + B
    body_edge['top'] = -4.47 - offset_second_pad
    body_edge['bottom'] =  body_edge['top'] + W

    bounding_box = body_edge.copy()
    bounding_box['top'] = body_edge['top'] - TW

    ##################################  Pins ##################################
    kicad_mod.append(PadArray(pincount=pins, start=[0,0],
        x_spacing=pitch, size=pad_size, drill=drill,
        type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_THT))
    kicad_mod.append(PadArray(pincount=pins, start=[0, -offset_second_pad],
        x_spacing=pitch, size=pad_size, drill=drill,
        shape=Pad.SHAPE_RECT, type=Pad.TYPE_THT, layers=Pad.LAYERS_THT))

    d_small = 0.3
    s_small = d_small + 2*min_annular_ring
    thermal_to_pad_edge = s_small/2 + 0.15

    if params['thermals']:
        for xi in range(pins):
            n = xi + 1
            pad_center_y = -offset_second_pad/2
            pad_center_x = xi*pitch
            pad_h = offset_second_pad + pad_size[1]
            dx = (pad_size[0] - 2*thermal_to_pad_edge)/2
            dy = (pad_h - 2*thermal_to_pad_edge)/4

            #draw rectangle on F.Fab layer

            # kicad_mod.append(RectLine(
            #     start=[pad_center_x - pad_l/2, pad_center_y - pad_size[1]/2],
            #     end=[pad_center_x + pad_l/2, pad_center_y + pad_size[1]/2],
            #     layer='F.Fab', width=configuration['fab_line_width']))

            kicad_mod.append(PadArray(center=[pad_center_x, pad_center_y],
                pincount=3, y_spacing=dy*2,
                drill=d_small, size=s_small, initial=n, increment=0,
                shape=Pad.SHAPE_CIRCLE, type=Pad.TYPE_THT, layers=Pad.LAYERS_THT))
            kicad_mod.append(PadArray(center=[pad_center_x - dx, pad_center_y],
                pincount=5, y_spacing=dy,
                drill=d_small, size=s_small, initial=n, increment=0,
                type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, layers=Pad.LAYERS_THT))
            kicad_mod.append(PadArray(center=[pad_center_x + dx, pad_center_y],
                pincount=5, y_spacing=dy,
                drill=d_small, size=s_small, initial=n, increment=0,
                type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, layers=Pad.LAYERS_THT))

    if params['lock']:
        kicad_mod.append(Pad(at=[-ret_dx, ret_dy], type=Pad.TYPE_THT,
            shape=Pad.SHAPE_CIRCLE, size=ret_size, drill=ret_drill, layers=Pad.LAYERS_THT))
        kicad_mod.append(Pad(at=[P+ret_dx, ret_dy], type=Pad.TYPE_THT,
            shape=Pad.SHAPE_CIRCLE, size=ret_size, drill=ret_drill, layers=Pad.LAYERS_THT))

    kicad_mod.append(RectLine(start=[-pad_size[0]/2, -offset_second_pad-pad_size[1]/2],
        end=[pad_size[0]/2,pad_size[1]/2],offset=pad_silk_off,
        width=configuration['silk_line_width'], layer='B.SilkS'))

    ############################ Outline ##############################
    #kicad_mod.append(RectLine(start=[xl1, yt1], end=[xr1, yb1], layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(RectLine(
        start=[body_edge['left'], body_edge['top']],
        end=[body_edge['right'], body_edge['bottom']],
        layer='F.Fab', width=configuration['fab_line_width']))

    tab = [
        {'x': P/2 - TL/2, 'y': body_edge['top']},
        {'x': P/2 - TL/2, 'y': body_edge['top'] - TW},
        {'x': P/2 + TL/2, 'y': body_edge['top'] - TW},
        {'x': P/2 + TL/2, 'y': body_edge['top']}
    ]
    kicad_mod.append(PolygoneLine(polygone=tab,
        layer='F.Fab', width=configuration['fab_line_width']))


    kicad_mod.append(RectLine(
        start=[body_edge['left'], body_edge['top']],
        end=[body_edge['right'], body_edge['bottom']],
        offset = off,
        layer='F.SilkS', width=configuration['silk_line_width']))

    tab = [
        {'x': P/2 - TL/2 - off, 'y': body_edge['top'] - off},
        {'x': P/2 - TL/2 - off, 'y': body_edge['top'] - TW - off},
        {'x': P/2 + TL/2 + off, 'y': body_edge['top'] - TW - off},
        {'x': P/2 + TL/2 + off, 'y': body_edge['top'] - off}
    ]
    kicad_mod.append(PolygoneLine(polygone=tab,
        layer='F.SilkS', width=configuration['silk_line_width']))


    ############################ Pin 1 ################################
    # Pin 1 designator
    pin1_sl = 2.4
    pin1 = [
        {'x': -pin1_sl/2, 'y': body_edge['top']},
        {'x': 0, 'y': body_edge['top'] + pin1_sl/sqrt(2)},
        {'x': pin1_sl/2, 'y': body_edge['top']}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin1,
        layer='F.Fab', width=configuration['fab_line_width']))

    pin1_sl = 0.8
    yp1 = body_edge['top'] - off - 0.3
    pin1 = [
    {'x': 0,'y': yp1},
    {'x': pin1_sl/2,'y': yp1-pin1_sl/sqrt(2)},
    {'x': -pin1_sl/2,'y': yp1-pin1_sl/sqrt(2)},
    {'x': 0,'y': yp1},
    ]

    kicad_mod.append(PolygoneLine(polygone=pin1, layer='F.SilkS', width=configuration['silk_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom'] + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pincount, configuration):
    mpn = part_code.format(n=pincount)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pincount//2, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Molex {:s}, {:s}, {:d} Pins ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, pincount, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    kicad_mod.setAttribute('smd')

    # calculate working values
    pad_x_spacing = pitch
    pad_y_spacing = 4.4 + 1.1
    pad_width = 0.3
    pad_height = 1.1
    pad_x_span = (pad_x_spacing * ((pincount / 2) - 1))

    h_body_width = 5.0 / 2.0
    h_body_length = (pad_x_span / 2.0) + 1.05 + 0.5

    fab_width = configuration['fab_line_width']

    #outline_x = 1.2
    outline_x = h_body_length - (pad_x_span / 2.0) - pad_width/2 - (configuration['silk_pad_clearance'] + configuration['silk_line_width']/2)
    marker_y = 0.8
    silk_width = configuration['silk_line_width']
    nudge = configuration['silk_fab_offset']

    courtyard_width = configuration['courtyard_line_width']
    courtyard_precision = configuration['courtyard_grid']
    courtyard_clearance = configuration['courtyard_offset']['connector']
    courtyard_x = roundToBase(h_body_length + courtyard_clearance, courtyard_precision)
    courtyard_y = roundToBase((pad_y_spacing + pad_height) / 2.0 + courtyard_clearance, courtyard_precision)

    # create pads
    kicad_mod.append(PadArray(pincount=pincount//2, x_spacing=pad_x_spacing, y_spacing=0,\
        center=[0,-pad_y_spacing/2.0], initial=1, increment=2, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, size=[pad_width, pad_height],\
        layers=Pad.LAYERS_SMT))
    kicad_mod.append(PadArray(pincount=pincount//2, x_spacing=pad_x_spacing, y_spacing=0,\
        center=[0,pad_y_spacing/2.0], initial=2, increment=2, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, size=[pad_width, pad_height],\
        layers=Pad.LAYERS_SMT))

    # create fab outline and pin 1 marker
    kicad_mod.append(RectLine(start=[-h_body_length, -h_body_width], end=[h_body_length, h_body_width], layer='F.Fab', width=fab_width))
    body_edge={
        'left':-h_body_length,
        'top':-h_body_width
    }
    body_edge['right'] = -body_edge['left']
    body_edge['bottom'] = -body_edge['top']
    kicad_mod.append(Line(start=[-h_body_length+outline_x, -h_body_width-nudge], end=[-h_body_length+outline_x, -h_body_width-marker_y], layer='F.Fab', width=fab_width))

    # create silkscreen outline and pin 1 marker
    left_outline = [[-h_body_length+outline_x, h_body_width+nudge], [-h_body_length-nudge, h_body_width+nudge], [-h_body_length-nudge, -h_body_width-nudge],\
                    [-h_body_length+outline_x, -h_body_width-nudge], [-h_body_length+outline_x, -h_body_width-marker_y]]
    right_outline = [[h_body_length-outline_x, h_body_width+nudge], [h_body_length+nudge, h_body_width+nudge], [h_body_length+nudge, -h_body_width-nudge],\
                     [h_body_length-outline_x, -h_body_width-nudge]]
    kicad_mod.append(PolygoneLine(polygone=left_outline, layer='F.SilkS', width=silk_width))
    kicad_mod.append(PolygoneLine(polygone=right_outline, layer='F.SilkS', width=silk_width))

    # create courtyard
    kicad_mod.append(RectLine(start=[-courtyard_x, -courtyard_y], end=[courtyard_x, courtyard_y], layer='F.CrtYd', width=courtyard_width))

    ######################### Text Fields ###############################

    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':-courtyard_y, 'bottom':+courtyard_y},
        fp_name=footprint_name, text_y_inside_position='center')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def make_module(pins_per_row, configuration):
    pad_silk_off = configuration['silk_line_width']/2 + configuration['silk_pad_clearance']
    off = configuration['silk_fab_offset']

    mpn = part_code.format(pins_per_row*2)

    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    footprint_name = footprint_name.replace("__",'_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Molex {:s}, {:s}, {:d} Circuits ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    Wi = 4.8
    T = 2.8
    W = Wi + T


    body_edge = {}
    body_edge['right'] = pitch_row + 2.2 + T
    body_edge['left'] = body_edge['right'] - W

    A = (pins_per_row-1)*pitch
    B = (A - 8) if A >= 8 else 0
    C = (A - 4.6) if A >= 4.6 else 0
    D = A + 2.6
    E = A + 3.6

    body_edge['top'] = -(E - A)/2
    body_edge['bottom'] = body_edge['top'] + E

    bounding_box = body_edge.copy()

    ############################## Pins ###############################
    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    for row_idx in range(2):
        kicad_mod.append(PadArray(
            initial=ROW_NAMES[row_idx]+'1', start=[(row_idx)*pitch_row, 0],
            y_spacing=pitch, pincount=pins_per_row, increment=incrementPadNumber,
            size=pad_size, drill=drill,
            type=Pad.TYPE_THT, shape=pad_shape, layers=Pad.LAYERS_THT,
            tht_pad1_id=ROW_NAMES[0]+'1',
            **optional_pad_params))

    ############################ Outline ##############################
    kicad_mod.append(RectLine(
        start=[body_edge['left'], body_edge['top']],
        end=[body_edge['right'], body_edge['bottom']],
        layer="F.Fab", width=configuration['fab_line_width']
    ))

    r_no_silk = max(pad_size)/2 + pad_silk_off
    dx = abs(body_edge['left']) + off
    pin_center_silk_y = 0 if dx >= r_no_silk else sqrt(r_no_silk**2-dx**2)
    pin1_center_silk_y = pad_size[1]/2 + pad_silk_off

    YCb = A/2+C/2
    YCt = A/2-C/2
    YBb = A/2+B/2


    poly_silk_b = [
        {'x': body_edge['left']-off, 'y': body_edge['bottom']+off},
        {'x': body_edge['right']+off, 'y': body_edge['bottom']+off},
        {'x': body_edge['right']+off, 'y': YCb},
    ]
    if C > 0:
        poly_silk_b.extend([
            {'x': body_edge['right']-T, 'y': YCb},
            {'x': body_edge['right']-T, 'y': A/2},
        ])
    kicad_mod.append(PolygoneLine(polygone=poly_silk_b,
        layer="F.SilkS", width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=poly_silk_b, y_mirror=A/2,
        layer="F.SilkS", width=configuration['silk_line_width']))


    if pin_center_silk_y == 0:
        kicad_mod.append(Line(
            start=[body_edge['left']-off, body_edge['top']],
            end=[body_edge['left']-off, body_edge['bottom']],
            layer="F.SilkS", width=configuration['silk_line_width']
        ))
    else:
        kicad_mod.append(Line(
            start=[body_edge['left']-off, body_edge['top']-off],
            end=[body_edge['left']-off, -pin1_center_silk_y],
            layer="F.SilkS", width=configuration['silk_line_width']
        ))
        kicad_mod.append(Line(
            start=[body_edge['left']-off, pin1_center_silk_y],
            end=[body_edge['left']-off, pitch-pin_center_silk_y],
            layer="F.SilkS", width=configuration['silk_line_width']
        ))
        kicad_mod.append(Line(
            start=[body_edge['left']-off, A+pin_center_silk_y],
            end=[body_edge['left']-off, body_edge['bottom']+off],
            layer="F.SilkS", width=configuration['silk_line_width']
        ))
        for i in range(1, pins_per_row-1):
            yt = i*pitch + pin_center_silk_y
            yb = (i+1)*pitch - pin_center_silk_y
            kicad_mod.append(Line(
                start=[body_edge['left']-off, yt],
                end=[body_edge['left']-off, yb],
                layer="F.SilkS", width=configuration['silk_line_width']
            ))

    x1 = body_edge['right']-T

    pin_w = 0.5
    pin_L = 2.7
    pin_chamfer_x = pin_w/3


    if B>0:
        x2 = x1 + 2 # estimated from drawing
        poly = [
            {'x': x2, 'y':YCb},
            {'x': x2, 'y':YBb+pin_w/2}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly,
            layer="F.SilkS", width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly, y_mirror=A/2,
            layer="F.SilkS", width=configuration['silk_line_width']))


    #pins
    if C>0:
        for i in range(pins_per_row):
            ypc = i*pitch

            x3 = x1 + pin_L
            x2 = x3 - pin_chamfer_x

            if ypc - pin_w/2 >= YCt and ypc + pin_w/2 <= YCb:
                pin_poly = [
                    {'x': x1, 'y': ypc-pin_w/2},
                    {'x': x2, 'y': ypc-pin_w/2},
                    {'x': x3, 'y': ypc},
                    {'x': x2, 'y': ypc+pin_w/2},
                    {'x': x1, 'y': ypc+pin_w/2}
                ]
                kicad_mod.append(PolygoneLine(polygone=pin_poly,
                    layer="F.SilkS", width=configuration['silk_line_width']))

    ########################### Pin 1 #################################

    p1s_sl = 2
    p1s_off = off + 0.3
    kicad_mod.append(PolygoneLine(
        polygone=[
            {'x': body_edge['left'] + p1s_sl, 'y': body_edge['top'] - p1s_off},
            {'x': body_edge['left'] - p1s_off, 'y': body_edge['top'] - p1s_off},
            {'x': body_edge['left'] - p1s_off, 'y': body_edge['top'] + p1s_sl}
        ], layer="F.SilkS", width=configuration['silk_line_width']))

    p1f_sl = 1
    kicad_mod.append(PolygoneLine(
        polygone=[
            {'x': body_edge['left'], 'y': p1f_sl/2},
            {'x': body_edge['left'] + p1f_sl/sqrt(2), 'y': 0},
            {'x': body_edge['left'], 'y': -p1f_sl/2}
        ], layer="F.Fab", width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')


    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)

    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #26
0
def generate_one_footprint(pins_per_row, variant_param, configuration):
    silk_pad_off = configuration['silk_pad_clearance']+configuration['silk_line_width']/2
    off = configuration['silk_fab_offset']

    number_of_rows = variant_param['number_of_rows']

    pad_size = [row - pad_to_pad_clearance, pitch - pad_to_pad_clearance]
    if number_of_rows == 1:
        pad_size[0] = drill + 2*max_annular_ring

    if pad_size[0] - drill < 2*min_annular_ring:
        pad_size[0] = drill + 2*min_annular_ring
    if pad_size[0] - drill > 2*max_annular_ring:
        pad_size[0] = drill + 2*max_annular_ring

    if pad_size[1] - drill < 2*min_annular_ring:
        pad_size[1] = drill + 2*min_annular_ring
    if pad_size[1] - drill > 2*max_annular_ring:
        pad_size[1] = drill + 2*max_annular_ring

    pad_shape = Pad.SHAPE_OVAL
    if pad_size[0] == pad_size[1]:
        pad_shape = Pad.SHAPE_CIRCLE

    first_to_last_pad_y = (pins_per_row-1)*pitch
    first_to_last_pad_x = (number_of_rows-1)*row

    peg_pos = [[0, -peg_to_nearest_pin if variant_param['style'] != 'in_line' else (first_to_last_pad_y + peg_to_nearest_pin)]]
    if variant_param['number_pegs'] == 2:
        peg_pos.append([0, first_to_last_pad_y + peg_to_nearest_pin])

    mpn = variant_param['part_code'][pins_per_row*number_of_rows].format(n=pins_per_row*2)

    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=man_short_fp_name,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    descr_format_str = "Molex {:s}, old mpn/engineering number: {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(descr_format_str.format(
        series_long, mpn, pins_per_row, datasheet))
    tags = configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=man_short_fp_name,
        entry=configuration['entry_direction'][orientation])
    kicad_mod.setTags(tags)

    x1 = -(variant_param['width']-first_to_last_pad_x)/2
    x2 = x1 + variant_param['width']
    body_lenght = (9.83-pitch)+first_to_last_pad_y
    y1 = -(body_lenght - first_to_last_pad_y)/2
    y2 = y1 + body_lenght

    peg_predrusion = 2.591 # from 3d model
    peg_d = 3.94 # from 3d model, rounded
    peg_from_body = 0.66 # from 3d model
    peg_conn_w = 1.6 # from 3d model, rounded
    stabalizer_width = 2.54 # from 3d model
    stabalizer_len = 2.591 # from 3d model
    TW = 3 # from 3d model, rounded
    TL = 1.3 # from 3d model, rounded
    BW = 1.14 # from 3d model, rounded
    BL = 0.76 # from 3d model, rounded

    #calculate fp dimensions
    body_edge={
        'left':x1,
        'right':x2,
        'bottom':y2,
        'top': y1
        }
    bounding_box = {}
    if variant_param['style'] != 'in_line':
        bounding_box['top'] = peg_pos[0][1]-peg_drill/2
        bounding_box['left'] = body_edge['left'] - TL
        bounding_box['right'] = body_edge['right'] + BL
        if variant_param['number_pegs'] == 2:
            bounding_box['bottom'] = peg_pos[1][1]+peg_drill/2
        else:
            bounding_box['bottom'] = body_edge['bottom'] + peg_predrusion
    else:
        bounding_box['bottom'] = peg_pos[0][1]+peg_drill/2
        bounding_box['top'] = body_edge['top'] - TL
        bounding_box['left'] = body_edge['left'] - BL
        bounding_box['right'] = body_edge['right']


    #generate the pads
    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    for row_idx in range(variant_param['number_of_rows']):
        initial = row_idx*pins_per_row + 1
        kicad_mod.append(PadArray(
            pincount=pins_per_row, initial=initial, start=[row_idx*row, 0],
            y_spacing=pitch, type=Pad.TYPE_THT, shape=pad_shape,
            size=pad_size, drill=drill, layers=Pad.LAYERS_THT,
            **optional_pad_params))

    for peg in peg_pos:
        kicad_mod.append(Pad(at=peg, type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
            size=peg_drill, drill=peg_drill, layers=Pad.LAYERS_NPTH))


    #draw the outline of the shape
    kicad_mod.append(RectLine(start=[x1,y1],end=[x2,y2],
        layer='F.Fab',width=configuration['fab_line_width']))

    dy = peg_to_nearest_pin + body_edge['top'] - off
    if dy < (peg_drill/2 + silk_pad_off):
        dx = sqrt((peg_drill/2 + silk_pad_off)**2-dy**2)
    else:
        dx = 0

    sl_poly=[
        {'x': 0, 'y': body_edge['top']-off},
        {'x': body_edge['left']-off, 'y': body_edge['top']-off},
        {'x': body_edge['left']-off, 'y': body_edge['bottom']+off},
        {'x': 0, 'y': body_edge['bottom']+off},
    ]
    sr_poly=[
        {'x': 0, 'y': body_edge['top']-off},
        {'x': body_edge['right']+off, 'y': body_edge['top']-off},
        {'x': body_edge['right']+off, 'y': body_edge['bottom']+off},
        {'x': 0, 'y': body_edge['bottom']+off},
    ]
    if variant_param['style'] == 'in_line' or variant_param['number_pegs'] == 2:
        sl_poly[3]['x']=-dx
        sr_poly[3]['x']=dx
    if variant_param['style'] != 'in_line':
        sl_poly[0]['x']=-dx
        sr_poly[0]['x']=dx

    kicad_mod.append(PolygoneLine(polygone=sl_poly,
        layer='F.SilkS', width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=sr_poly,
        layer='F.SilkS', width=configuration['silk_line_width']))

    def peg_outline(kicad_mod, center_y):
        edge = body_edge['top'] if center_y < 0 else body_edge['bottom']
        dir = -1 if center_y < 0 else 1
        sy=edge + dir*peg_from_body
        y3 = edge +dir*peg_predrusion
        kicad_mod.append(Line(
            start=[peg_conn_w/2, edge],
            end=[peg_conn_w/2, sy],
            layer='F.Fab',width=configuration['fab_line_width']
        ))
        kicad_mod.append(Line(
            start=[-peg_conn_w/2, edge],
            end=[-peg_conn_w/2, sy],
            layer='F.Fab',width=configuration['fab_line_width']
        ))
        dy = center_y - sy
        sx = sqrt((peg_d/2)**2-dy**2)
        dy2 = y3 - center_y
        ex = sqrt((peg_d/2)**2-dy2**2)
        a1 = degrees(asin(abs(dy2)/(peg_d/2)))
        a2 = degrees(asin(abs(dy)/(peg_d/2)))
        a = a1+a2
        kicad_mod.append(Line(
            start=[sx, sy], end=[-sx, sy],
            layer='F.Fab',width=configuration['fab_line_width']
        ))
        kicad_mod.append(Line(
            start=[ex, y3], end=[-ex, y3],
            layer='F.Fab',width=configuration['fab_line_width']
        ))
        kicad_mod.append(Arc(center=[0,center_y],
            start=[sx,sy], angle=dir*a,
            layer='F.Fab', width=configuration['fab_line_width']))
        kicad_mod.append(Arc(center=[0,center_y],
            start=[-sx,sy], angle=-a*dir,
            layer='F.Fab', width=configuration['fab_line_width']))
    #
    #draw the outline of the tab
    if variant_param['style'] == 'in_line':
        tab_poly = [
            {'x': -TW/2,'y': body_edge['top']},
            {'x': -TW/2,'y': body_edge['top']-TL},
            {'x': TW/2,'y': body_edge['top']-TL},
            {'x': TW/2,'y': body_edge['top']},
        ]
        kicad_mod.append(PolygoneLine(polygone=tab_poly,
            layer='F.Fab', width=configuration['fab_line_width']))
        tab_poly = [
            {'x': -TW/2-off,'y': body_edge['top']-off},
            {'x': -TW/2-off,'y': body_edge['top']-TL-off},
            {'x': TW/2+off,'y': body_edge['top']-TL-off},
            {'x': TW/2+off,'y': body_edge['top']-off},
        ]
        kicad_mod.append(PolygoneLine(polygone=tab_poly,
            layer='F.SilkS', width=configuration['silk_line_width']))
        b_poly = [
            {'x': body_edge['left'],'y': body_edge['top']},
            {'x': body_edge['left']-BL,'y': body_edge['top']},
            {'x': body_edge['left']-BL,'y': body_edge['top']+BW},
            {'x': body_edge['left'],'y': body_edge['top']+BW},
        ]
        kicad_mod.append(PolygoneLine(polygone=b_poly,
            layer='F.Fab', width=configuration['fab_line_width']))
        b_poly = [
            {'x': body_edge['left']-off,'y': body_edge['top']-off},
            {'x': body_edge['left']-BL-off,'y': body_edge['top']-off},
            {'x': body_edge['left']-BL-off,'y': body_edge['top']+BW+off},
            {'x': body_edge['left']-off,'y': body_edge['top']+BW+off},
        ]
        kicad_mod.append(PolygoneLine(polygone=b_poly,
            layer='F.SilkS', width=configuration['silk_line_width']))
        for i in range(pins_per_row):
            yc = i*pitch+pitch/2
            b_poly = [
                {'x': body_edge['left'],'y': yc - BW/2},
                {'x': body_edge['left']-BL,'y': yc - BW/2},
                {'x': body_edge['left']-BL,'y': yc + BW/2},
                {'x': body_edge['left'],'y': yc + BW/2},
            ]
            kicad_mod.append(PolygoneLine(polygone=b_poly,
                layer='F.Fab', width=configuration['fab_line_width']))
            b_poly = [
                {'x': body_edge['left']-off,'y': yc - BW/2-off},
                {'x': body_edge['left']-BL-off,'y': yc - BW/2-off},
                {'x': body_edge['left']-BL-off,'y': yc + BW/2+off},
                {'x': body_edge['left']-off,'y': yc + BW/2+off},
            ]
            kicad_mod.append(PolygoneLine(polygone=b_poly,
                layer='F.SilkS', width=configuration['silk_line_width']))
    else:
        cy = first_to_last_pad_y/2
        tab_poly = [
            {'x': body_edge['left'],'y': cy-TW/2},
            {'x': body_edge['left']-TL,'y': cy-TW/2},
            {'x': body_edge['left']-TL,'y': cy+TW/2},
            {'x': body_edge['left'],'y': cy+TW/2},
        ]
        kicad_mod.append(PolygoneLine(polygone=tab_poly,
            layer='F.Fab', width=configuration['fab_line_width']))

        tab_poly = [
            {'x': body_edge['left']-off,'y': cy-TW/2-off},
            {'x': body_edge['left']-TL-off,'y': cy-TW/2-off},
            {'x': body_edge['left']-TL-off,'y': cy+TW/2+off},
            {'x': body_edge['left']-off,'y': cy+TW/2+off},
        ]
        kicad_mod.append(PolygoneLine(polygone=tab_poly,
            layer='F.SilkS', width=configuration['silk_line_width']))

        b_poly = [
            {'x': body_edge['right'],'y': body_edge['top']},
            {'x': body_edge['right']+BL,'y': body_edge['top']},
            {'x': body_edge['right']+BL,'y': body_edge['top']+BW},
            {'x': body_edge['right'],'y': body_edge['top']+BW},
        ]
        kicad_mod.append(PolygoneLine(polygone=b_poly,
            layer='F.Fab', width=configuration['fab_line_width']))

        b_poly = [
            {'x': body_edge['right']+off,'y': body_edge['top']-off},
            {'x': body_edge['right']+BL+off,'y': body_edge['top']-off},
            {'x': body_edge['right']+BL+off,'y': body_edge['top']+BW+off},
            {'x': body_edge['right']+off,'y': body_edge['top']+BW+off},
        ]
        kicad_mod.append(PolygoneLine(polygone=b_poly,
            layer='F.SilkS', width=configuration['silk_line_width']))
        if len(peg_pos) == 1:
            center_stabalizer = (number_of_rows-1)*row
            stab_x1 = center_stabalizer - stabalizer_width/2
            stab_x2 = center_stabalizer + stabalizer_width/2
            stab_y1 = body_edge['bottom'] + stabalizer_len
            stab_poly = [
                {'x': stab_x1,'y': body_edge['bottom']},
                {'x': stab_x1,'y': stab_y1},
                {'x': stab_x2,'y': stab_y1},
                {'x': stab_x2,'y': body_edge['bottom']}
            ]
            kicad_mod.append(PolygoneLine(polygone=stab_poly,
                layer='F.Fab', width=configuration['fab_line_width']))
            stab_poly = [
                {'x': stab_x1-off,'y': body_edge['bottom']+off},
                {'x': stab_x1-off,'y': stab_y1+off},
                {'x': stab_x2+off,'y': stab_y1+off},
                {'x': stab_x2+off,'y': body_edge['bottom']+off}
            ]
            kicad_mod.append(PolygoneLine(polygone=stab_poly,
                layer='F.SilkS', width=configuration['silk_line_width']))

        for i in range(pins_per_row):
            yc = i*pitch+pitch/2
            b_poly = [
                {'x': body_edge['right'],'y': yc - BW/2},
                {'x': body_edge['right']+BL,'y': yc - BW/2},
                {'x': body_edge['right']+BL,'y': yc + BW/2},
                {'x': body_edge['right'],'y': yc + BW/2},
            ]
            kicad_mod.append(PolygoneLine(polygone=b_poly,
                layer='F.Fab', width=configuration['fab_line_width']))

            b_poly = [
                {'x': body_edge['right']+off,'y': yc - BW/2-off},
                {'x': body_edge['right']+BL+off,'y': yc - BW/2-off},
                {'x': body_edge['right']+BL+off,'y': yc + BW/2+off},
                {'x': body_edge['right']+off,'y': yc + BW/2+off},
            ]
            kicad_mod.append(PolygoneLine(polygone=b_poly,
                layer='F.SilkS', width=configuration['silk_line_width']))

    for peg in peg_pos:
        peg_outline(kicad_mod, peg[1])



    if variant_param['style'] != 'in_line':
        L = 2.5
        O = off + 0.3
        dy = peg_to_nearest_pin + body_edge['top'] - O
        if dy < (peg_drill/2 + silk_pad_off):
            dx = sqrt((peg_drill/2 + silk_pad_off)**2-dy**2)

        pin = [
            {'x': -dx,'y': body_edge['top'] - O},
            {'x': body_edge['left'] - O,'y': body_edge['top'] - O},
            {'x': body_edge['left'] - O,'y': body_edge['top'] + L}
        ]
    else:
        sl = 0.6
        xs = body_edge['left']-(off + 0.3)
        pin = [
            {'x': xs,'y': 0},
            {'x': xs - sl/sqrt(2),'y': sl/2},
            {'x': xs - sl/sqrt(2),'y': -sl/2},
            {'x': xs,'y': 0}
        ]


    kicad_mod.append(PolygoneLine(polygone=pin, layer="F.SilkS", width=configuration['silk_line_width']))

    sl = 2
    pin = [
        {'x': body_edge['left'],'y': -sl/2},
        {'x': body_edge['left'] +sl/sqrt(2),'y': 0},
        {'x': body_edge['left'],'y': sl/2}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin, width=configuration['fab_line_width'], layer='F.Fab'))

    ########################### CrtYd #################################
    CrtYd_offset = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']

    cx1 = roundToBase(bounding_box['left'] - CrtYd_offset, CrtYd_grid)
    cy1 = roundToBase(bounding_box['top'] - CrtYd_offset, CrtYd_grid)

    cx2 = roundToBase(bounding_box['right'] + CrtYd_offset, CrtYd_grid)
    cy2 = roundToBase(bounding_box['bottom'] + CrtYd_offset, CrtYd_grid)

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='right')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=man_lib)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, variant, configuration):
    V=variant_params[variant]['V']
    #calculate fp dimensions
    A = (pins - 1) * pitch
    B = A + 4.9

    #Thickness of connector
    T = 11.5

    #corners
    x1 = -2.45
    x2 = x1 + B

    x_mid = (x1 + x2) / 2

    y2 = V
    y1= y2 - T


    #y at which the plastic tabs end
    y3 = y2 - 7

    #generate the name
    mpn = part_base.format(n=pins, variant=variant)
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pincount, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator".format(series, mpn, datasheet))

    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))


    if pins == 2:
        drill = 1.0
    else:
        drill = 0.95

    pad_size = [pitch - pad_to_pad_clearance, drill + 2*pad_copper_y_solder_length]
    if pad_size[0] - drill < 2*min_annular_ring:
        pad_size[0] = drill + 2*min_annular_ring

    #generate the pads
    ############################# Pads ##################################
    # kicad_mod.append(Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    #                     at=[0, 0], size=pad_size,
    #                     drill=drill, layers=Pad.LAYERS_THT))

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(initial=1, start=[0, 0],
        x_spacing=pitch, pincount=pincount,
        size=pad_size, drill=drill,
        type=Pad.TYPE_THT, shape=Pad.SHAPE_OVAL, layers=Pad.LAYERS_THT,
        **optional_pad_params))

    #draw the courtyard
    cx1 = roundToBase(x1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(y1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(x2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(y2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    #offset the outline around the connector
    off = configuration['silk_fab_offset']

    xo1 = x1 - off
    yo1 = y1 - off

    xo2 = x2 + off
    yo2 = y2 + off

    #thickness of the notches
    notch = 1.5

    #wall thickness of the outline
    wall = 1.2

    #draw the outline of the connector
    outline = [
    {'x': x_mid,'y': yo2},
    {'x': xo1,'y': yo2},
    {'x': xo1,'y': yo1},
    {'x': xo1+wall+2*off,'y': yo1},
    {'x': xo1+wall+2*off,'y': y3 - off},
    {'x': A/2,'y': y3 - off},
    #{'x': -1.1,'y': y3 + off}
    ]
    if variant == 'A-1':
        outline = outline[:-1]
    kicad_mod.append(PolygoneLine(polygone=outline, layer='F.SilkS', width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=outline, x_mirror=x_mid, layer='F.SilkS', width=configuration['silk_line_width']))

    outline = [
    {'x': x_mid,'y': y2},
    {'x': x1,'y': y2},
    {'x': x1,'y': y1},
    {'x': x1+wall,'y': y1},
    {'x': x1+wall,'y': y3},
    {'x': A/2,'y': y3},
    #{'x': -1.1,'y': y3 + off}
    ]
    kicad_mod.append(PolygoneLine(polygone=outline, layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(PolygoneLine(polygone=outline, x_mirror=x_mid, layer='F.Fab', width=configuration['fab_line_width']))


    #draw the pinsss
    for i in range(pins):

        x = i * pitch
        w = 0.25
        kicad_mod.append(RectLine(start=[x-w,y3+1], end=[x+w,y2-0.5], layer='F.SilkS', width=configuration['silk_line_width']))

    #add pin-1 designator
    px = 0
    py = -1.5
    m = 0.3

    pin1 = [
    {'x': px,'y': py},
    {'x': px-m,'y': py-2*m},
    {'x': px+m,'y': py-2*m},
    {'x': px,'y': py},
    ]

    kicad_mod.append(PolygoneLine(polygone=pin1, layer='F.SilkS', width=configuration['silk_line_width']))
    if fab_pin1_marker_type == 1:
        kicad_mod.append(PolygoneLine(polygone=pin1, layer='F.Fab', width=configuration['fab_line_width']))

    if fab_pin1_marker_type == 2:
        fab_marker_left = -fab_first_marker_w/2.0
        fab_marker_bottom = y3 - fab_first_marker_h
        poly_fab_marker = [
            {'x':fab_marker_left, 'y':y3},
            {'x':0, 'y':fab_marker_bottom},
            {'x':fab_marker_left + fab_first_marker_w, 'y':y3}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_fab_marker, layer='F.Fab', width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    text_center_y = 'center'
    body_edge={'left':x1, 'right':x2, 'top':y1, 'bottom':y2}
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position=text_center_y)


    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #28
0
def generate_one_footprint(pins, configuration):
    silk_pad_clearance = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2
    mpn = part_base.format(n=pins)
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator"
        .format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #calculate fp dimensions
    A = (pins - 1) * pitch
    B = A + 3.9

    #coordinate locations
    # y1 x1 x3                x4 x2
    # y2 | |                   | |
    # y3 | |1||2||3||4||5||6||7| |
    # y4 |_|                  |__|
    #      |                  |
    # y5   |__________________|
    # y6   || || || || || || ||

    #generate pads
    pad_size = [
        pitch - pad_to_pad_clearance, drill + 2 * pad_copper_y_solder_length
    ]
    if pad_size[0] - drill < 2 * min_annular_ring:
        pad_size[0] = drill + 2 * min_annular_ring

    if pad_size[0] - drill > 2 * pad_copper_y_solder_length:
        pad_size[0] = drill + 2 * pad_copper_y_solder_length

    shape = Pad.SHAPE_OVAL
    if pad_size[0] == pad_size[1]:
        shape = Pad.SHAPE_CIRCLE

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(
        PadArray(pincount=pins,
                 x_spacing=pitch,
                 type=Pad.TYPE_THT,
                 shape=shape,
                 size=pad_size,
                 drill=drill,
                 layers=Pad.LAYERS_THT,
                 **optional_pad_params))

    #draw the component outline
    x1 = A / 2 - B / 2
    x2 = x1 + B
    x3 = -0.9
    x4 = pitch * (pins - 1) + 0.9
    y6 = 13.4
    y4 = y6 - 7.7
    y1 = y4 - 7.7
    y2 = y1 + 2
    y3 = y1 + 4.5
    y5 = y3 + 9.4

    body_edge = {'left': x1, 'right': x2, 'top': y4, 'bottom': y5}

    #draw shroud outline on F.Fab layer
    kicad_mod.append(
        RectLine(start=[x3, y3],
                 end=[x4, y5],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x4 - 0.2,
            'y': y3
        }, {
            'x': x4 - 0.2,
            'y': y1
        }, {
            'x': x2,
            'y': y1
        }, {
            'x': x2,
            'y': y4
        }, {
            'x': x4,
            'y': y4
        }],
                     layer='F.Fab',
                     width=configuration['fab_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x3,
            'y': y4
        }, {
            'x': x1,
            'y': y4
        }, {
            'x': x1,
            'y': y1
        }, {
            'x': x3 + 0.2,
            'y': y1
        }, {
            'x': x3 + 0.2,
            'y': y3
        }],
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(x1 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy1 = roundToBase(y1 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    cx2 = roundToBase(x2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy2 = roundToBase(y6 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    #draw pin outlines and plastic between pins on F.Fab (pin width is 1.4mm, so 0.7mm is half the pin width)
    for pin in range(pins):
        kicad_mod.append(
            PolygoneLine(polygone=[{
                'x': pin * pitch - 0.7,
                'y': y5
            }, {
                'x': pin * pitch - 0.7,
                'y': y6
            }, {
                'x': pin * pitch + 0.7,
                'y': y6
            }, {
                'x': pin * pitch + 0.7,
                'y': y5
            }],
                         layer='F.Fab',
                         width=configuration['fab_line_width']))
        if pin < (pins - 1):
            kicad_mod.append(
                PolygoneLine(polygone=[{
                    'x': pin * pitch + 1.38,
                    'y': y3
                }, {
                    'x': pin * pitch + 1.38,
                    'y': y2
                }, {
                    'x': pin * pitch + 2.58,
                    'y': y2
                }, {
                    'x': pin * pitch + 2.58,
                    'y': y3
                }],
                             layer='F.Fab',
                             width=configuration['fab_line_width']))

    #draw pin1 mark on F.Fab
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': -0.8,
            'y': y3
        }, {
            'x': 0,
            'y': y3 + 0.8
        }, {
            'x': 0.8,
            'y': y3
        }],
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    #draw silk outlines
    off = configuration['silk_fab_offset']
    x1 -= off
    y1 -= off
    x2 += off
    y2 -= off
    x3 -= off
    y3 -= off
    x4 += off
    y4 += off
    y5 += off
    y6 += off

    p1s_x = pad_size[0] / 2 + silk_pad_clearance
    p1s_y = pad_size[1] / 2 + silk_pad_clearance

    #silk around shroud; silk around stabilizers; silk long shroud between pin and shroud for first and last pins
    #note that half of pin width is 0.7mm, so adding 0.12mm silk offset gives 0.82mm about pin center; 0.44 is double silk offset in caeses where 'off' is in the wrong direction
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x3,
            'y': y4
        }, {
            'x': x3,
            'y': y5
        }, {
            'x': -0.82,
            'y': y5
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x4 - 0.44,
            'y': -1.6
        }, {
            'x': x4 - 0.44,
            'y': y1
        }, {
            'x': x2,
            'y': y1
        }, {
            'x': x2,
            'y': y4
        }, {
            'x': x4,
            'y': y4
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x4 - 0.44,
            'y': y3
        }, {
            'x': x4 - 0.44,
            'y': 1.6
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x3,
            'y': y4
        }, {
            'x': x1,
            'y': y4
        }, {
            'x': x1,
            'y': y1
        }, {
            'x': x3 + 0.44,
            'y': y1
        }, {
            'x': x3 + 0.44,
            'y': -p1s_y
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x3 + 0.44,
            'y': 1.7
        }, {
            'x': x3 + 0.44,
            'y': y3
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': (pins - 1) * pitch + 0.82,
            'y': y5
        }, {
            'x': x4,
            'y': y5
        }, {
            'x': x4,
            'y': y4
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': -0.58,
            'y': y3
        }, {
            'x': 1.26,
            'y': y3
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': pin * pitch - 1.26,
            'y': y3
        }, {
            'x': pin * pitch + 0.58,
            'y': y3
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    #per-pin silk
    #pin silk
    for pin in range(pins):
        kicad_mod.append(
            PolygoneLine(polygone=[{
                'x': pin * pitch - 0.82,
                'y': y5
            }, {
                'x': pin * pitch - 0.82,
                'y': y6
            }, {
                'x': pin * pitch + 0.82,
                'y': y6
            }, {
                'x': pin * pitch + 0.82,
                'y': y5
            }],
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))
        #silk around plastic between pins 1 and 2 (since pin 1 is rectangular, it seends to be handled a bit differently to meet ~0.2mm pin-silk clearance)
        if pin == 0:
            kicad_mod.append(
                PolygoneLine(polygone=[{
                    'x': pin * pitch + 1.26,
                    'y': y3
                }, {
                    'x': pin * pitch + 1.26,
                    'y': 1.7
                }],
                             layer='F.SilkS',
                             width=configuration['silk_line_width']))
            kicad_mod.append(
                PolygoneLine(polygone=[{
                    'x': pin * pitch + pad_size[0] / 2 + silk_pad_clearance,
                    'y': y2
                }, {
                    'x':
                    (pin + 1) * pitch - pad_size[0] / 2 - silk_pad_clearance,
                    'y':
                    y2
                }],
                             layer='F.SilkS',
                             width=configuration['silk_line_width']))
            kicad_mod.append(
                PolygoneLine(polygone=[{
                    'x': pin * pitch + 2.7,
                    'y': 1
                }, {
                    'x': pin * pitch + 2.7,
                    'y': y3
                }],
                             layer='F.SilkS',
                             width=configuration['silk_line_width']))
        #silk around plastic between other pins; silk along shroud between pin and shroud for other pins
        if (pin > 0) and (pin < (pins - 1)):
            kicad_mod.append(
                PolygoneLine(polygone=[{
                    'x': pin * pitch + 1.26,
                    'y': y3
                }, {
                    'x': pin * pitch + 1.26,
                    'y': 1
                }],
                             layer='F.SilkS',
                             width=configuration['silk_line_width']))
            kicad_mod.append(
                PolygoneLine(polygone=[{
                    'x': pin * pitch + pad_size[0] / 2 + silk_pad_clearance,
                    'y': y2
                }, {
                    'x':
                    (pin + 1) * pitch - pad_size[0] / 2 - silk_pad_clearance,
                    'y':
                    y2
                }],
                             layer='F.SilkS',
                             width=configuration['silk_line_width']))
            kicad_mod.append(
                PolygoneLine(polygone=[{
                    'x': pin * pitch + 2.7,
                    'y': 1
                }, {
                    'x': pin * pitch + 2.7,
                    'y': y3
                }],
                             layer='F.SilkS',
                             width=configuration['silk_line_width']))
            kicad_mod.append(
                PolygoneLine(polygone=[{
                    'x': pin * pitch - 1.26,
                    'y': y3
                }, {
                    'x': pin * pitch + 1.26,
                    'y': y3
                }],
                             layer='F.SilkS',
                             width=configuration['silk_line_width']))
        #silk between pins at locking end of shroud
        if (pin > 0) and (pin < pins):
            kicad_mod.append(
                PolygoneLine(polygone=[{
                    'x': pin * pitch - 3.14,
                    'y': y5
                }, {
                    'x': pin * pitch - 0.82,
                    'y': y5
                }],
                             layer='F.SilkS'))

    #add pin1 marker on F.FilkS (magic numbers intended to hit ~0.3mm copper-silk clearance)

    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': 0,
            'y': -p1s_y
        }, {
            'x': -p1s_x,
            'y': -p1s_y
        }, {
            'x': -p1s_x,
            'y': 0
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pincount, configuration):
    mpn = "S{pincount}B-EH".format(pincount=pincount) #JST part number format string
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pincount, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator".format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    if pincount == 2:
        drill = 1.0
    else:
        drill = 0.95

    pad_size = [pitch - pad_to_pad_clearance, drill + 2*pad_copper_y_solder_length]
    if pad_size[0] - drill < 2*min_annular_ring:
        pad_size[0] = drill + 2*min_annular_ring

    # create pads
    # kicad_mod.append(Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    #                     at=[0, 0], size=pad_size,
    #                     drill=drill, layers=Pad.LAYERS_THT))

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(initial=1, start=[0, 0],
        x_spacing=pitch, pincount=pincount,
        size=pad_size, drill=drill,
        type=Pad.TYPE_THT, shape=Pad.SHAPE_OVAL, layers=Pad.LAYERS_THT,
        **optional_pad_params))

    A = (pincount - 1) * pitch
    B = A + 5.0

    x1 = -2.5
    y1 = -6.7
    x2 = x1 + B
    y21 = y1 + 6
    y2 = 1.5
    x11 = x1+1
    x21 = x2-1
    body_edge={'left':x1, 'right':x2, 'top':y1, 'bottom':y2}

    #draw the main outline around the footprint
    # kicad_mod.append(RectLine(start={'x':x1,'y':y1}, end={'x':x2,'y':y2}, layer='F.Fab', width=configuration['fab_line_width']))
    fab_outline=[
        {'x': x11, 'y': y21},
        {'x': x11, 'y': y2},
        {'x': x1, 'y': y2},
        {'x': x1, 'y': y1},
        {'x': x2, 'y': y1},
        {'x': x2, 'y': y2},
        {'x': x21, 'y': y2},
        {'x': x21, 'y': y21},
        {'x': x11, 'y': y21}
    ]
    kicad_mod.append(PolygoneLine(polygone=fab_outline,
        layer='F.Fab', width=configuration['fab_line_width']))
    ########################### CrtYd #################################
    cx1 = roundToBase(x1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(y1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(x2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(y2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ########################### SilkS #################################

    #line offset
    off = configuration['silk_fab_offset']

    x1 -= off
    y1 -= off

    x2 += off
    y2 += off


    T = 1 + 2*configuration['silk_fab_offset']

    y3 = y21 + off

    kicad_mod.append(PolygoneLine(polygone=[{'x':x1+T,'y':y3},
                               {'x':x1+T,'y':y2},
                               {'x':x1,'y':y2},
                               {'x':x1,'y':y1},
                               {'x':x2,'y':y1},
                               {'x':x2,'y':y2},
                               {'x':x2-T,'y':y2},
                               {'x':x2-T,'y':y3}], layer='F.SilkS', width=configuration['silk_line_width']))

    kicad_mod.append(PolygoneLine(polygone=[{'x':x1,'y':y1+T},
                               {'x':x1+T,'y':y1+T},
                               {'x':x1+T,'y':y3},
                               {'x':x1,'y':y3}], layer='F.SilkS', width=configuration['silk_line_width']))

    kicad_mod.append(PolygoneLine(polygone=[{'x':x2,'y':y1+T},
                           {'x':x2-T,'y':y1+T},
                           {'x':x2-T,'y':y3},
                           {'x':x2,'y':y3}], layer='F.SilkS', width=configuration['silk_line_width']))



    #add pictures of pins
    #pin-width w
    #pin-length l
    w = 0.32
    l = 3.5

    py = y3-1

    kicad_mod.append(Line(start={'x':x1+T,'y':py},end={'x':x2-T,'y':py}, layer='F.SilkS', width=configuration['silk_line_width']))

    # kicad_mod.append(Line(start={'x':x1+T,'y':py+1},end={'x':x2-T,'y':py+1}, layer='F.SilkS', width=configuration['silk_line_width']))
    pcs_x = pad_size[0]/2 + configuration['silk_pad_clearance'] + configuration['silk_line_width']
    for p in range(pincount):

        px = p * pitch

        kicad_mod.append(PolygoneLine(polygone=[{'x': px,'y': py},
                                   {'x': px-w,'y': py},
                                   {'x': px-w,'y': py-l+0.25*w},
                                   {'x': px,'y': py-l},
                                   {'x': px+w,'y': py-l+0.25*w},
                                   {'x': px+w,'y': py},
                                   {'x': px,'y': py}], layer='F.SilkS', width=configuration['silk_line_width']))

        if p < pincount-1:
            kicad_mod.append(Line(start=[px + pcs_x, y3], end=[px + pitch - pcs_x, y3],
                layer='F.SilkS', width=configuration['silk_line_width']))

    ######################### Pin 1 marker ##############################

    xm = 0
    ym = 1.5

    m = 0.3

    pin = [{'x':xm,'y':ym},
           {'x':xm - m,'y':ym + 2 * m},
           {'x':xm + m,'y':ym + 2 * m},
           {'x':xm,'y':ym}]
    kicad_mod.append(PolygoneLine(polygone=pin, layer='F.SilkS', width=configuration['silk_line_width']))

    sl = 1
    pin = [
        {'x':xm-sl/2,'y':y21},
        {'x':xm,'y':y21-sl/sqrt(2)},
        {'x':xm+sl/2,'y':y21}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin,layer='F.Fab', width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='center')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #30
0
    def generateFootprint(self, device_params):
        device_dimensions = LGA.deviceDimensions(device_params)
        size_x = device_dimensions['body_size_x'].nominal
        size_y = device_dimensions['body_size_y'].nominal
        with_thermal_vias = device_dimensions[
            'has_EP'] and 'thermal_vias' in device_params

        fab_line_width = self.configuration.get('fab_line_width', 0.1)
        silk_line_width = self.configuration.get('silk_line_width', 0.12)

        lib_name = self.configuration['lib_name_format_string'].format(
            category=category)

        pincount = device_params['num_pins_x'] * 2 + device_params[
            'num_pins_y'] * 2

        ipc_reference = 'ipc_spec_flat_no_lead_pull_back'

        used_density = device_params.get('ipc_density', ipc_density)
        ipc_data_set = self.ipc_defintions[ipc_reference][used_density]
        ipc_round_base = self.ipc_defintions[ipc_reference]['round_base']

        pad_details = self.calcPadDetails(device_dimensions, ipc_data_set,
                                          ipc_round_base)

        suffix = device_params.get('suffix', '').format(
            pad_x=pad_details['left']['size'][0],
            pad_y=pad_details['left']['size'][1])
        suffix_3d = suffix if device_params.get('include_suffix_in_3dpath',
                                                'True') == 'True' else ""

        model3d_path_prefix = self.configuration.get('3d_model_prefix',
                                                     '${KISYS3DMOD}')
        name_format = self.configuration[
            'fp_name_lga_format_string_no_trailing_zero']

        if device_dimensions['has_EP']:
            name_format = self.configuration[
                'fp_name_EP_format_string_no_trailing_zero']
            EP_size = {
                'x': device_dimensions['EP_size_x'].nominal,
                'y': device_dimensions['EP_size_y'].nominal
            }
            EP_center = {
                'x': device_dimensions['EP_center_x'].nominal,
                'y': device_dimensions['EP_center_y'].nominal
            }

        if device_params['num_pins_x'] == 0 or device_params['num_pins_y'] == 0:
            layout = ''
        else:
            layout = self.configuration['lga_layout_border'].format(
                nx=device_params['num_pins_x'], ny=device_params['num_pins_y'])

        fp_name = name_format.format(
            man=device_params.get('manufacturer', ''),
            mpn=device_params.get('part_number', ''),
            pkg=device_params['device_type'],
            pincount=pincount,
            size_y=size_y,
            size_x=size_x,
            ep_size_x=EP_size['x'],
            ep_size_y=EP_size['y'],
            pitch=device_params['pitch'],
            layout=layout,
            suffix=suffix,
            suffix2="",
            vias=self.configuration.get('thermal_via_suffix', '_ThermalVias')
            if with_thermal_vias else '').replace('__', '_').lstrip('_')

        fp_name_2 = name_format.format(
            man=device_params.get('manufacturer', ''),
            mpn=device_params.get('part_number', ''),
            pkg=device_params['device_type'],
            pincount=pincount,
            size_y=size_y,
            size_x=size_x,
            ep_size_x=EP_size['x'],
            ep_size_y=EP_size['y'],
            pitch=device_params['pitch'],
            layout=layout,
            suffix=suffix_3d,
            suffix2="",
            vias='').replace('__', '_').lstrip('_')

        model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'\
            .format(
                model3d_path_prefix=model3d_path_prefix, lib_name=lib_name,
                fp_name=fp_name_2)
        #print(fp_name)
        #print(pad_details)

        kicad_mod = Footprint(fp_name)

        # init kicad footprint
        kicad_mod.setDescription(
            "{manufacturer} {mpn} {package}, {pincount} Pin ({datasheet}), generated with kicad-footprint-generator {scriptname}"\
            .format(
                manufacturer = device_params.get('manufacturer',''),
                package = device_params['device_type'],
                mpn = device_params.get('part_number',''),
                pincount = pincount,
                datasheet = device_params['size_source'],
                scriptname = os.path.basename(__file__).replace("  ", " ")
                ).lstrip())

        kicad_mod.setTags(self.configuration['keyword_fp_string']\
            .format(
                man=device_params.get('manufacturer',''),
                package=device_params['device_type'],
                category=category
            ).lstrip())
        kicad_mod.setAttribute('smd')

        pad_shape_details = {}
        pad_shape_details['shape'] = Pad.SHAPE_ROUNDRECT
        pad_shape_details['radius_ratio'] = configuration.get(
            'round_rect_radius_ratio', 0)
        if 'round_rect_max_radius' in configuration:
            pad_shape_details['maximum_radius'] = configuration[
                'round_rect_max_radius']

        if device_dimensions['has_EP']:
            if with_thermal_vias:
                thermals = device_params['thermal_vias']
                paste_coverage = thermals.get(
                    'EP_paste_coverage',
                    device_params.get('EP_paste_coverage',
                                      DEFAULT_PASTE_COVERAGE))

                kicad_mod.append(
                    ExposedPad(
                        number=pincount + 1,
                        size=EP_size,
                        at=EP_center,
                        paste_layout=thermals.get(
                            'EP_num_paste_pads',
                            device_params.get('EP_num_paste_pads', 1)),
                        paste_coverage=paste_coverage,
                        via_layout=thermals.get('count', 0),
                        paste_between_vias=thermals.get('paste_between_vias'),
                        paste_rings_outside=thermals.get(
                            'paste_rings_outside'),
                        via_drill=thermals.get('drill', 0.3),
                        via_grid=thermals.get('grid'),
                        paste_avoid_via=thermals.get('paste_avoid_via', True),
                        via_paste_clarance=thermals.get(
                            'paste_via_clearance',
                            DEFAULT_VIA_PASTE_CLEARANCE),
                        min_annular_ring=thermals.get(
                            'min_annular_ring', DEFAULT_MIN_ANNULAR_RING),
                        bottom_pad_min_size=thermals.get('bottom_min_size', 0),
                        kicad4_compatible=args.kicad4_compatible,
                        **pad_shape_details))
            else:
                kicad_mod.append(
                    ExposedPad(number=pincount + 1,
                               size=EP_size,
                               at=EP_center,
                               paste_layout=device_params.get(
                                   'EP_num_paste_pads', 1),
                               paste_coverage=device_params.get(
                                   'EP_paste_coverage',
                                   DEFAULT_PASTE_COVERAGE),
                               kicad4_compatible=args.kicad4_compatible,
                               **pad_shape_details))

        init = 1
        if device_params['num_pins_x'] == 0:
            kicad_mod.append(
                PadArray(initial=init,
                         type=Pad.TYPE_SMT,
                         layers=Pad.LAYERS_SMT,
                         pincount=device_params['num_pins_y'],
                         x_spacing=0,
                         y_spacing=device_params['pitch'],
                         **pad_details['left'],
                         **pad_shape_details))
            init += device_params['num_pins_y']
            kicad_mod.append(
                PadArray(initial=init,
                         type=Pad.TYPE_SMT,
                         layers=Pad.LAYERS_SMT,
                         pincount=device_params['num_pins_y'],
                         x_spacing=0,
                         y_spacing=-device_params['pitch'],
                         **pad_details['right'],
                         **pad_shape_details))
        elif device_params['num_pins_y'] == 0:
            #for devices with clockwise numbering
            kicad_mod.append(
                PadArray(initial=init,
                         type=Pad.TYPE_SMT,
                         layers=Pad.LAYERS_SMT,
                         pincount=device_params['num_pins_x'],
                         y_spacing=0,
                         x_spacing=device_params['pitch'],
                         **pad_details['top'],
                         **pad_shape_details))
            init += device_params['num_pins_x']
            kicad_mod.append(
                PadArray(initial=init,
                         type=Pad.TYPE_SMT,
                         layers=Pad.LAYERS_SMT,
                         pincount=device_params['num_pins_x'],
                         y_spacing=0,
                         x_spacing=-device_params['pitch'],
                         **pad_details['bottom'],
                         **pad_shape_details))
        else:
            chamfer_size = device_params.get('chamfer_edge_pins')
            corner_first = [0, 1, 0, 0]
            corner_last = [0, 0, 1, 0]

            kicad_mod.append(
                PadArray(initial=init,
                         type=Pad.TYPE_SMT,
                         layers=Pad.LAYERS_SMT,
                         pincount=device_params['num_pins_y'],
                         x_spacing=0,
                         y_spacing=device_params['pitch'],
                         chamfer_size=chamfer_size,
                         chamfer_corner_selection_first=corner_first,
                         chamfer_corner_selection_last=corner_last,
                         **pad_details['left'],
                         **pad_shape_details))

            init += device_params['num_pins_y']
            corner_first = [1, 0, 0, 0]
            corner_last = [0, 1, 0, 0]
            kicad_mod.append(
                PadArray(initial=init,
                         type=Pad.TYPE_SMT,
                         layers=Pad.LAYERS_SMT,
                         pincount=device_params['num_pins_x'],
                         y_spacing=0,
                         x_spacing=device_params['pitch'],
                         chamfer_size=chamfer_size,
                         chamfer_corner_selection_first=corner_first,
                         chamfer_corner_selection_last=corner_last,
                         **pad_details['bottom'],
                         **pad_shape_details))

            init += device_params['num_pins_x']
            corner_first = [0, 0, 0, 1]
            corner_last = [1, 0, 0, 0]
            kicad_mod.append(
                PadArray(initial=init,
                         type=Pad.TYPE_SMT,
                         layers=Pad.LAYERS_SMT,
                         pincount=device_params['num_pins_y'],
                         x_spacing=0,
                         y_spacing=-device_params['pitch'],
                         chamfer_size=chamfer_size,
                         chamfer_corner_selection_first=corner_first,
                         chamfer_corner_selection_last=corner_last,
                         **pad_details['right'],
                         **pad_shape_details))

            init += device_params['num_pins_y']
            corner_first = [0, 0, 1, 0]
            corner_last = [0, 0, 0, 1]
            kicad_mod.append(
                PadArray(initial=init,
                         type=Pad.TYPE_SMT,
                         layers=Pad.LAYERS_SMT,
                         pincount=device_params['num_pins_x'],
                         y_spacing=0,
                         x_spacing=-device_params['pitch'],
                         chamfer_size=chamfer_size,
                         chamfer_corner_selection_first=corner_first,
                         chamfer_corner_selection_last=corner_last,
                         **pad_details['top'],
                         **pad_shape_details))

        body_edge = {
            'left': -size_x / 2,
            'right': size_x / 2,
            'top': -size_y / 2,
            'bottom': size_y / 2
        }

        bounding_box = body_edge

        pad_width = pad_details['top']['size'][0]

        # ############################ SilkS ##################################

        silk_pad_offset = configuration[
            'silk_pad_clearance'] + configuration['silk_line_width'] / 2
        silk_offset = configuration['silk_fab_offset']
        if device_params['num_pins_x'] == 0:
            kicad_mod.append(
                Line(start={
                    'x': 0,
                    'y': body_edge['top'] - silk_offset
                },
                     end={
                         'x': body_edge['right'],
                         'y': body_edge['top'] - silk_offset
                     },
                     width=configuration['silk_line_width'],
                     layer="F.SilkS",
                     x_mirror=0))
            kicad_mod.append(
                Line(start={
                    'x': body_edge['left'],
                    'y': body_edge['bottom'] + silk_offset
                },
                     end={
                         'x': body_edge['right'],
                         'y': body_edge['bottom'] + silk_offset
                     },
                     width=configuration['silk_line_width'],
                     layer="F.SilkS",
                     x_mirror=0))
        elif device_params['num_pins_y'] == 0:
            kicad_mod.append(
                Line(start={
                    'y': 0,
                    'x': body_edge['left'] - silk_offset
                },
                     end={
                         'y': body_edge['bottom'],
                         'x': body_edge['left'] - silk_offset
                     },
                     width=configuration['silk_line_width'],
                     layer="F.SilkS",
                     x_mirror=0))
            kicad_mod.append(
                Line(start={
                    'y': body_edge['top'],
                    'x': body_edge['right'] + silk_offset
                },
                     end={
                         'y': body_edge['bottom'],
                         'x': body_edge['right'] + silk_offset
                     },
                     width=configuration['silk_line_width'],
                     layer="F.SilkS",
                     x_mirror=0))
        else:
            sx1 = -(device_params['pitch'] *
                    (device_params['num_pins_x'] - 1) / 2.0 + pad_width / 2.0 +
                    silk_pad_offset)

            sy1 = -(device_params['pitch'] *
                    (device_params['num_pins_y'] - 1) / 2.0 + pad_width / 2.0 +
                    silk_pad_offset)

            poly_silk = [{
                'x': sx1,
                'y': body_edge['top'] - silk_offset
            }, {
                'x': body_edge['left'] - silk_offset,
                'y': body_edge['top'] - silk_offset
            }, {
                'x': body_edge['left'] - silk_offset,
                'y': sy1
            }]
            kicad_mod.append(
                PolygoneLine(polygone=poly_silk,
                             width=configuration['silk_line_width'],
                             layer="F.SilkS",
                             x_mirror=0))
            kicad_mod.append(
                PolygoneLine(polygone=poly_silk,
                             width=configuration['silk_line_width'],
                             layer="F.SilkS",
                             y_mirror=0))
            kicad_mod.append(
                PolygoneLine(polygone=poly_silk,
                             width=configuration['silk_line_width'],
                             layer="F.SilkS",
                             x_mirror=0,
                             y_mirror=0))

        # # ######################## Fabrication Layer ###########################

        fab_bevel_size = min(
            configuration['fab_bevel_size_absolute'],
            configuration['fab_bevel_size_relative'] * min(size_x, size_y))

        poly_fab = [
            {
                'x': body_edge['left'] + fab_bevel_size,
                'y': body_edge['top']
            },
            {
                'x': body_edge['right'],
                'y': body_edge['top']
            },
            {
                'x': body_edge['right'],
                'y': body_edge['bottom']
            },
            {
                'x': body_edge['left'],
                'y': body_edge['bottom']
            },
            {
                'x': body_edge['left'],
                'y': body_edge['top'] + fab_bevel_size
            },
            {
                'x': body_edge['left'] + fab_bevel_size,
                'y': body_edge['top']
            },
        ]

        kicad_mod.append(
            PolygoneLine(polygone=poly_fab,
                         width=configuration['fab_line_width'],
                         layer="F.Fab"))

        # # ############################ CrtYd ##################################

        off = ipc_data_set['courtyard']
        grid = configuration['courtyard_grid']

        cy1 = roundToBase(bounding_box['top'] - off, grid)

        kicad_mod.append(
            RectLine(start={
                'x': roundToBase(bounding_box['left'] - off, grid),
                'y': cy1
            },
                     end={
                         'x': roundToBase(bounding_box['right'] + off, grid),
                         'y': roundToBase(bounding_box['bottom'] + off, grid)
                     },
                     width=configuration['courtyard_line_width'],
                     layer='F.CrtYd'))

        # ######################### Text Fields ###############################

        addTextFields(kicad_mod=kicad_mod,
                      configuration=configuration,
                      body_edges=body_edge,
                      courtyard={
                          'top': cy1,
                          'bottom': -cy1
                      },
                      fp_name=fp_name,
                      text_y_inside_position='center')

        ##################### Output and 3d model ############################

        kicad_mod.append(Model(filename=model_name))

        output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
        if not os.path.isdir(
                output_dir
        ):  #returns false if path does not yet exist!! (Does not check path validity)
            os.makedirs(output_dir)
        filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                            fp_name=fp_name)

        file_handler = KicadFileHandler(kicad_mod)
        file_handler.writeFile(filename)
def generate_one_footprint(model, params, configuration):

    subseries, connector_style = params.series_name.split('-')
    pitch_mpn = ''
    if params.pin_pitch == 5.08:
        pitch_mpn = '-5,08'
    elif params.pin_pitch == 7.62:
        pitch_mpn = '-7,62'
    lib_series = 'GMSTB' if params.pin_pitch >= 7.5 else 'MSTB'
    lib_name = configuration['lib_name_format_str'].format(series=lib_series,
        style=series[1], pitch=params.pin_pitch, suffix='')
    mpn = configuration['mpn_format_string'].format(subseries=subseries, style = connector_style,
        rating=series[1], num_pins=params.num_pins, pitch=pitch_mpn)
    footprint_name = configuration['fp_name_format_string'].format(man = configuration['manufacturer'], series = series[0], mpn = mpn, num_rows = 1,
        num_pins = params.num_pins, mounting_pad = "", pitch = params.pin_pitch,
        orientation = configuration['orientation_str'][1] if params.angled else configuration['orientation_str'][0],
        flanged = configuration['flanged_str'][1] if params.flanged else configuration['flanged_str'][0],
        mount_hole = configuration['mount_hole_str'][1] if params.mount_hole else configuration['mount_hole_str'][0])

    length, width, upper_to_pin, left_to_pin, mount_hole_left, mount_hole_right, inner_len = dimensions(params)

    body_top_left=[left_to_pin,upper_to_pin]
    body_bottom_right=v_add(body_top_left,[length,width])

    body_edge={
        'left': body_top_left[0],
        'top': body_top_left[1],
        'right': body_bottom_right[0],
        'bottom': body_bottom_right[1],
    }

    silk_top_left=v_offset(body_top_left, configuration['silk_fab_offset'])
    silk_bottom_right=v_offset(body_bottom_right, configuration['silk_fab_offset'])

    center_x = (params.num_pins-1)/2.0*params.pin_pitch
    kicad_mod = Footprint(footprint_name)

    mpn = configuration['mpn_format_string_description'].format(subseries=subseries, style = connector_style,
        rating=series[1], num_pins=params.num_pins, pitch=pitch_mpn)
    kicad_mod.setDescription(generate_description(params, mpn))
    kicad_mod.setTags(configuration['keywords_format_string'].format(mpn=mpn, param_name=model,
        order_info = ', '.join(params.order_info)))


    ################################################# Pads #################################################
    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(initial=1, start=[0, 0],
        x_spacing=params.pin_pitch, pincount=params.num_pins,
        size=[params.pin_Sx, params.pin_Sy], drill=seriesParams.drill,
        type=Pad.TYPE_THT, shape=Pad.SHAPE_OVAL, layers=configuration['pin_layers'],
        **optional_pad_params))

    if params.mount_hole:
        kicad_mod.append(Pad(number='""', type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
                            at=mount_hole_left, size=[seriesParams.mount_drill, seriesParams.mount_drill], \
                            drill=seriesParams.mount_drill, layers=configuration['mount_hole_layers']))
        kicad_mod.append(Pad(number='""', type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
                            at=mount_hole_right, size=[seriesParams.mount_drill, seriesParams.mount_drill], \
                            drill=seriesParams.mount_drill, layers=configuration['mount_hole_layers']))
    #add an outline around the pins

    ################################################# Silk and Fab #################################################
    kicad_mod.append(RectLine(start=silk_top_left, end=silk_bottom_right, layer='F.SilkS', width=configuration['silk_line_width']))
    if configuration['with_fab_layer']:
        kicad_mod.append(RectLine(start=body_top_left, end=body_bottom_right, layer='F.Fab', width=configuration['fab_line_width']))
    if params.angled:
        lock_poly=[
            {'x':-1, 'y':0},
            {'x':1, 'y':0},
            {'x':1.5/2, 'y':-1.5},
            {'x':-1.5/2, 'y':-1.5},
            {'x':-1, 'y':0}
        ]
        lock_poly_fab=[
            {'x':-1, 'y':-configuration['silk_fab_offset']},
            {'x':1, 'y':-configuration['silk_fab_offset']},
            {'x':1.5/2, 'y':-1.5},
            {'x':-1.5/2, 'y':-1.5},
            {'x':-1, 'y':-configuration['silk_fab_offset']}
        ]
        kicad_mod.append(RectLine(start=[silk_top_left[0],silk_bottom_right[1]-1.5], end=[silk_bottom_right[0], silk_bottom_right[1]-1.5-1.8], layer='F.SilkS', width=configuration['silk_line_width']))
        if configuration['inner_details_on_fab']:
            kicad_mod.append(RectLine(start=[body_top_left[0],silk_bottom_right[1]-1.5], end=[body_bottom_right[0], silk_bottom_right[1]-1.5-1.8],
                layer='F.Fab', width=configuration['fab_line_width']))
        if params.flanged:
            lock_translation = Translation(mount_hole_left[0], silk_bottom_right[1])
            lock_translation.append(PolygoneLine(polygone=lock_poly, layer='F.SilkS', width=configuration['silk_line_width']))
            if configuration['inner_details_on_fab']:
                lock_translation.append(PolygoneLine(polygone=lock_poly_fab, layer='F.Fab', width=configuration['fab_line_width']))
            kicad_mod.append(lock_translation)
            lock_translation = Translation(mount_hole_right[0], silk_bottom_right[1])
            lock_translation.append(PolygoneLine(polygone=lock_poly, layer='F.SilkS', width=configuration['silk_line_width']))
            if configuration['inner_details_on_fab']:
                lock_translation.append(PolygoneLine(polygone=lock_poly_fab, layer='F.Fab', width=configuration['fab_line_width']))
            kicad_mod.append(lock_translation)

        for i in range(params.num_pins):
            lock_translation = Translation(i*params.pin_pitch, silk_bottom_right[1])
            lock_translation.append(PolygoneLine(polygone=lock_poly, layer='F.SilkS', width=configuration['silk_line_width']))
            if configuration['inner_details_on_fab']:
                lock_translation.append(PolygoneLine(polygone=lock_poly_fab, layer='F.Fab', width=configuration['fab_line_width']))
            kicad_mod.append(lock_translation)
    else:
        inner_width = 5.3 #measured

        pi1 = [body_top_left[0]+(length-inner_len)/2.0, body_top_left[1]+1.7] # 1.7mm measured
        top_thickness = pi1[1]-silk_top_left[1]
        pi2 = [body_bottom_right[0]-(length-inner_len)/2.0, pi1[1]+inner_width]
        #kicad_mod.append(RectLine(start=pi1, end=pi2, layer='F.SilkS'))

        first_center = params.pin_pitch/2.0
        line_len = params.pin_pitch-2
        outher_line_len = (-left_to_pin-1 + mount_hole_left[0]) if params.flanged else (-left_to_pin-1)
        kicad_mod.append(Line(start=[silk_top_left[0], pi1[1]-1], end=[silk_top_left[0]+outher_line_len, pi1[1]-1], layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(Line(start=[silk_bottom_right[0], pi1[1]-1], end=[silk_bottom_right[0]-outher_line_len, pi1[1]-1], layer='F.SilkS', width=configuration['silk_line_width']))
        if configuration['inner_details_on_fab']:
            kicad_mod.append(Line(start=[body_top_left[0], pi1[1]-1], end=[body_top_left[0]+outher_line_len, pi1[1]-1], layer='F.Fab', width=configuration['fab_line_width']))
            kicad_mod.append(Line(start=[body_bottom_right[0], pi1[1]-1], end=[body_bottom_right[0]-outher_line_len, pi1[1]-1], layer='F.Fab', width=configuration['fab_line_width']))

        for i in range(params.num_pins -1):
            chamfer_edge = Translation(i*params.pin_pitch, pi1[1]-1)
            chamfer_edge.append(Line(start=[first_center-line_len/2.0, 0], end=[first_center+line_len/2.0, 0], layer='F.SilkS', width=configuration['silk_line_width']))
            if configuration['inner_details_on_fab']:
                chamfer_edge.append(Line(start=[first_center-line_len/2.0, 0], end=[first_center+line_len/2.0, 0], layer='F.Fab', width=configuration['fab_line_width']))
            kicad_mod.append(chamfer_edge)

        flanged_line_left = (mount_hole_left[0]+1)
        lock_rect_silk={'start':[-1,0], 'end':[1,-top_thickness], 'layer':'F.SilkS', 'width':configuration['silk_line_width']}
        lock_rect_fab={'start':[-1,0], 'end':[1,-top_thickness+configuration['silk_fab_offset']], 'layer':'F.Fab', 'width':configuration['fab_line_width']}
        if params.flanged:
            lock_translation = Translation(mount_hole_left[0], pi1[1])
            lock_translation.append(RectLine(**lock_rect_silk))
            if configuration['inner_details_on_fab']:
                lock_translation.append(RectLine(**lock_rect_fab))
            kicad_mod.append(lock_translation)
            lock_translation = Translation(mount_hole_right[0], pi1[1])
            lock_translation.append(RectLine(**lock_rect_silk))
            if configuration['inner_details_on_fab']:
                lock_translation.append(RectLine(**lock_rect_fab))
            kicad_mod.append(lock_translation)

            chamfer_edge = Translation(0, pi1[1]-1)
            chamfer_edge.append(Line(start=[flanged_line_left, 0], end=[-1, 0], layer='F.SilkS', width=configuration['silk_line_width']))
            if configuration['inner_details_on_fab']:
                chamfer_edge.append(Line(start=[flanged_line_left, 0], end=[-1, 0], layer='F.Fab', width=configuration['fab_line_width']))
            kicad_mod.append(chamfer_edge)
            chamfer_edge = Translation((params.num_pins-1)*params.pin_pitch+params.mount_hole_to_pin, pi1[1]-1)
            chamfer_edge.append(Line(start=[flanged_line_left, 0], end=[-1, 0], layer='F.SilkS', width=configuration['silk_line_width']))
            if configuration['inner_details_on_fab']:
                chamfer_edge.append(Line(start=[flanged_line_left, 0], end=[-1, 0], layer='F.Fab', width=configuration['fab_line_width']))
            kicad_mod.append(chamfer_edge)


        for i in range(params.num_pins):
            lock_translation = Translation(i*params.pin_pitch, pi1[1])
            lock_translation.append(RectLine(**lock_rect_silk))
            if configuration['inner_details_on_fab']:
                lock_translation.append(RectLine(**lock_rect_fab))
            kicad_mod.append(lock_translation)

        if params.flanged:
            kicad_mod.append(Circle(center=mount_hole_left, radius=1.9, layer='F.SilkS', width=configuration['silk_line_width']))
            kicad_mod.append(Circle(center=mount_hole_right, radius=1.9, layer='F.SilkS', width=configuration['silk_line_width']))
            if not params.mount_hole:
                kicad_mod.append(Circle(center=mount_hole_left, radius=1, layer='F.SilkS', width=configuration['silk_line_width']))
                kicad_mod.append(Circle(center=mount_hole_right, radius=1, layer='F.SilkS', width=configuration['silk_line_width']))

            if configuration['inner_details_on_fab']:
                kicad_mod.append(Circle(center=mount_hole_left, radius=1.9, layer='F.Fab', width=configuration['fab_line_width']))
                kicad_mod.append(Circle(center=mount_hole_right, radius=1.9, layer='F.Fab', width=configuration['fab_line_width']))
                kicad_mod.append(Circle(center=mount_hole_left, radius=1, layer='F.Fab', width=configuration['fab_line_width']))
                kicad_mod.append(Circle(center=mount_hole_right, radius=1, layer='F.Fab', width=configuration['fab_line_width']))

        angle = -100.5
        arc_width = 4.0
        for i in range(params.num_pins):
            plug_arc = Translation(i*params.pin_pitch,0)
            plug_arc.append(Arc(start=[-arc_width/2.0,pi2[1]], center=[0,0.55], angle=angle, layer='F.SilkS', width=configuration['silk_line_width']))
            if configuration['inner_details_on_fab']:
                plug_arc.append(Arc(start=[-arc_width/2.0,pi2[1]], center=[0,0.55], angle=angle, layer='F.Fab', width=configuration['fab_line_width']))
            kicad_mod.append(plug_arc)

        for i in range(params.num_pins-1):
            lower_line = Translation(i*params.pin_pitch,pi2[1])
            lower_line.append(Line(start=[arc_width/2.0, 0], end=[params.pin_pitch-arc_width/2.0, 0], layer='F.SilkS', width=configuration['silk_line_width']))
            if configuration['inner_details_on_fab']:
                lower_line.append(Line(start=[arc_width/2.0, 0], end=[params.pin_pitch-arc_width/2.0, 0], layer='F.Fab', width=configuration['fab_line_width']))
            kicad_mod.append(lower_line)

        arc_to_side = pi1[0]+arc_width/2.0
        poly=[
            {'x':pi1[0]-arc_to_side, 'y':pi2[1]},
            {'x':pi1[0], 'y':pi2[1]},
            {'x':pi1[0], 'y':pi1[1]},
            {'x':pi2[0], 'y':pi1[1]},
            {'x':pi2[0], 'y':pi2[1]},
            {'x':pi2[0]+arc_to_side, 'y':pi2[1]}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly))
        if configuration['inner_details_on_fab']:
            kicad_mod.append(PolygoneLine(polygone=poly, layer='F.Fab', width=configuration['fab_line_width']))


    if params.mount_hole:
        kicad_mod.append(Circle(center=mount_hole_left, radius=seriesParams.mount_screw_head_r+configuration['silk_fab_offset'], layer='B.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(Circle(center=mount_hole_right, radius=seriesParams.mount_screw_head_r+configuration['silk_fab_offset'], layer='B.SilkS', width=configuration['silk_line_width']))

        kicad_mod.append(Circle(center=mount_hole_right, radius=seriesParams.mount_screw_head_r, layer='B.Fab', width=configuration['fab_line_width']))
        kicad_mod.append(Circle(center=mount_hole_left, radius=seriesParams.mount_screw_head_r, layer='B.Fab', width=configuration['fab_line_width']))

    ################################################## Courtyard ##################################################
    #if params.angled:
        #p1=[p1[0],-seriesParams.pin_Sy/2]
    crtyd_top_left=v_offset(body_top_left, configuration['courtyard_offset']['connector'])
    crtyd_bottom_right=v_offset(body_bottom_right, configuration['courtyard_offset']['connector'])
    kicad_mod.append(RectLine(start=round_crty_point(crtyd_top_left, configuration['courtyard_grid']), end=round_crty_point(crtyd_bottom_right, configuration['courtyard_grid']), layer='F.CrtYd'))

    if params.mount_hole and configuration['courtyard_for_mountscrews']:
        kicad_mod.append(Circle(center=mount_hole_right, radius=seriesParams.mount_screw_head_r+configuration['courtyard_offset']['connector'], layer='B.CrtYd', width=configuration['courtyard_line_width']))
        kicad_mod.append(Circle(center=mount_hole_left, radius=seriesParams.mount_screw_head_r+configuration['courtyard_offset']['connector'], layer='B.CrtYd', width=configuration['courtyard_line_width']))

    ################################################# Text Fields #################################################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':crtyd_top_left[1], 'bottom':crtyd_bottom_right[1]}, fp_name=footprint_name, text_y_inside_position='top')

    ################################################# Pin 1 Marker #################################################
    if not params.angled:
        kicad_mod.append(PolygoneLine(polygone=create_pin1_marker_triangle(silk_top_left[1]-0.2),
            layer='F.SilkS', width=configuration['silk_line_width']))
        if configuration['with_fab_layer']:
            kicad_mod.append(PolygoneLine(
                polygone=create_pin1_marker_triangle(bottom_y = -params.pin_Sy/2- 0.75,
                    dimensions = [1, 1], with_top_line = True),
                layer='F.Fab', width=configuration['fab_line_width']))
    else:
        y_bottom_silk_marker = (silk_top_left[1] if silk_top_left[1] < -params.pin_Sy/2 else -params.pin_Sy/2) - 0.2
        kicad_mod.append(PolygoneLine(polygone=create_pin1_marker_triangle(y_bottom_silk_marker),
            layer='F.SilkS', width=configuration['silk_line_width']))
        if configuration['with_fab_layer']:
            kicad_mod.append(PolygoneLine(
                polygone=create_pin1_marker_triangle(bottom_y = -0.5,
                    dimensions = [1.9, -body_top_left[1]-0.5], with_top_line = False),
                layer='F.Fab', width=configuration['fab_line_width']))

    #################################################### 3d file ###################################################
    p3dname = '{prefix:s}{lib_name:s}.3dshapes/{fp_name}.wrl'.format(prefix = configuration.get('3d_model_prefix', '${KISYS3DMOD}/'), lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=p3dname,
                           at=[0, 0, 0], scale=[1, 1, 1], rotate=[0, 0, 0]))

    file_handler = KicadFileHandler(kicad_mod)
    out_dir = '{:s}.pretty/'.format(lib_name)
    if not os.path.exists(out_dir):
        os.makedirs(out_dir)
    file_handler.writeFile('{:s}.pretty/{:s}.kicad_mod'.format(lib_name, footprint_name))
def generate_one_footprint(idx, pins, configuration):
    mpn = part_code.format(n=pins, param_1=mpn_param_1[idx])
    pad_silk_off = configuration['silk_line_width'] / 2 + configuration[
        'silk_pad_clearance']
    off = configuration['silk_fab_offset']
    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins,
        mounting_pad="-1MP",
        pitch=pitch,
        orientation=orientation_str)

    footprint_name = footprint_name.replace("__", '_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setAttribute('smd')
    kicad_mod.setDescription(
        "{:s} {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
        .format(manufacturer, series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    A = (pins - 1) * pitch
    B = A + 2 * rel_body_edge_x
    pad_y = -rel_pad_y_outside_edge / 2 + pad_size[1] / 2
    mpad_y = rel_pad_y_outside_edge / 2 - mp_size[1] / 2
    mpad_x = A / 2 + center_pad_to_mounting_pad_edge + mp_size[0] / 2

    kicad_mod.append(
        Pad(number=configuration['mounting_pad_number'],
            type=Pad.TYPE_SMT,
            shape=Pad.SHAPE_RECT,
            at=[mpad_x, mpad_y],
            size=mp_size,
            layers=Pad.LAYERS_SMT))
    kicad_mod.append(
        Pad(number=configuration['mounting_pad_number'],
            type=Pad.TYPE_SMT,
            shape=Pad.SHAPE_RECT,
            at=[-mpad_x, mpad_y],
            size=mp_size,
            layers=Pad.LAYERS_SMT))

    # create pads
    #createNumberedPadsTHT(kicad_mod, pincount, pitch, drill, {'x':x_dia, 'y':y_dia})
    kicad_mod.append(
        PadArray(center=[0, pad_y],
                 pincount=pins,
                 x_spacing=pitch,
                 type=Pad.TYPE_SMT,
                 shape=Pad.SHAPE_RECT,
                 size=pad_size,
                 layers=Pad.LAYERS_SMT))

    x1 = -B / 2
    x2 = x1 + B
    y2 = mpad_y + mp_size[1] / 2 + rel_body_edge_y
    y1 = y2 - body_size_y

    body_edge = {'left': x1, 'right': x2, 'bottom': y2, 'top': y1}

    bounding_box = body_edge.copy()
    bounding_box['top'] = pad_y - pad_size[1] / 2
    bb_x = mpad_x + mp_size[0] / 2
    if bb_x > x2:
        bounding_box['left'] = -bb_x
        bounding_box['right'] = bb_x

    kicad_mod.append(
        RectLine(start={
            'x': x1,
            'y': y1
        },
                 end={
                     'x': x2,
                     'y': y2
                 },
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    #line offset
    off = 0.1

    x1 -= off
    y1 -= off

    x2 += off
    y2 += off

    #draw the main outline around the footprint
    silk_pad_x_left = -A / 2 - pad_size[0] / 2 - pad_silk_off
    silk_mp_top = mpad_y - mp_size[1] / 2 - pad_silk_off
    silk_mp_bottom = mpad_y + mp_size[1] / 2 + pad_silk_off
    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': silk_pad_x_left,
            'y': y1
        }, {
            'x': x1,
            'y': y1
        }, {
            'x': x1,
            'y': silk_mp_top
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': -silk_pad_x_left,
            'y': y1
        }, {
            'x': x2,
            'y': y1
        }, {
            'x': x2,
            'y': silk_mp_top
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    kicad_mod.append(
        PolygoneLine(polygone=[{
            'x': x1,
            'y': silk_mp_bottom
        }, {
            'x': x1,
            'y': y2
        }, {
            'x': x2,
            'y': y2
        }, {
            'x': x2,
            'y': silk_mp_bottom
        }],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    #add pin-1 marker

    kicad_mod.append(
        Line(start=[silk_pad_x_left, y1],
             end=[silk_pad_x_left, pad_y - pad_size[1] / 2],
             layer='F.SilkS',
             width=configuration['silk_line_width']))

    sl = 1
    pin = [{
        'y': body_edge['top'],
        'x': -A / 2 - sl / 2
    }, {
        'y': body_edge['top'] + sl / sqrt(2),
        'x': -A / 2
    }, {
        'y': body_edge['top'],
        'x': -A / 2 + sl / 2
    }]
    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     width=configuration['fab_line_width'],
                     layer='F.Fab'))

    ########################### KEEPOUT #################################

    k_top = pad_y + pad_size[1] / 2 + 0.1
    k_size = [A + pad_size[0], 2.37]
    addRectangularKeepout(kicad_mod, [0, k_top + k_size[1] / 2], k_size)

    ########################### CrtYd #################################
    cx1 = roundToBase(
        bounding_box['left'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = roundToBase(
        bounding_box['top'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cx2 = roundToBase(
        bounding_box['right'] + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        bounding_box['bottom'] +
        configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pincount, configuration):
    silk_x_min = x_min - configuration['silk_fab_offset']
    silk_y_min = y_min - configuration['silk_fab_offset']
    silk_y_main_min = y_main_min - configuration['silk_fab_offset']
    silk_y_max = y_max + configuration['silk_fab_offset']

    x_mid = (pincount-1)*pitch/2.0
    x_max = (pincount-1)*pitch + 1.95
    silk_x_max = x_max + configuration['silk_fab_offset']

    pad_size = [pitch - pad_to_pad_clearance, drill_size + 2*pad_copper_y_solder_length]
    if pad_size[0] - drill_size < 2*min_annular_ring:
        pad_size[0] = drill_size + 2*min_annular_ring

    # Through-hole type shrouded header, Side entry type
    mpn = "S{n}B-PH-K".format(n=pincount) #JST part number format string

    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pincount, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator".format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    # create Silkscreen
    tmp_x1=x_min+body_back_protrusion_width+configuration['silk_fab_offset']
    tmp_x2=x_max-body_back_protrusion_width-configuration['silk_fab_offset']
    pad_silk_offset = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2
    poly_silk_outline= [
                    {'x':-pad_size[0]/2.0-pad_silk_offset, 'y':silk_y_main_min},
                    {'x':tmp_x1, 'y':silk_y_main_min},
                    {'x':tmp_x1, 'y':silk_y_min},
                    {'x':silk_x_min, 'y':silk_y_min},
                    {'x':silk_x_min, 'y':silk_y_max},
                    {'x':silk_x_max, 'y':silk_y_max},
                    {'x':silk_x_max, 'y':silk_y_min},
                    {'x':tmp_x2, 'y':silk_y_min},
                    {'x':tmp_x2, 'y':silk_y_main_min},
                    {'x':(pincount-1)*pitch+pad_size[0]/2.0+pad_silk_offset, 'y':silk_y_main_min}
    ]
    kicad_mod.append(PolygoneLine(polygone=poly_silk_outline, layer='F.SilkS', width=configuration['silk_line_width']))

    if configuration['allow_silk_below_part'] == 'tht' or configuration['allow_silk_below_part'] == 'both':
        poly_big_cutout=[{'x':0.5, 'y':silk_y_max}
                                  ,{'x':0.5, 'y':2}
                                  ,{'x':x_max-2.45, 'y':2}
                                  ,{'x':x_max-2.45, 'y':silk_y_max}]
        kicad_mod.append(PolygoneLine(polygone=poly_big_cutout, layer='F.SilkS', width=configuration['silk_line_width']))

        kicad_mod.append(Line(start=[silk_x_min, silk_y_main_min], end=[tmp_x1, silk_y_main_min], layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(Line(start=[silk_x_max, silk_y_main_min], end=[tmp_x2, silk_y_main_min], layer='F.SilkS', width=configuration['silk_line_width']))

        kicad_mod.append(RectLine(start=[-1.3, 2.5], end=[-0.3, 4.1],
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(RectLine(start=[(pincount-1)*pitch+1.3, 2.5], end=[(pincount-1)*pitch+0.3, 4.1],
            layer='F.SilkS', width=configuration['silk_line_width']))

        kicad_mod.append(Line(start=[-0.3, 4.1], end=[-0.3, silk_y_max],
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(Line(start=[-0.8, 4.1], end=[-0.8, silk_y_max],
            layer='F.SilkS', width=configuration['silk_line_width']))

    ########################### CrtYd ################################
    part_x_min = x_min
    part_x_max = x_max
    part_y_min = y_min
    part_y_max = y_max

    cx1 = roundToBase(part_x_min-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(part_y_min-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(part_x_max+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(part_y_max+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ########################### Fab Outline ################################
    tmp_x1=x_min+body_back_protrusion_width
    tmp_x2=x_max-body_back_protrusion_width
    poly_fab_outline= [
                    {'x':tmp_x1, 'y':y_main_min},
                    {'x':tmp_x1, 'y':y_min},
                    {'x':x_min, 'y':y_min},
                    {'x':x_min, 'y':y_max},
                    {'x':x_max, 'y':y_max},
                    {'x':x_max, 'y':y_min},
                    {'x':tmp_x2, 'y':y_min},
                    {'x':tmp_x2, 'y':y_main_min},
                    {'x':tmp_x1, 'y':y_main_min}
    ]
    kicad_mod.append(PolygoneLine(polygone=poly_fab_outline, layer='F.Fab', width=configuration['fab_line_width']))

    ############################# Pads ##################################
    # kicad_mod.append(Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    #                     at=[0, 0], size=pad_size,
    #                     drill=drill_size, layers=Pad.LAYERS_THT))

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(initial=1, start=[0, 0],
        x_spacing=pitch, pincount=pincount,
        size=pad_size, drill=drill_size,
        type=Pad.TYPE_THT, shape=Pad.SHAPE_OVAL, layers=Pad.LAYERS_THT,
        **optional_pad_params))


    ########################### Pin 1 marker ################################
    poly_pin1_marker = [
        {'x':0, 'y':-1.2},
        {'x':-0.4, 'y':-1.6},
        {'x':0.4, 'y':-1.6},
        {'x':0, 'y':-1.2}
    ]
    if silk_pin1_marker_type == 1:
        kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker, layer='F.SilkS', width=configuration['silk_line_width']))
    if silk_pin1_marker_type == 2:
        silk_pin1_marker_t2_x = -pad_size[0]/2.0-pad_silk_offset

        kicad_mod.append(Line(start=[silk_pin1_marker_t2_x, silk_y_main_min],
            end=[silk_pin1_marker_t2_x, -pad_size[1]/2.0-configuration['silk_pad_clearance']],layer='F.SilkS', width=configuration['silk_line_width']))

    if fab_pin1_marker_type == 1:
        kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker, layer='F.Fab', width=configuration['fab_line_width']))

    if fab_pin1_marker_type == 2:
        poly_pin1_marker_type2 = [
            {'x':-0.75, 'y':y_main_min},
            {'x':0, 'y':y_main_min+0.75},
            {'x':0.75, 'y':y_main_min}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker_type2, layer='F.Fab', width=configuration['fab_line_width']))

    if fab_pin1_marker_type == 3:
        fab_pin1_marker_t3_y = pad_size[1]/2.0
        poly_pin1_marker_type2 = [
            {'x':0, 'y':fab_pin1_marker_t3_y},
            {'x':-0.5, 'y':fab_pin1_marker_t3_y+0.5},
            {'x':0.5, 'y':fab_pin1_marker_t3_y+0.5},
            {'x':0, 'y':fab_pin1_marker_t3_y}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker_type2, layer='F.Fab', width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    text_center_y = 2.5
    body_edge={'left':part_x_min, 'right':part_x_max, 'top':part_y_min, 'bottom':part_y_max}
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position=text_center_y)


    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #34
0
    def __createFootprintVariant(self, device_params, header, dimensions,
                                 with_thermal_vias):
        fab_line_width = self.configuration.get('fab_line_width', 0.1)
        silk_line_width = self.configuration.get('silk_line_width', 0.12)

        lib_name = self.configuration['lib_name_format_string'].format(
            category=header['library_Suffix'])

        size_x = dimensions['body_size_x'].nominal
        size_y = dimensions['body_size_y'].nominal

        pincount = device_params['num_pins_x'] * 2 + device_params[
            'num_pins_y'] * 2

        ipc_reference = 'ipc_spec_gw_large_pitch' if device_params[
            'pitch'] >= 0.625 else 'ipc_spec_gw_small_pitch'
        if device_params.get('force_small_pitch_ipc_definition', False):
            ipc_reference = 'ipc_spec_gw_small_pitch'

        used_density = device_params.get('ipc_density', ipc_density)
        ipc_data_set = self.ipc_defintions[ipc_reference][used_density]
        ipc_round_base = self.ipc_defintions[ipc_reference]['round_base']

        pitch = device_params['pitch']

        name_format = self.configuration[
            'fp_name_format_string_no_trailing_zero']
        EP_size = {'x': 0, 'y': 0}
        EP_mask_size = {'x': 0, 'y': 0}

        if dimensions['has_EP']:
            name_format = self.configuration[
                'fp_name_EP_format_string_no_trailing_zero']
            if 'EP_size_x_overwrite' in device_params:
                EP_size = {
                    'x': device_params['EP_size_x_overwrite'],
                    'y': device_params['EP_size_y_overwrite']
                }
            else:
                EP_size = {
                    'x': device_dimensions['EP_size_x'].nominal,
                    'y': device_dimensions['EP_size_y'].nominal
                }
            if 'EP_mask_x' in dimensions:
                name_format = self.configuration[
                    'fp_name_EP_custom_mask_format_string_no_trailing_zero']
                EP_mask_size = {
                    'x': dimensions['EP_mask_x'].nominal,
                    'y': dimensions['EP_mask_y'].nominal
                }
        EP_size = Vector2D(EP_size)

        pad_details = self.calcPadDetails(dimensions, EP_size, ipc_data_set,
                                          ipc_round_base)

        if 'custom_name_format' in device_params:
            name_format = device_params['custom_name_format']

        suffix = device_params.get('suffix', '').format(
            pad_x=pad_details['left']['size'][0],
            pad_y=pad_details['left']['size'][1])
        suffix_3d = suffix if device_params.get('include_suffix_in_3dpath',
                                                'True') == 'True' else ""
        model3d_path_prefix = self.configuration.get('3d_model_prefix',
                                                     '${KISYS3DMOD}')

        fp_name = name_format.format(
            man=device_params.get('manufacturer', ''),
            mpn=device_params.get('part_number', ''),
            pkg=header['device_type'],
            pincount=pincount,
            size_y=size_y,
            size_x=size_x,
            pitch=device_params['pitch'],
            ep_size_x=EP_size['x'],
            ep_size_y=EP_size['y'],
            mask_size_x=EP_mask_size['x'],
            mask_size_y=EP_mask_size['y'],
            suffix=suffix,
            suffix2="",
            vias=self.configuration.get('thermal_via_suffix', '_ThermalVias')
            if with_thermal_vias else '').replace('__', '_').lstrip('_')

        fp_name_2 = name_format.format(
            man=device_params.get('manufacturer', ''),
            mpn=device_params.get('part_number', ''),
            pkg=header['device_type'],
            pincount=pincount,
            size_y=size_y,
            size_x=size_x,
            pitch=device_params['pitch'],
            ep_size_x=EP_size['x'],
            ep_size_y=EP_size['y'],
            mask_size_x=EP_mask_size['x'],
            mask_size_y=EP_mask_size['y'],
            suffix=suffix_3d,
            suffix2="",
            vias='').replace('__', '_').lstrip('_')

        model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'\
            .format(
                model3d_path_prefix=model3d_path_prefix, lib_name=lib_name,
                fp_name=fp_name_2)
        #print(fp_name)
        #print(pad_details)

        kicad_mod = Footprint(fp_name)

        # init kicad footprint
        kicad_mod.setDescription(
            "{manufacturer} {mpn} {package}, {pincount} Pin ({datasheet}), generated with kicad-footprint-generator {scriptname}"\
            .format(
                manufacturer = device_params.get('manufacturer',''),
                package = header['device_type'],
                mpn = device_params.get('part_number',''),
                pincount = pincount,
                datasheet = device_params['size_source'],
                scriptname = os.path.basename(__file__).replace("  ", " ")
                ).lstrip())

        kicad_mod.setTags(self.configuration['keyword_fp_string']\
            .format(
                man=device_params.get('manufacturer',''),
                package=header['device_type'],
                category=header['library_Suffix']
            ).lstrip())
        kicad_mod.setAttribute('smd')

        pad_shape_details = {}
        pad_shape_details['shape'] = Pad.SHAPE_ROUNDRECT
        pad_shape_details['radius_ratio'] = configuration.get(
            'round_rect_radius_ratio', 0)
        if 'round_rect_max_radius' in configuration:
            pad_shape_details['maximum_radius'] = configuration[
                'round_rect_max_radius']

        EP_round_radius = 0
        if dimensions['has_EP']:
            EP_mask_size = EP_mask_size if EP_mask_size['x'] > 0 else None

            if with_thermal_vias:
                thermals = device_params['thermal_vias']
                paste_coverage = thermals.get(
                    'EP_paste_coverage',
                    device_params.get('EP_paste_coverage',
                                      DEFAULT_PASTE_COVERAGE))

                EP = ExposedPad(
                    number=pincount + 1,
                    size=EP_size,
                    mask_size=EP_mask_size,
                    paste_layout=thermals.get('EP_num_paste_pads'),
                    paste_coverage=paste_coverage,
                    via_layout=thermals.get('count', 0),
                    paste_between_vias=thermals.get('paste_between_vias'),
                    paste_rings_outside=thermals.get('paste_rings_outside'),
                    via_drill=thermals.get('drill', 0.3),
                    via_grid=thermals.get('grid'),
                    paste_avoid_via=thermals.get('paste_avoid_via', True),
                    via_paste_clarance=thermals.get(
                        'paste_via_clearance', DEFAULT_VIA_PASTE_CLEARANCE),
                    min_annular_ring=thermals.get('min_annular_ring',
                                                  DEFAULT_MIN_ANNULAR_RING),
                    bottom_pad_min_size=thermals.get('bottom_min_size', 0),
                    **pad_shape_details)
            else:
                EP = ExposedPad(
                    number=pincount + 1,
                    size=EP_size,
                    mask_size=EP_mask_size,
                    paste_layout=device_params.get('EP_num_paste_pads', 1),
                    paste_coverage=device_params.get('EP_paste_coverage',
                                                     DEFAULT_PASTE_COVERAGE),
                    **pad_shape_details)

            kicad_mod.append(EP)
            EP_round_radius = EP.getRoundRadius()

        pad_radius = add_dual_or_quad_pad_border(kicad_mod, configuration,
                                                 pad_details, device_params)

        body_edge = {
            'left': -dimensions['body_size_x'].nominal / 2,
            'right': dimensions['body_size_x'].nominal / 2,
            'top': -dimensions['body_size_y'].nominal / 2,
            'bottom': dimensions['body_size_y'].nominal / 2
        }

        bounding_box = {
            'left':
            pad_details['left']['center'][0] -
            pad_details['left']['size'][0] / 2,
            'right':
            pad_details['right']['center'][0] +
            pad_details['right']['size'][0] / 2,
            'top':
            pad_details['top']['center'][1] -
            pad_details['top']['size'][1] / 2,
            'bottom':
            pad_details['bottom']['center'][1] +
            pad_details['bottom']['size'][1] / 2
        }

        if device_params['num_pins_x'] == 0:
            bounding_box['top'] = body_edge['top']
            bounding_box['bottom'] = body_edge['bottom']
            if EP_size['y'] > dimensions['body_size_y'].nominal:
                bounding_box['top'] = -EP_size['y'] / 2
                bounding_box['bottom'] = EP_size['y'] / 2

        if device_params['num_pins_y'] == 0:
            bounding_box['left'] = body_edge['left']
            bounding_box['right'] = body_edge['right']
            if EP_size['x'] > dimensions['body_size_x'].nominal:
                bounding_box['left'] = -EP_size['x'] / 2
                bounding_box['right'] = EP_size['x'] / 2

        pad_width = pad_details['top']['size'][0]

        # ############################ SilkS ##################################
        silk_pad_offset = configuration[
            'silk_pad_clearance'] + configuration['silk_line_width'] / 2
        silk_offset = configuration['silk_fab_offset']

        right_pads_silk_bottom = (device_params['num_pins_y']-1)*device_params['pitch']/2\
            +pad_details['right']['size'][1]/2+silk_pad_offset
        silk_bottom = body_edge['bottom'] + silk_offset
        if EP_size['y'] / 2 <= body_edge[
                'bottom'] and right_pads_silk_bottom >= silk_bottom:
            silk_bottom = max(silk_bottom, EP_size['y'] / 2 + silk_pad_offset)

        silk_bottom = max(silk_bottom, right_pads_silk_bottom)
        silk_bottom = min(body_edge['bottom'] + silk_pad_offset, silk_bottom)

        bottom_pads_silk_right = (device_params['num_pins_x']-1)*device_params['pitch']/2\
            +pad_details['bottom']['size'][0]/2+silk_pad_offset
        silk_right = body_edge['right'] + silk_offset
        if EP_size['x'] / 2 <= body_edge[
                'right'] and bottom_pads_silk_right >= silk_right:
            silk_right = max(silk_right, EP_size['x'] / 2 + silk_pad_offset)
        silk_right = max(silk_right, bottom_pads_silk_right)
        silk_right = min(body_edge['right'] + silk_pad_offset, silk_right)

        min_lenght = configuration.get('silk_line_lenght_min', 0)
        silk_corner_bottom_right = Vector2D(silk_right, silk_bottom)

        silk_point_bottom_inside = nearestSilkPointOnOrthogonalLine(
            pad_size=EP_size,
            pad_position=[0, 0],
            pad_radius=EP_round_radius,
            fixed_point=silk_corner_bottom_right,
            moving_point=Vector2D(0, silk_bottom),
            silk_pad_offset=silk_pad_offset,
            min_lenght=min_lenght)

        if silk_point_bottom_inside is not None and device_params[
                'num_pins_x'] > 0:
            silk_point_bottom_inside = nearestSilkPointOnOrthogonalLine(
                pad_size=pad_details['bottom']['size'],
                pad_position=[
                    pad_details['bottom']['center'][0] +
                    (device_params['num_pins_x'] - 1) / 2 * pitch,
                    pad_details['bottom']['center'][1]
                ],
                pad_radius=pad_radius,
                fixed_point=silk_corner_bottom_right,
                moving_point=silk_point_bottom_inside,
                silk_pad_offset=silk_pad_offset,
                min_lenght=min_lenght)

        silk_point_right_inside = nearestSilkPointOnOrthogonalLine(
            pad_size=EP_size,
            pad_position=[0, 0],
            pad_radius=EP_round_radius,
            fixed_point=silk_corner_bottom_right,
            moving_point=Vector2D(silk_right, 0),
            silk_pad_offset=silk_pad_offset,
            min_lenght=min_lenght)
        if silk_point_right_inside is not None and device_params[
                'num_pins_y'] > 0:
            silk_point_right_inside = nearestSilkPointOnOrthogonalLine(
                pad_size=pad_details['right']['size'],
                pad_position=[
                    pad_details['right']['center'][0],
                    pad_details['right']['center'][1] +
                    (device_params['num_pins_y'] - 1) / 2 * pitch
                ],
                pad_radius=pad_radius,
                fixed_point=silk_corner_bottom_right,
                moving_point=silk_point_right_inside,
                silk_pad_offset=silk_pad_offset,
                min_lenght=min_lenght)

        if silk_point_bottom_inside is None and silk_point_right_inside is not None:
            silk_corner_bottom_right['y'] = body_edge['bottom']
            silk_corner_bottom_right = nearestSilkPointOnOrthogonalLine(
                pad_size=pad_details['bottom']['size'],
                pad_position=[
                    pad_details['bottom']['center'][0] +
                    (device_params['num_pins_x'] - 1) / 2 * pitch,
                    pad_details['bottom']['center'][1]
                ],
                pad_radius=pad_radius,
                fixed_point=silk_point_right_inside,
                moving_point=silk_corner_bottom_right,
                silk_pad_offset=silk_pad_offset,
                min_lenght=min_lenght)

        elif silk_point_right_inside is None and silk_point_bottom_inside is not None:
            silk_corner_bottom_right['x'] = body_edge['right']
            silk_corner_bottom_right = nearestSilkPointOnOrthogonalLine(
                pad_size=pad_details['right']['size'],
                pad_position=[
                    pad_details['right']['center'][0],
                    pad_details['right']['center'][1] +
                    (device_params['num_pins_y'] - 1) / 2 * pitch
                ],
                pad_radius=pad_radius,
                fixed_point=silk_point_bottom_inside,
                moving_point=silk_corner_bottom_right,
                silk_pad_offset=silk_pad_offset,
                min_lenght=min_lenght)

        poly_bottom_right = []
        if silk_point_bottom_inside is not None:
            poly_bottom_right.append(silk_point_bottom_inside)
        poly_bottom_right.append(silk_corner_bottom_right)
        if silk_point_right_inside is not None:
            poly_bottom_right.append(silk_point_right_inside)

        if len(poly_bottom_right) > 1 and silk_corner_bottom_right is not None:
            kicad_mod.append(
                PolygoneLine(polygone=poly_bottom_right,
                             width=configuration['silk_line_width'],
                             layer="F.SilkS"))
            kicad_mod.append(
                PolygoneLine(polygone=poly_bottom_right,
                             width=configuration['silk_line_width'],
                             layer="F.SilkS",
                             x_mirror=0))
            kicad_mod.append(
                PolygoneLine(polygone=poly_bottom_right,
                             width=configuration['silk_line_width'],
                             layer="F.SilkS",
                             y_mirror=0))

            if device_params['num_pins_y'] > 0:
                if silk_corner_bottom_right[
                        'y'] - min_lenght >= right_pads_silk_bottom:
                    poly_bottom_right[-1]['y'] = right_pads_silk_bottom
                    kicad_mod.append(
                        PolygoneLine(polygone=poly_bottom_right,
                                     width=configuration['silk_line_width'],
                                     layer="F.SilkS",
                                     y_mirror=0,
                                     x_mirror=0))
                    kicad_mod.append(
                        Line(start={
                            'x': -silk_corner_bottom_right['x'],
                            'y': -right_pads_silk_bottom
                        },
                             end={
                                 'x': bounding_box['left'],
                                 'y': -right_pads_silk_bottom
                             },
                             width=configuration['silk_line_width'],
                             layer="F.SilkS"))
                elif silk_corner_bottom_right[
                        'y'] >= right_pads_silk_bottom and silk_point_bottom_inside is not None:
                    kicad_mod.append(
                        Line(start=-silk_point_bottom_inside,
                             end={
                                 'x': bounding_box['left'],
                                 'y': -silk_point_bottom_inside['y']
                             },
                             width=configuration['silk_line_width'],
                             layer="F.SilkS"))
            else:
                if silk_corner_bottom_right[
                        'x'] - min_lenght >= bottom_pads_silk_right:
                    poly_bottom_right[0]['x'] = bottom_pads_silk_right
                    kicad_mod.append(
                        PolygoneLine(polygone=poly_bottom_right,
                                     width=configuration['silk_line_width'],
                                     layer="F.SilkS",
                                     y_mirror=0,
                                     x_mirror=0))
                    kicad_mod.append(
                        Line(start={
                            'x': -bottom_pads_silk_right,
                            'y': -silk_corner_bottom_right['y']
                        },
                             end={
                                 'x': -bottom_pads_silk_right,
                                 'y': bounding_box['top']
                             },
                             width=configuration['silk_line_width'],
                             layer="F.SilkS"))
                elif silk_corner_bottom_right[
                        'x'] >= bottom_pads_silk_right and silk_point_right_inside is not None:
                    kicad_mod.append(
                        Line(start=-silk_point_right_inside,
                             end={
                                 'x': -silk_point_right_inside['x'],
                                 'y': bounding_box['top']
                             },
                             width=configuration['silk_line_width'],
                             layer="F.SilkS"))

        # # ######################## Fabrication Layer ###########################

        fab_bevel_size = min(
            configuration['fab_bevel_size_absolute'],
            configuration['fab_bevel_size_relative'] * min(size_x, size_y))

        poly_fab = [
            {
                'x': body_edge['left'] + fab_bevel_size,
                'y': body_edge['top']
            },
            {
                'x': body_edge['right'],
                'y': body_edge['top']
            },
            {
                'x': body_edge['right'],
                'y': body_edge['bottom']
            },
            {
                'x': body_edge['left'],
                'y': body_edge['bottom']
            },
            {
                'x': body_edge['left'],
                'y': body_edge['top'] + fab_bevel_size
            },
            {
                'x': body_edge['left'] + fab_bevel_size,
                'y': body_edge['top']
            },
        ]

        kicad_mod.append(
            PolygoneLine(polygone=poly_fab,
                         width=configuration['fab_line_width'],
                         layer="F.Fab"))

        # # ############################ CrtYd ##################################

        off = ipc_data_set['courtyard']
        grid = configuration['courtyard_grid']

        if device_params['num_pins_y'] == 0 or device_params['num_pins_x'] == 0:
            cy1 = roundToBase(bounding_box['top'] - off, grid)

            kicad_mod.append(
                RectLine(start={
                    'x': roundToBase(bounding_box['left'] - off, grid),
                    'y': cy1
                },
                         end={
                             'x': roundToBase(bounding_box['right'] + off,
                                              grid),
                             'y': roundToBase(bounding_box['bottom'] + off,
                                              grid)
                         },
                         width=configuration['courtyard_line_width'],
                         layer='F.CrtYd'))

        else:
            cy1 = roundToBase(bounding_box['top'] - off, grid)
            cy2 = roundToBase(body_edge['top'] - off, grid)
            cy3 = -roundToBase(
                device_params['pitch'] *
                (device_params['num_pins_y'] - 1) / 2.0 + pad_width / 2.0 +
                off, grid)

            cx1 = -roundToBase(
                device_params['pitch'] *
                (device_params['num_pins_x'] - 1) / 2.0 + pad_width / 2.0 +
                off, grid)
            cx2 = roundToBase(body_edge['left'] - off, grid)
            cx3 = roundToBase(bounding_box['left'] - off, grid)

            crty_poly_tl = [{
                'x': 0,
                'y': cy1
            }, {
                'x': cx1,
                'y': cy1
            }, {
                'x': cx1,
                'y': cy2
            }, {
                'x': cx2,
                'y': cy2
            }, {
                'x': cx2,
                'y': cy3
            }, {
                'x': cx3,
                'y': cy3
            }, {
                'x': cx3,
                'y': 0
            }]
            kicad_mod.append(
                PolygoneLine(polygone=crty_poly_tl,
                             layer='F.CrtYd',
                             width=configuration['courtyard_line_width']))
            kicad_mod.append(
                PolygoneLine(polygone=crty_poly_tl,
                             layer='F.CrtYd',
                             width=configuration['courtyard_line_width'],
                             x_mirror=0))
            kicad_mod.append(
                PolygoneLine(polygone=crty_poly_tl,
                             layer='F.CrtYd',
                             width=configuration['courtyard_line_width'],
                             y_mirror=0))
            kicad_mod.append(
                PolygoneLine(polygone=crty_poly_tl,
                             layer='F.CrtYd',
                             width=configuration['courtyard_line_width'],
                             x_mirror=0,
                             y_mirror=0))

        # ######################### Text Fields ###############################

        addTextFields(kicad_mod=kicad_mod,
                      configuration=configuration,
                      body_edges=body_edge,
                      courtyard={
                          'top': cy1,
                          'bottom': -cy1
                      },
                      fp_name=fp_name,
                      text_y_inside_position='center')

        ##################### Output and 3d model ############################

        kicad_mod.append(Model(filename=model_name))

        output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
        if not os.path.isdir(
                output_dir
        ):  #returns false if path does not yet exist!! (Does not check path validity)
            os.makedirs(output_dir)
        filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                            fp_name=fp_name)

        file_handler = KicadFileHandler(kicad_mod)
        file_handler.writeFile(filename)
def generate_footprint(pins, configuration):

    mpn = pn.format(n=pins)
    pins_per_row = pins

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Harwin {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    kicad_mod.setAttribute('smd')

    ########################## Dimensions ##############################

    A = 2.54 * pins
    B = 2.54 * (pins-1)
    C = B - 2.54

    body_edge={
        'left': -2.54,
        'right': 2.54,
        'top': -A/2,
        'bottom': A/2
    }

    ############################# Pads ##################################
    #
    # Mount Pegs
    #
    if pins == 2:
        kicad_mod.append(Pad(at=[0, 0], number="",
            type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=mount_drill,
            drill=mount_drill, layers=Pad.LAYERS_NPTH))
    else:
        kicad_mod.append(Pad(at=[0, -C/2], number="",
            type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=mount_drill,
            drill=mount_drill, layers=Pad.LAYERS_NPTH))
        kicad_mod.append(Pad(at=[0, C/2], number="",
            type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=mount_drill,
            drill=mount_drill, layers=Pad.LAYERS_NPTH))

    #
    # THT Pegs
    #
    kicad_mod.append(PadArray(start=[-1.27, -B/2], initial="", pincount=pins,
        y_spacing=pitch, type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
        size=peg_drill_tht, drill=peg_drill_tht, layers=Pad.LAYERS_NPTH))

    kicad_mod.append(PadArray(start=[1.27, -B/2], initial="", pincount=pins,
        y_spacing=pitch, type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
        size=peg_drill_tht, drill=peg_drill_tht, layers=Pad.LAYERS_NPTH))

    #
    # Add pads
    #
    kicad_mod.append(PadArray(start=[-2.91, -B/2], initial=1,
        pincount=pins, increment=1,  y_spacing=pitch, size=pad_size,
        type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT))
    kicad_mod.append(PadArray(start=[2.91, -B/2], initial=pins+1,
        pincount=pins, increment=1,  y_spacing=pitch, size=pad_size,
        type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT))

    ######################## Fabrication Layer ###########################
    main_body_poly= [
        {'x': body_edge['left'], 'y': body_edge['top']},
        {'x': body_edge['right'], 'y': body_edge['top']},
        {'x': body_edge['right'], 'y': body_edge['bottom']},
        {'x': body_edge['left'], 'y': body_edge['bottom']},
        {'x': body_edge['left'], 'y': body_edge['top']}
    ]
    kicad_mod.append(PolygoneLine(polygone=main_body_poly,
        width=configuration['fab_line_width'], layer="F.Fab"))

    main_arrow_poly= [
        {'x': -2.54, 'y': body_edge['top'] + 1.27 - .4},
        {'x': -1.9, 'y': body_edge['top'] + 1.27},
        {'x': -2.54, 'y': body_edge['top'] + 1.27 + .4},
    ]
    kicad_mod.append(PolygoneLine(polygone=main_arrow_poly,
        width=configuration['fab_line_width'], layer="F.Fab"))

    ######################## SilkS Layer ###########################
    poly_s_top= [
        {'x': body_edge['left'] - configuration['silk_fab_offset'], 'y': body_edge['top'] - configuration['silk_fab_offset'] + .7},
        {'x': body_edge['left'] - configuration['silk_fab_offset'], 'y': body_edge['top'] - configuration['silk_fab_offset']},
        {'x': body_edge['right'] + configuration['silk_fab_offset'], 'y': body_edge['top'] - configuration['silk_fab_offset']},
        {'x': body_edge['right'] + configuration['silk_fab_offset'], 'y': body_edge['top'] - configuration['silk_fab_offset'] + .7},
    ]
    kicad_mod.append(PolygoneLine(polygone=poly_s_top,
        width=configuration['silk_line_width'], layer="F.SilkS"))

    poly_s_bot= [
        {'x': body_edge['left'] - configuration['silk_fab_offset'], 'y': body_edge['bottom'] + configuration['silk_fab_offset'] - .7},
        {'x': body_edge['left'] - configuration['silk_fab_offset'], 'y': body_edge['bottom'] + configuration['silk_fab_offset']},
        {'x': body_edge['right'] + configuration['silk_fab_offset'], 'y': body_edge['bottom'] + configuration['silk_fab_offset']},
        {'x': body_edge['right'] + configuration['silk_fab_offset'], 'y': body_edge['bottom'] + configuration['silk_fab_offset'] - .7},
    ]
    kicad_mod.append(PolygoneLine(polygone=poly_s_bot,
        width=configuration['silk_line_width'], layer="F.SilkS"))

    ######################## CrtYd Layer ###########################
    CrtYd_offset = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']

    poly_yd = [
        {'x': -3.8 - CrtYd_offset, 'y': body_edge['top'] - CrtYd_offset},
        {'x': 3.8 + CrtYd_offset, 'y': body_edge['top'] - CrtYd_offset},
        {'x': 3.8 + CrtYd_offset, 'y': body_edge['bottom'] + CrtYd_offset},
        {'x': -3.8 - CrtYd_offset, 'y': body_edge['bottom'] + CrtYd_offset},
        {'x': -3.8 - CrtYd_offset, 'y': body_edge['top'] - CrtYd_offset}
    ]

    kicad_mod.append(PolygoneLine(polygone=poly_yd,
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    cy1 = body_edge['top'] - configuration['courtyard_offset']['connector']
    cy2 = body_edge['bottom'] + configuration['courtyard_offset']['connector'] + 0.2

    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='top')

    ##################### Write to File and 3D ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #36
0
def generate_one_footprint(pins_per_row, variant, configuration):
    mpn = variant_params[variant]['part_code'].format(n=pins_per_row *
                                                      number_of_rows)
    alt_mpn = [
        code.format(n=pins_per_row * number_of_rows)
        for code in variant_params[variant]['alternative_codes']
    ]

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins_per_row,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "Molex {:s}, {:s} (compatible alternatives: {:s}), {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
        .format(series_long, mpn, ', '.join(alt_mpn), pins_per_row,
                variant_params[variant]['datasheet']))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #kicad_mod.setAttribute('smd')

    ########################## Dimensions ##############################
    B = (pins_per_row - 1) * pitch
    A = B + 6.65
    C = B + variant_params[variant]['C_minus_B']

    pad_row_1_y = 0
    pad1_x = 0

    peg1_x = (B - C) / 2
    peg2_x = (B + C) / 2
    peg_y = pad_row_1_y + pitch + 0.94

    tab_w = 1.4
    tab_l = 1.4

    body_edge = {'left': (B - A) / 2, 'right': (A + B) / 2, 'top': -2.47 + 0.5}
    body_edge['bottom'] = body_edge['top'] + (7.37 - 0.5)

    y_top_min = -2.47
    chamfer = {'x': 1.2, 'y': 0.63}

    ############################# Pads ##################################
    #
    # Pegs
    #
    kicad_mod.append(
        Pad(at=[peg1_x, peg_y],
            number="",
            type=Pad.TYPE_NPTH,
            shape=Pad.SHAPE_CIRCLE,
            size=peg_drill,
            drill=peg_drill,
            layers=Pad.LAYERS_NPTH))
    kicad_mod.append(
        Pad(at=[peg2_x, peg_y],
            number="",
            type=Pad.TYPE_NPTH,
            shape=Pad.SHAPE_CIRCLE,
            size=peg_drill,
            drill=peg_drill,
            layers=Pad.LAYERS_NPTH))

    #
    # Add pads
    #

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    for row_idx in range(2):
        kicad_mod.append(
            PadArray(start=[pad1_x, pad_row_1_y + pitch * row_idx],
                     initial=row_idx * pins_per_row + 1,
                     pincount=pins_per_row,
                     increment=1,
                     x_spacing=pitch,
                     size=pad_size,
                     type=Pad.TYPE_THT,
                     shape=pad_shape,
                     layers=Pad.LAYERS_THT,
                     drill=drill,
                     **optional_pad_params))

    ######################## Fabrication Layer ###########################
    main_body_poly = [{
        'x': body_edge['left'] + chamfer['x'],
        'y': body_edge['top']
    }, {
        'x': body_edge['left'] + chamfer['x'],
        'y': y_top_min
    }, {
        'x': body_edge['left'],
        'y': y_top_min
    }, {
        'x': body_edge['left'],
        'y': body_edge['bottom']
    }, {
        'x': body_edge['right'],
        'y': body_edge['bottom']
    }, {
        'x': body_edge['right'],
        'y': y_top_min
    }, {
        'x': body_edge['right'] - chamfer['x'],
        'y': y_top_min
    }, {
        'x': body_edge['right'] - chamfer['x'],
        'y': body_edge['top']
    }, {
        'x': body_edge['left'] + chamfer['x'],
        'y': body_edge['top']
    }]
    kicad_mod.append(
        PolygoneLine(polygone=main_body_poly,
                     width=configuration['fab_line_width'],
                     layer="F.Fab"))

    kicad_mod.append(
        Line(start={
            'x': body_edge['left'],
            'y': body_edge['top'] + chamfer['y']
        },
             end={
                 'x': body_edge['left'] + chamfer['x'],
                 'y': body_edge['top']
             },
             width=configuration['fab_line_width'],
             layer="F.Fab"))

    kicad_mod.append(
        Line(start={
            'x': body_edge['right'],
            'y': body_edge['top'] + chamfer['y']
        },
             end={
                 'x': body_edge['right'] - chamfer['x'],
                 'y': body_edge['top']
             },
             width=configuration['fab_line_width'],
             layer="F.Fab"))

    tab_poly = [
        {
            'x': B / 2 - tab_l / 2,
            'y': body_edge['bottom']
        },
        {
            'x': B / 2 - tab_l / 2,
            'y': body_edge['bottom'] + tab_w
        },
        {
            'x': B / 2 + tab_l / 2,
            'y': body_edge['bottom'] + tab_w
        },
        {
            'x': B / 2 + tab_l / 2,
            'y': body_edge['bottom']
        },
    ]
    kicad_mod.append(
        PolygoneLine(polygone=tab_poly,
                     width=configuration['fab_line_width'],
                     layer="F.Fab"))

    p1m_sl = 1
    p1m_poly = tab_poly = [{
        'x': pad1_x - p1m_sl / 2,
        'y': body_edge['top']
    }, {
        'x': pad1_x,
        'y': body_edge['top'] + p1m_sl / sqrt(2)
    }, {
        'x': pad1_x + p1m_sl / 2,
        'y': body_edge['top']
    }]
    kicad_mod.append(
        PolygoneLine(polygone=tab_poly,
                     width=configuration['fab_line_width'],
                     layer="F.Fab"))

    ############################ SilkS ##################################
    # Top left corner

    silk_pad_off = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2

    ymp_top = peg_y - peg_drill / 2 - silk_pad_off
    ymp_bottom = peg_y + peg_drill / 2 + silk_pad_off
    off = configuration['silk_fab_offset']

    poly_s_b = [
        {
            'x': body_edge['left'] - off,
            'y': ymp_bottom
        },
        {
            'x': body_edge['left'] - off,
            'y': body_edge['bottom'] + off
        },
        {
            'x': body_edge['right'] + off,
            'y': body_edge['bottom'] + off
        },
        {
            'x': body_edge['right'] + off,
            'y': ymp_bottom
        },
    ]
    kicad_mod.append(
        PolygoneLine(polygone=poly_s_b,
                     width=configuration['silk_line_width'],
                     layer="F.SilkS"))

    poly_s_t = [
        {
            'x': body_edge['left'] - off,
            'y': ymp_top
        },
        {
            'x': body_edge['left'] - off,
            'y': y_top_min - off
        },
        {
            'x': body_edge['left'] + chamfer['x'] + off,
            'y': y_top_min - off
        },
        {
            'x': body_edge['left'] + chamfer['x'] + off,
            'y': body_edge['top'] - off
        },
        {
            'x': body_edge['right'] - chamfer['x'] - off,
            'y': body_edge['top'] - off
        },
        {
            'x': body_edge['right'] - chamfer['x'] - off,
            'y': y_top_min - off
        },
        {
            'x': body_edge['right'] + off,
            'y': y_top_min - off
        },
        {
            'x': body_edge['right'] + off,
            'y': ymp_top
        },
    ]
    kicad_mod.append(
        PolygoneLine(polygone=poly_s_t,
                     width=configuration['silk_line_width'],
                     layer="F.SilkS"))

    ############################ CrtYd ##################################
    CrtYd_offset = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']

    cy_top = roundToBase(y_top_min - CrtYd_offset, CrtYd_grid)
    cy_bottom = roundToBase(body_edge['bottom'] + tab_w + CrtYd_offset,
                            CrtYd_grid)
    cy_left = roundToBase(body_edge['left'] - CrtYd_offset, CrtYd_grid)
    cy_right = roundToBase(body_edge['right'] + CrtYd_offset, CrtYd_grid)

    poly_cy = [
        {
            'x': cy_left,
            'y': cy_top
        },
        {
            'x': cy_right,
            'y': cy_top
        },
        {
            'x': cy_right,
            'y': cy_bottom
        },
        {
            'x': cy_left,
            'y': cy_bottom
        },
        {
            'x': cy_left,
            'y': cy_top
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=poly_cy,
                     layer='F.CrtYd',
                     width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################

    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy_top,
                      'bottom': cy_bottom
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def make_module(pin_count, configuration):
    mpn = part_code.format(pin_count)
    datasheet='https://www.molex.com/pdm_docs/sd/2005280{:02d}0_sd.pdf'.format(pin_count)

    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man = manufacturer,
        series = series,
        mpn = mpn,
        num_rows = number_of_rows,
        pins = pin_count,
	pins_per_row = pin_count,
        mounting_pad = "-1MP",
        pitch = pitch,
        orientation = orientation_str)

    footprint_name = footprint_name.replace("__",'_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setAttribute('smd')
    kicad_mod.setDescription(
        ("Molex {:s}, {:s}, {:d} Circuits ({:s}), " +
         "generated with kicad-footprint-generator").format(
        series_long, mpn, pin_count, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        man=manufacturer,
        series=series,
        orientation=orientation_str,
        entry=configuration['entry_direction'][orientation]))




    A = pin_count + 5.2
    B = pin_span = pin_count - 1
    C = pin_count + 3.6
    pin_y = -(0.4 - (lead_size[1] / 2)) - 0.71
    lever_size = (C, 4)
    toe_ins_corner = ((A / 2) - toe_size[0], pin_y + (0.4 - (lead_size[1] / 2)))
    lever_out_corner = (C / 2,
        (toe_ins_corner[1] - toe_size[1]) + 5.25)
    pad_silk_off = (configuration['silk_pad_clearance'] +
                    (configuration['silk_line_width'] / 2))
    fab_silk_off = configuration['silk_fab_offset']

    ## Mounting Pads ##

    mp_pos = ((pin_span / 2) + 1.8 + (mp_size[0] / 2),
        pin_y + (pad_size[1] / 2) + 1.55 + (mp_size[1] / 2))

    def make_anchor_pad(x_direction):
        kicad_mod.append(
            Pad(number = configuration['mounting_pad_number'],
                type = Pad.TYPE_SMT,
                shape = Pad.SHAPE_RECT,
                at = [x_direction * mp_pos[0], mp_pos[1]],
                size = mp_size,
                layers = Pad.LAYERS_SMT))
    make_anchor_pad(-1)
    make_anchor_pad(1)

    ## Pads ##

    kicad_mod.append(
        PadArray(center = [0, pin_y],
            pincount = pin_count,
            x_spacing = pitch,
            type = Pad.TYPE_SMT,
            shape = Pad.SHAPE_RECT,
            size = pad_size,
            layers = Pad.LAYERS_SMT))

    ## Fab ##

    fab_body_outline = [
        {'x': toe_ins_corner[0], 'y': toe_ins_corner[1] - toe_size[1]},
        {'x': toe_ins_corner[0], 'y': toe_ins_corner[1]},
        {'x': -toe_ins_corner[0], 'y': toe_ins_corner[1]},
        {'x': -toe_ins_corner[0], 'y': toe_ins_corner[1] - toe_size[1]},
        {'x': -(A / 2), 'y': toe_ins_corner[1] - toe_size[1]},
        {'x': -(A / 2), 'y': (toe_ins_corner[1] - toe_size[1]) + foot_y},
        {'x': (A / 2), 'y': (toe_ins_corner[1] - toe_size[1]) + foot_y},
        {'x': (A / 2), 'y': toe_ins_corner[1] - toe_size[1]},
        {'x': toe_ins_corner[0], 'y': toe_ins_corner[1] - toe_size[1]}
    ]

    kicad_mod.append(PolygoneLine(
        polygone = fab_body_outline,
        layer = 'F.Fab',
        width = configuration['fab_line_width']))

    fab_pin1_mark = [
        {'x': -(pin_span / 2) - 0.5, 'y': toe_ins_corner[1]},
        {'x': -(pin_span / 2), 'y': toe_ins_corner[1] + 0.75},
        {'x': -(pin_span / 2) + 0.5, 'y': toe_ins_corner[1]}
    ]

    kicad_mod.append(PolygoneLine(
        polygone = fab_pin1_mark,
        layer = 'F.Fab',
        width = configuration['fab_line_width']))

    fab_lever_outline = [
        {'x': lever_out_corner[0], 'y': lever_out_corner[1] - lever_size[1]},
        {'x': -lever_out_corner[0], 'y': lever_out_corner[1] - lever_size[1]},
        {'x': -lever_out_corner[0], 'y': lever_out_corner[1]},
        {'x': lever_out_corner[0], 'y': lever_out_corner[1]},
        {'x': lever_out_corner[0], 'y': lever_out_corner[1] - lever_size[1]}
    ]

    kicad_mod.append(PolygoneLine(
        polygone = fab_lever_outline,
        layer = 'F.Fab',
        width = configuration['fab_line_width']))

    ## SilkS ##

    silk_outline1 = [
        {'x': (-(pin_span / 2) - (pad_size[0] / 2)) - pad_silk_off, 'y': pin_y - (pad_size[1] / 2)},
        {'x': (-(pin_span / 2) - (pad_size[0] / 2)) - pad_silk_off, 'y': toe_ins_corner[1] - fab_silk_off},
        {'x': -toe_ins_corner[0] + fab_silk_off, 'y': toe_ins_corner[1] - fab_silk_off},
        {'x': -toe_ins_corner[0] + fab_silk_off, 'y': (toe_ins_corner[1] - toe_size[1]) - fab_silk_off},
        {'x': -(A / 2) - fab_silk_off, 'y': (toe_ins_corner[1] - toe_size[1]) - fab_silk_off},
        {'x': -(A / 2) - fab_silk_off, 'y': (mp_pos[1] - (mp_size[1] / 2)) - pad_silk_off},
    ]


    silk_outline2 = [
        {'x': -(A / 2) - fab_silk_off, 'y': (mp_pos[1] + (mp_size[1] / 2)) + pad_silk_off},
        {'x': -(A / 2) - fab_silk_off, 'y': ((toe_ins_corner[1] - toe_size[1]) + foot_y) + fab_silk_off},
        {'x': -lever_out_corner[0] - fab_silk_off, 'y': ((toe_ins_corner[1] - toe_size[1]) + foot_y) + fab_silk_off},
        {'x': -lever_out_corner[0] - fab_silk_off, 'y': lever_out_corner[1] + fab_silk_off},
        {'x': lever_out_corner[0] + fab_silk_off, 'y': lever_out_corner[1] + fab_silk_off},
        {'x': lever_out_corner[0] + fab_silk_off, 'y': ((toe_ins_corner[1] - toe_size[1]) + foot_y) + fab_silk_off},
        {'x': (A / 2) + fab_silk_off, 'y': ((toe_ins_corner[1] - toe_size[1]) + foot_y) + fab_silk_off},
        {'x': (A / 2) + fab_silk_off, 'y': (mp_pos[1] + (mp_size[1] / 2)) + pad_silk_off},
    ]

    silk_outline3 = [
        {'x': (A / 2) + fab_silk_off, 'y': (mp_pos[1] - (mp_size[1] / 2)) - pad_silk_off},
        {'x': (A / 2) + fab_silk_off, 'y': (toe_ins_corner[1] - toe_size[1]) - fab_silk_off},
        {'x': toe_ins_corner[0] - fab_silk_off, 'y': (toe_ins_corner[1] - toe_size[1]) - fab_silk_off},
        {'x': toe_ins_corner[0] - fab_silk_off, 'y': toe_ins_corner[1] - fab_silk_off},
        {'x': ((pin_span / 2) + (pad_size[0] / 2)) + pad_silk_off, 'y': toe_ins_corner[1] - fab_silk_off}
    ]

    kicad_mod.append(PolygoneLine(
        polygone = silk_outline1,
        layer = 'F.SilkS',
        width = configuration['silk_line_width']))

    kicad_mod.append(PolygoneLine(
        polygone = silk_outline2,
        layer = 'F.SilkS',
        width = configuration['silk_line_width']))

    kicad_mod.append(PolygoneLine(
        polygone = silk_outline3,
        layer = 'F.SilkS',
        width = configuration['silk_line_width']))

    ## CrtYd ##

    bounding_box = {
        'top': pin_y - (pad_size[1] / 2),
        'left': (-mp_pos[0] - (mp_size[0] / 2)),
        'bottom': lever_out_corner[1],
        'right': (mp_pos[0] + (mp_size[0] / 2))}

    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ## Text ##

    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=bounding_box, courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='center')




    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    if lib_by_conn_category:
        lib_name = configuration['lib_name_specific_function_format_string'].format(category=conn_category)
    else:
        lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)

    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #38
0
def generate_one_footprint(pincount, configuration):
    if pincount in [6, 8]:
        number_of_rows = 2
        pin_per_row = int(pincount / 2)
    else:
        number_of_rows = 1
        pin_per_row = pincount

    mpn = part_base.format(n=pincount)

    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pin_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator".format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    conn_width = jwpf_widths[pincount]
    conn_length = jwpf_lengths[pincount]

    mount_hole_offset_y = 2.05 if number_of_rows == 1 else 2.45


    # Add texts
    x_mid = (number_of_rows-1) * row_spacing / 2
    y_mid = (pin_per_row - 1) * pitch / 2.0

    # Connector outline
    y1 = y_mid - conn_length / 2
    y2 = y_mid + conn_length / 2

    x1 = -5.4 # measured from 3D model alignment
    x2 = x1 + conn_width

    body_edge={'left':x1, 'right':x2, 'top':y1, 'bottom':y2}

    y_ref = -3 if number_of_rows == 1 else -4

    pad_size = [pad_drill + 2*pad_copper_x_solder_length, pitch - pad_to_pad_clearance]
    if number_of_rows > 1:
        if pad_size[0] - pad_drill > 2*pad_copper_x_solder_length:
            pad_size[0] = pad_drill + 2*pad_copper_x_solder_length
        if pad_size[0] - pad_drill < 2*min_annular_ring:
            pad_size[0] = pad_drill + 2*min_annular_ring
    if pad_size[1] - pad_drill < 2*min_annular_ring:
        pad_size[1] = pad_drill + 2*min_annular_ring

    if pad_size[0] == pad_size[1]:
        pad_shape = Pad.SHAPE_CIRCLE
    else:
        pad_shape = Pad.SHAPE_OVAL

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    # Create pins
    for i in range(number_of_rows):
        kicad_mod.append(PadArray(
            initial=1+i*pin_per_row, start=[i*row_spacing, 0],
            pincount=pin_per_row, y_spacing=pitch,
            type=Pad.TYPE_THT, shape=pad_shape,
            size=pad_size, drill=pad_drill, layers=Pad.LAYERS_THT,
            **optional_pad_params))

    # Add mounting hole
    mx = -mount_hole_offset_x
    my = (pin_per_row - 1) * pitch + mount_hole_offset_y
    kicad_mod.append(Pad(at=[mx, my], size=mount_hole_size, drill=mount_hole_size, shape=Pad.SHAPE_CIRCLE, type=Pad.TYPE_NPTH, layers=Pad.LAYERS_NPTH))

    # Tab dimensions
    tw = 7
    tt = 0.5

    ########################### CrtYd #################################
    cx1 = roundToBase(x1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(y1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(x2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(y2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    def draw_outline(offset=0, layer='F.Fab', width=configuration['fab_line_width']):
        O = offset
        R = 1.0

        if pincount == 2:
            poly = [
                {'x': x2 + O - R, 'y': y1 - O},
                {'x': x1 - O, 'y': y1 - O},
                {'x': x1 - O, 'y': y2 + O},
                {'x': x2 + O - R, 'y': y2 + O},
            ]

            kicad_mod.append(PolygoneLine(polygone=poly, layer=layer, width=width))
        else:
            # top line
            kicad_mod.append(Line(start=[tt+x1-O+R, y1-O], end=[x2+O-R, y1-O], layer=layer, width=width))
            # bottom line
            kicad_mod.append(Line(start=[tt+x1-O+R, y2+O], end=[x2+O-R, y2+O], layer=layer, width=width))

            # left line (including tab)
            poly = [
                {'x': tt+x1-O, 'y': y1-O+R},
                {'x': tt+x1-O, 'y': y_mid - tw/2.0 - O},
                {'x': x1-O, 'y': y_mid - tw/2.0 - O},
                {'x': x1-O, 'y': y_mid + tw/2.0 + O},
                {'x': tt+x1-O, 'y': y_mid + tw/2.0 + O},
                {'x': tt+x1-O, 'y': y2+O-R}
            ]

            kicad_mod.append(PolygoneLine(polygone=poly, width=width, layer=layer))

            # top left
            kicad_mod.append(Arc(center=[tt+x1-O+R, y1-O+R], start=[tt+x1-O, y1-O+R], angle=90.0, layer=layer, width=width))
            # bottom left
            kicad_mod.append(Arc(center=[tt+x1-O+R, y2+O-R], start=[tt+x1-O+R, y2+O], angle=90.0, layer=layer, width=width))


        # right line
        kicad_mod.append(Line(start=[x2+O, y1-O+R], end=[x2+O, y2+O-R], layer=layer, width=width))

        # top right
        kicad_mod.append(Arc(center=[x2+O-R, y1-O+R], start=[x2+O-R, y1-O], angle=90.0, layer=layer, width=width))

        # bottom right
        kicad_mod.append(Arc(center=[x2+O-R, y2+O-R], start=[x2+O, y2+O-R], angle=90.0, layer=layer, width=width))


    draw_outline()
    draw_outline(offset=configuration['silk_fab_offset'], layer='F.SilkS', width=configuration['silk_line_width'])

    # Add pin-1 marker on F.SilkS
    Q = 0.35 # offset
    L = 1.5
    p1 = [
        {'x': x1 - Q, 'y': y1 - Q + L},
        {'x': x1 - Q, 'y': y1 - Q},
        {'x': x1 - Q + L, 'y': y1 - Q},
    ]

    kicad_mod.append(PolygoneLine(polygone=p1, layer='F.SilkS', width=configuration['silk_line_width']))

    # Add pin-1 marker on F.Fab
    D = -0.5 - pad_size[1] / 2
    M = 0.75
    p1 = [
        {'x': -M/2, 'y': D - M},
        {'x': M/2, 'y': D - M},
        {'x': 0, 'y': D},
        {'x': -M/2, 'y': D - M},
    ]

    kicad_mod.append(PolygoneLine(polygone=p1, layer='F.Fab', width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='left')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, params, configuration):
    pad_silk_off = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2
    mpn = part_code.format(n=pins*number_of_rows)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)
    footprint_name += params['fp_name_suffix']

    kicad_mod = Footprint(footprint_name)
    desc_format_str = "Molex {:s}, {:s}{:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(desc_format_str.format(series_long, mpn, params['description'], pins, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #calculate fp dimensions
    #ref: http://www.molex.com/pdm_docs/sd/439151404_sd.pdf
    #A = distance between mounting holes
    A = pins * pitch + 1.41

    #B = distance between end pin centers
    B = (pins - 1) * pitch

    #E = length of part
    E = pins * pitch + 0.9

    #connector width
    W = 19.16

    #corner positions
    y1 = -(E-B)/2
    y2 = y1 + E

    x1 = -1.15
    x2 = x1 + W

    TL = 5
    TW = 13

    body_edge={
        'left':x1,
        'right':x2,
        'bottom':y2,
        'top': y1
        }
    bounding_box = {
        'left': -pad_size[0]/2,
        'right': pitch_row + offset_second_pad + pad_size[0]/2
    }

    pad_silk_off = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2

    #generate the pads
    for row_idx in range(2):
        for pad_idx in range(2):
            kicad_mod.append(PadArray(
                pincount=pins, start=[row_idx*pitch_row + pad_idx*offset_second_pad, 0],
                initial=row_idx*pins+1, y_spacing=pitch, size=pad_size, drill=drill,
                type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_THT,
                tht_pad1_shape=Pad.SHAPE_RECT))

    #thermal vias

    d_small = 0.3
    s_small = d_small + 2*min_annular_ring
    thermal_to_pad_edge = s_small/2 + 0.15

    if params['thermals']:
        for yi in range(pins):
            for xi in range(number_of_rows):
                n = xi*pins + yi + 1
                pad_center_x = xi*pitch_row + offset_second_pad/2
                pad_center_y = yi*pitch
                pad_l = offset_second_pad + pad_size[0]
                dy = (pad_size[1] - 2*thermal_to_pad_edge)/2
                dx = (pad_l - 2*thermal_to_pad_edge)/4

                #draw rectangle on F.Fab layer

                # kicad_mod.append(RectLine(
                #     start=[pad_center_x - pad_l/2, pad_center_y - pad_size[1]/2],
                #     end=[pad_center_x + pad_l/2, pad_center_y + pad_size[1]/2],
                #     layer='F.Fab', width=configuration['fab_line_width']))

                kicad_mod.append(PadArray(center=[pad_center_x, pad_center_y],
                    pincount=3, x_spacing=dx*2,
                    drill=d_small, size=s_small, initial=n, increment=0,
                    shape=Pad.SHAPE_CIRCLE, type=Pad.TYPE_THT, layers=Pad.LAYERS_THT))
                kicad_mod.append(PadArray(center=[pad_center_x, pad_center_y - dy],
                    pincount=5, x_spacing=dx,
                    drill=d_small, size=s_small, initial=n, increment=0,
                    type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, layers=Pad.LAYERS_THT))
                kicad_mod.append(PadArray(center=[pad_center_x, pad_center_y + dy],
                    pincount=5, x_spacing=dx,
                    drill=d_small, size=s_small, initial=n, increment=0,
                    type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, layers=Pad.LAYERS_THT))

    # locating pins
    kicad_mod.append(Pad(at=[x_loc, 5], type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
        size=r_loc, drill=r_loc, layers=Pad.LAYERS_NPTH))
    kicad_mod.append(Pad(at=[x_loc, B/2-A/2], type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE,
        size=r_loc+0.5, drill=r_loc, layers=Pad.LAYERS_THT))
    kicad_mod.append(Pad(at=[x_loc, B/2+A/2], type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE,
        size=r_loc+0.5, drill=r_loc, layers=Pad.LAYERS_THT))

    #mark pin-1 (bottom layer)
    kicad_mod.append(RectLine(start=[-pad_size[0]/2, -pad_size[1]/2],
        end=[offset_second_pad + pad_size[0]/2,pad_size[1]/2],offset=pad_silk_off,
        width=configuration['silk_line_width'], layer='B.SilkS'))

    #draw connector outline (basic)
    kicad_mod.append(RectLine(start=[x1,y1],end=[x2,y2],
        width=configuration['fab_line_width'], layer='F.Fab'))

    #connector outline on F.SilkScreen
    off = configuration['silk_line_width']
    corner = [
        {'y': -pad_size[1]/2 - pad_silk_off, 'x': x1-off},
        {'y': y1 - off, 'x': x1-off},
        {'y': y1 - off, 'x': x_loc-r_loc/2-0.5},
    ]

    # kicad_mod.append(PolygoneLine(polygone=corner,
    #     width=configuration['silk_line_width'], layer='F.SilkS'))
    kicad_mod.append(Line(start=[x_loc-r_loc/2-0.5, y1 - off],
        end=[x_loc-TW/2-off, y1 - off],
        width=configuration['silk_line_width'], layer='F.SilkS'))

    kicad_mod.append(PolygoneLine(polygone=corner,y_mirror=B/2,
        width=configuration['silk_line_width'], layer='F.SilkS'))
    kicad_mod.append(PolygoneLine(polygone=corner,x_mirror=x_loc,
        width=configuration['silk_line_width'], layer='F.SilkS'))
    kicad_mod.append(PolygoneLine(polygone=corner,y_mirror=B/2,x_mirror=x_loc,
        width=configuration['silk_line_width'], layer='F.SilkS'))

    #silk-screen between each pad

    for i in range(pins-1):
        ya = i * pitch + pad_size[1]/2 + pad_silk_off
        yb = (i+1) * pitch - pad_size[1]/2 - pad_silk_off

        kicad_mod.append(Line(start=[x1-off, ya],end=[x1-off, yb],
            width=configuration['silk_line_width'], layer='F.SilkS'))
        kicad_mod.append(Line(start=[x2+off, ya],end=[x2+off, yb],
            width=configuration['silk_line_width'], layer='F.SilkS'))

    #draw the tabs at each end
    def offsetPoly(poly_points, o , center_x, center_y):
        new_points = []
        for point in poly_points:
            new_points.append(
                {
                'y': point['y'] + (o if point['y'] > center_y else -o),
                'x': point['x'] + (o if point['x'] > center_x else -o)
                }
            )
        return new_points

    tab = [
        {'y': y1,'x': x_loc-TW/2},
        {'y': y1-TL,'x': x_loc-TW/2},
        {'y': y1-TL,'x': x_loc+TW/2},
        {'y': y1,'x': x_loc+TW/2},
    ]

    kicad_mod.append(PolygoneLine(polygone=tab,
        width=configuration['fab_line_width'], layer='F.Fab'))
    kicad_mod.append(PolygoneLine(polygone=tab, y_mirror=B/2,
        width=configuration['fab_line_width'], layer='F.Fab'))

    tap_off = offsetPoly(tab, off, x_loc, B/2)
    kicad_mod.append(PolygoneLine(polygone=tap_off,
        width=configuration['silk_line_width'], layer='F.SilkS'))
    kicad_mod.append(PolygoneLine(polygone=tap_off, y_mirror=B/2,
        width=configuration['silk_line_width'], layer='F.SilkS'))

    bounding_box['top'] = y1 - TL
    bounding_box['bottom'] = y2 + TL

    #inner-tab
    T = 2
    tab = [
        {'y': y1-off,'x': x_loc-TW/2-off+T},
        {'y': y1-off-TL+T,'x': x_loc-TW/2-off+T},
        {'y': y1-off-TL+T,'x': x_loc+TW/2+off-T},
        {'y': y1-off,'x': x_loc+TW/2+off-T},
    ]

    kicad_mod.append(PolygoneLine(polygone=tab,
        width=configuration['silk_line_width'], layer='F.SilkS'))
    kicad_mod.append(PolygoneLine(polygone=tab,y_mirror=B/2,
        width=configuration['silk_line_width'], layer='F.SilkS'))

    #pin-1 marker
    x = x1 - 1.5
    m = 0.4

    pin = [
    {'x': x,'y': 0},
    {'x': x-2*m,'y': -m},
    {'x': x-2*m,'y': +m},
    {'x': x,'y': 0},
    ]

    kicad_mod.append(PolygoneLine(polygone=pin,
        width=configuration['silk_line_width'], layer='F.SilkS'))

    sl=3
    pin = [
        {'x': body_edge['left'], 'y': -sl/2},
        {'x': body_edge['left'] + sl/sqrt(2), 'y': 0},
        {'x': body_edge['left'], 'y': sl/2}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin,
        width=configuration['fab_line_width'], layer='F.Fab'))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom'] + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(idx, pincount, series_definition, configuration,
                           group_definition):
    if 'mpn_param_1' in series_definition:
        mpn_param_1 = series_definition['mpn_param_1']
        mpn = series_definition['mpn_format_string'].format(
            pincount=pincount, param_1=mpn_param_1[idx])
    else:
        mpn = series_definition['mpn_format_string'].format(pincount=pincount)

    pins_toward_bottom = series_definition['pad1_position'] == 'bottom-left'
    needs_additional_silk_pin1_marker = False

    pad_size = [
        series_definition['pad_size_x'],
        series_definition['rel_pad_y_outside_edge'] -
        series_definition['rel_pad_y_inside_edge']
    ]
    pad_pos_y = -series_definition['rel_pad_y_outside_edge'] / 2 + pad_size[
        1] / 2

    mounting_pad_size = series_definition['mounting_pad_size']
    mount_pad_y_pos = series_definition[
        'rel_pad_y_outside_edge'] / 2 - mounting_pad_size[1] / 2
    if 'center_shift_y' in series_definition:
        mount_pad_y_pos -= series_definition['center_shift_y']
        pad_pos_y -= series_definition['center_shift_y']
    mount_pad_center_x_to_pin = series_definition[
        'center_pad_to_mounting_pad_edge'] + mounting_pad_size[0] / 2.0

    # center pin 1 to center pin n
    dimension_A = (pincount - 1) * series_definition['pitch']

    body_edge = {}
    if pins_toward_bottom:
        pad_pos_y *= -1
        mount_pad_y_pos *= -1
        mount_pad_edge_y_outside = mount_pad_y_pos - mounting_pad_size[1] / 2
        body_edge['top'] = mount_pad_edge_y_outside - series_definition[
            'rel_body_edge_y']
        body_edge[
            'bottom'] = body_edge['top'] + series_definition['body_size_y']
    else:
        mount_pad_edge_y_outside = mount_pad_y_pos + mounting_pad_size[1] / 2
        body_edge['bottom'] = mount_pad_edge_y_outside + series_definition[
            'rel_body_edge_y']
        body_edge[
            'top'] = body_edge['bottom'] - series_definition['body_size_y']

    body_edge['right'] = dimension_A / 2 + series_definition['rel_body_edge_x']
    body_edge['left'] = -body_edge['right']

    orientation = configuration['orientation_options'][
        series_definition['orientation']]
    footprint_name = configuration['fp_name_format_string'].format(
        man=group_definition['manufacturer'],
        series=series_definition['series'],
        mpn=mpn,
        num_rows=1,
        pins_per_row=pincount,
        pitch=series_definition['pitch'],
        orientation=orientation)
    footprint_name = footprint_name.replace('__', '_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "{:s} {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator"
        .format(group_definition['manufacturer'], series_definition['series'],
                mpn, series_definition['datasheet']))
    kicad_mod.setAttribute('smd')
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series_definition['series'],
        orientation=orientation,
        man=group_definition['manufacturer'],
        entry=configuration['entry_direction'][
            series_definition['orientation']]))

    ############################# Pads ##################################
    kicad_mod.append(
        PadArray(center=[0, pad_pos_y],
                 x_spacing=series_definition['pitch'],
                 pincount=pincount,
                 size=pad_size,
                 type=Pad.TYPE_SMT,
                 shape=Pad.SHAPE_RECT,
                 layers=Pad.LAYERS_SMT))

    mount_pad_left_x_pos = -dimension_A / 2 - mount_pad_center_x_to_pin
    kicad_mod.append(
        Pad(number='""',
            type=Pad.TYPE_SMT,
            shape=Pad.SHAPE_RECT,
            at=[mount_pad_left_x_pos, mount_pad_y_pos],
            size=mounting_pad_size,
            layers=Pad.LAYERS_SMT))
    kicad_mod.append(
        Pad(number='""',
            type=Pad.TYPE_SMT,
            shape=Pad.SHAPE_RECT,
            at=[-mount_pad_left_x_pos, mount_pad_y_pos],
            size=mounting_pad_size,
            layers=Pad.LAYERS_SMT))

    ######################### Body outline ###############################
    pad_edge_silk_center_offset = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2
    pad_1_x_outside_edge = -dimension_A / 2 - pad_size[0] / 2

    if pins_toward_bottom:  #Man i wish there where a rotate footprint function available.
        body_edge_pin = body_edge['bottom']
        body_edge_mount_pad = body_edge['top']
        silk_y_mp_pin_side = mount_pad_y_pos + mounting_pad_size[
            1] / 2 + pad_edge_silk_center_offset
        mp_edge_outside = mount_pad_y_pos - mounting_pad_size[1] / 2
        silk_y_mp_outside = mp_edge_outside - pad_edge_silk_center_offset
        pin_edge_outside = pad_pos_y + pad_size[1] / 2
        silk_y_offset_pin_side = configuration['silk_fab_offset']
    else:
        body_edge_pin = body_edge['top']
        body_edge_mount_pad = body_edge['bottom']
        silk_y_mp_pin_side = mount_pad_y_pos - mounting_pad_size[
            1] / 2 - pad_edge_silk_center_offset
        mp_edge_outside = mount_pad_y_pos + mounting_pad_size[1] / 2
        silk_y_mp_outside = mp_edge_outside + pad_edge_silk_center_offset
        pin_edge_outside = pad_pos_y - pad_size[1] / 2
        silk_y_offset_pin_side = -configuration['silk_fab_offset']

    # Pin side
    bounding_box_y_pin_side = pad_pos_y + (
        pad_size[1] / 2 if pins_toward_bottom else -pad_size[1] / 2)
    side_line_y_pin_side = body_edge_pin
    mp_inner_edge_x_left_silk = mount_pad_left_x_pos + mounting_pad_size[
        0] / 2 + pad_edge_silk_center_offset
    modified_pinside_x_inner = body_edge['left']
    if 'edge_modifier_pin_side' in series_definition:
        modifier = series_definition['edge_modifier_pin_side']
        modified_pinside_x_inner = body_edge['left'] + modifier['width']

        if pins_toward_bottom:
            side_line_y_pin_side += modifier['length']
            if side_line_y_pin_side > bounding_box_y_pin_side:
                bounding_box_y_pin_side = side_line_y_pin_side
        else:
            side_line_y_pin_side -= modifier['length']
            if side_line_y_pin_side < bounding_box_y_pin_side:
                bounding_box_y_pin_side = side_line_y_pin_side

        poly_fab_pin_side = [{
            'x': body_edge['left'],
            'y': side_line_y_pin_side
        }, {
            'x': modified_pinside_x_inner,
            'y': side_line_y_pin_side
        }, {
            'x': modified_pinside_x_inner,
            'y': body_edge_pin
        }, {
            'x': -modified_pinside_x_inner,
            'y': body_edge_pin
        }, {
            'x': -modified_pinside_x_inner,
            'y': side_line_y_pin_side
        }, {
            'x': body_edge['right'],
            'y': side_line_y_pin_side
        }]

        if modifier['length'] < 0:
            silk_x_offset = -configuration['silk_fab_offset']
        else:
            silk_x_offset = configuration['silk_fab_offset']

        if modified_pinside_x_inner + silk_x_offset > pad_1_x_outside_edge - pad_edge_silk_center_offset:
            poly_silk_edge_left = [{
                'x':
                body_edge['left'] - configuration['silk_fab_offset'],
                'y':
                silk_y_mp_pin_side
            }, {
                'x':
                body_edge['left'] - configuration['silk_fab_offset'],
                'y':
                side_line_y_pin_side + silk_y_offset_pin_side
            }, {
                'x':
                pad_1_x_outside_edge - pad_edge_silk_center_offset,
                'y':
                side_line_y_pin_side + silk_y_offset_pin_side
            }, {
                'x': pad_1_x_outside_edge - pad_edge_silk_center_offset,
                'y': pin_edge_outside
            }]
            if abs(pin_edge_outside) - abs(
                    side_line_y_pin_side + silk_y_offset_pin_side
            ) < configuration['silk_line_lenght_min']:
                needs_additional_silk_pin1_marker = True

            poly_silk_edge_right = [{
                'x':
                body_edge['right'] + configuration['silk_fab_offset'],
                'y':
                silk_y_mp_pin_side
            }, {
                'x':
                body_edge['right'] + configuration['silk_fab_offset'],
                'y':
                side_line_y_pin_side + silk_y_offset_pin_side
            }, {
                'x':
                -pad_1_x_outside_edge + pad_edge_silk_center_offset,
                'y':
                side_line_y_pin_side + silk_y_offset_pin_side
            }]

        else:
            poly_silk_edge_left = [{
                'x':
                body_edge['left'] - configuration['silk_fab_offset'],
                'y':
                silk_y_mp_pin_side
            }, {
                'x':
                body_edge['left'] - configuration['silk_fab_offset'],
                'y':
                side_line_y_pin_side + silk_y_offset_pin_side
            }, {
                'x':
                modified_pinside_x_inner + silk_x_offset,
                'y':
                side_line_y_pin_side + silk_y_offset_pin_side
            }, {
                'x': modified_pinside_x_inner + silk_x_offset,
                'y': body_edge_pin + silk_y_offset_pin_side
            }, {
                'x': pad_1_x_outside_edge - pad_edge_silk_center_offset,
                'y': body_edge_pin + silk_y_offset_pin_side
            }, {
                'x': pad_1_x_outside_edge - pad_edge_silk_center_offset,
                'y': pin_edge_outside
            }]
            if abs(pin_edge_outside) - abs(
                    body_edge_pin + silk_y_offset_pin_side
            ) < configuration['silk_line_lenght_min']:
                needs_additional_silk_pin1_marker = True

            poly_silk_edge_right = [{
                'x':
                body_edge['right'] + configuration['silk_fab_offset'],
                'y':
                silk_y_mp_pin_side
            }, {
                'x':
                body_edge['right'] + configuration['silk_fab_offset'],
                'y':
                side_line_y_pin_side + silk_y_offset_pin_side
            }, {
                'x':
                -modified_pinside_x_inner - silk_x_offset,
                'y':
                side_line_y_pin_side + silk_y_offset_pin_side
            }, {
                'x': -modified_pinside_x_inner - silk_x_offset,
                'y': body_edge_pin + silk_y_offset_pin_side
            }, {
                'x': -pad_1_x_outside_edge + pad_edge_silk_center_offset,
                'y': body_edge_pin + silk_y_offset_pin_side
            }]
    else:
        poly_fab_pin_side = [{
            'x': body_edge['left'],
            'y': body_edge_pin
        }, {
            'x': body_edge['right'],
            'y': body_edge_pin
        }]
        poly_silk_edge_left = [{
            'x':
            body_edge['left'] - configuration['silk_fab_offset'],
            'y':
            silk_y_mp_pin_side
        }, {
            'x':
            body_edge['left'] - configuration['silk_fab_offset'],
            'y':
            side_line_y_pin_side + silk_y_offset_pin_side
        }, {
            'x': pad_1_x_outside_edge - pad_edge_silk_center_offset,
            'y': body_edge_pin + silk_y_offset_pin_side
        }, {
            'x': pad_1_x_outside_edge - pad_edge_silk_center_offset,
            'y': pin_edge_outside
        }]
        if abs(pin_edge_outside) - abs(body_edge_pin +
                                       silk_y_offset_pin_side) < configuration[
                                           'silk_line_lenght_min']:
            needs_additional_silk_pin1_marker = True

        poly_silk_edge_right = [{
            'x':
            body_edge['right'] + configuration['silk_fab_offset'],
            'y':
            silk_y_mp_pin_side
        }, {
            'x':
            body_edge['right'] + configuration['silk_fab_offset'],
            'y':
            side_line_y_pin_side + silk_y_offset_pin_side
        }, {
            'x': -pad_1_x_outside_edge + pad_edge_silk_center_offset,
            'y': body_edge_pin + silk_y_offset_pin_side
        }]
    kicad_mod.append(
        PolygoneLine(polygone=poly_fab_pin_side,
                     layer='F.Fab',
                     width=configuration['fab_line_width']))
    if series_definition.get('no_automatic_silk_autline', 'False') != 'True':
        kicad_mod.append(
            PolygoneLine(polygone=poly_silk_edge_left,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))
        kicad_mod.append(
            PolygoneLine(polygone=poly_silk_edge_right,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))

    # Mount pad side
    bounding_box_y_mount_pad_side = mount_pad_y_pos + (
        -mounting_pad_size[1] /
        2 if pins_toward_bottom else mounting_pad_size[1] / 2)
    if abs(bounding_box_y_mount_pad_side) < abs(body_edge_mount_pad):
        bounding_box_y_mount_pad_side = body_edge_mount_pad
    mid_line_y_mount_pad_side = body_edge_mount_pad
    if 'edge_modifier_mount_pad_side' in series_definition:
        modifier = series_definition['edge_modifier_mount_pad_side']

        if 'width_start' in modifier:
            modified_mp_start_x_inner = -modifier[
                'width_start'] / 2  # We assume centered body!
        if 'start_from_body_side' in modifier:
            modified_mp_start_x_inner = body_edge['left'] + modifier[
                'start_from_body_side']
        modified_mp_end_x_inner = modified_mp_start_x_inner
        if 'width_end' in modifier:
            modified_mp_end_x_inner = -modifier[
                'width_end'] / 2  # We assume centered body!
        if 'end_from_body_side' in modifier:
            modified_mp_end_x_inner = body_edge['left'] + modifier[
                'end_from_body_side']

        if pins_toward_bottom:
            mid_line_y_mount_pad_side += modifier['depth']
            if mid_line_y_mount_pad_side < bounding_box_y_mount_pad_side:
                bounding_box_y_mount_pad_side = mid_line_y_mount_pad_side
        else:
            mid_line_y_mount_pad_side -= modifier['depth']
            if mid_line_y_mount_pad_side > bounding_box_y_mount_pad_side:
                bounding_box_y_mount_pad_side = mid_line_y_mount_pad_side

        if modifier['depth'] < 0:
            silk_x_offset = -configuration['silk_fab_offset']
        else:
            silk_x_offset = configuration['silk_fab_offset']

        poly_fab_mp_side = [{
            'x': body_edge['left'],
            'y': body_edge_mount_pad
        }, {
            'x': modified_mp_start_x_inner,
            'y': body_edge_mount_pad
        }, {
            'x': modified_mp_end_x_inner,
            'y': mid_line_y_mount_pad_side
        }, {
            'x': -modified_mp_end_x_inner,
            'y': mid_line_y_mount_pad_side
        }, {
            'x': -modified_mp_start_x_inner,
            'y': body_edge_mount_pad
        }, {
            'x': body_edge['right'],
            'y': body_edge_mount_pad
        }]

        poly_silk_mp_side = [{
            'x': mp_inner_edge_x_left_silk,
            'y': body_edge_mount_pad - silk_y_offset_pin_side
        }, {
            'x': modified_mp_start_x_inner + silk_x_offset,
            'y': body_edge_mount_pad - silk_y_offset_pin_side
        }, {
            'x':
            modified_mp_end_x_inner + silk_x_offset,
            'y':
            mid_line_y_mount_pad_side - silk_y_offset_pin_side
        }, {
            'x':
            -modified_mp_end_x_inner - silk_x_offset,
            'y':
            mid_line_y_mount_pad_side - silk_y_offset_pin_side
        }, {
            'x': -modified_mp_start_x_inner - silk_x_offset,
            'y': body_edge_mount_pad - silk_y_offset_pin_side
        }, {
            'x': -mp_inner_edge_x_left_silk,
            'y': body_edge_mount_pad - silk_y_offset_pin_side
        }]
        if modified_mp_start_x_inner + configuration[
                'silk_fab_offset'] < mp_inner_edge_x_left_silk:
            poly_silk_mp_side = [{
                'x':
                mp_inner_edge_x_left_silk,
                'y':
                mid_line_y_mount_pad_side - silk_y_offset_pin_side
            }, {
                'x':
                -mp_inner_edge_x_left_silk,
                'y':
                mid_line_y_mount_pad_side - silk_y_offset_pin_side
            }]
    else:
        poly_fab_mp_side = [{
            'x': body_edge['left'],
            'y': body_edge_mount_pad
        }, {
            'x': body_edge['right'],
            'y': body_edge_mount_pad
        }]
        poly_silk_mp_side = [{
            'x': mp_inner_edge_x_left_silk,
            'y': body_edge_mount_pad - silk_y_offset_pin_side
        }, {
            'x': -mp_inner_edge_x_left_silk,
            'y': body_edge_mount_pad - silk_y_offset_pin_side
        }]

    if series_definition['rel_body_edge_y'] > pad_edge_silk_center_offset:
        poly_silk_mp_side[0]['x'] = body_edge['left']
        poly_silk_mp_side[len(poly_silk_mp_side) - 1]['x'] = body_edge['right']

    if series_definition[
            'rel_body_edge_y'] > pad_edge_silk_center_offset + configuration[
                'silk_line_lenght_min']:
        poly_silk_mp_side[0][
            'x'] = body_edge['left'] - configuration['silk_fab_offset']
        poly_silk_mp_side[
            len(poly_silk_mp_side) -
            1]['x'] = body_edge['right'] + configuration['silk_fab_offset']

        poly_silk_mp_side.insert(
            0, {
                'x': body_edge['left'] - configuration['silk_fab_offset'],
                'y': silk_y_mp_outside
            })
        poly_silk_mp_side.append({
            'x':
            body_edge['right'] + configuration['silk_fab_offset'],
            'y':
            silk_y_mp_outside
        })

    if series_definition.get('no_automatic_silk_autline', 'False') != 'True':
        kicad_mod.append(
            PolygoneLine(polygone=poly_silk_mp_side,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))

    kicad_mod.append(
        PolygoneLine(polygone=poly_fab_mp_side,
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    kicad_mod.append(
        Line(start=[body_edge['left'], side_line_y_pin_side],
             end=[body_edge['left'], body_edge_mount_pad],
             layer='F.Fab',
             width=configuration['fab_line_width']))

    kicad_mod.append(
        Line(start=[body_edge['right'], side_line_y_pin_side],
             end=[body_edge['right'], body_edge_mount_pad],
             layer='F.Fab',
             width=configuration['fab_line_width']))

    ###################### Additional Drawing ###########################
    if 'additional_drawing' in series_definition:
        for drawing in series_definition['additional_drawing']:
            parseAdditionalDrawing(kicad_mod, drawing, configuration,
                                   series_definition, body_edge, pincount)

    ############################# CrtYd ##################################
    mp_left_edge = mount_pad_left_x_pos - mounting_pad_size[0] / 2
    bounding_box_x1 = body_edge[
        'left'] if body_edge['left'] < mp_left_edge else mp_left_edge
    bounding_box_x2 = -bounding_box_x1
    if pins_toward_bottom:
        bounding_box_y1 = bounding_box_y_mount_pad_side
        bounding_box_y2 = bounding_box_y_pin_side

    else:
        bounding_box_y1 = bounding_box_y_pin_side
        bounding_box_y2 = bounding_box_y_mount_pad_side

    cx1 = roundToBase(
        bounding_box_x1 - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cx2 = roundToBase(
        bounding_box_x2 + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cy1 = roundToBase(
        bounding_box_y1 - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        bounding_box_y2 + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ######################### Pin 1 marker ##############################

    if series_definition['pad1_position'] == 'bottom-left':
        poly_pin1_marker = [{
            'x':
            -dimension_A / 2 - configuration['fab_pin1_marker_length'] / 2,
            'y':
            body_edge['bottom']
        }, {
            'x':
            -dimension_A / 2,
            'y':
            body_edge['bottom'] -
            configuration['fab_pin1_marker_length'] / sqrt(2)
        }, {
            'x':
            -dimension_A / 2 + configuration['fab_pin1_marker_length'] / 2,
            'y':
            body_edge['bottom']
        }]
        poly_pin1_marker_small = [{
            'x':
            -dimension_A / 2 - configuration['fab_pin1_marker_length'] / 4,
            'y':
            cy2 + configuration['fab_pin1_marker_length'] / sqrt(8)
        }, {
            'x': -dimension_A / 2,
            'y': cy2
        }, {
            'x':
            -dimension_A / 2 + configuration['fab_pin1_marker_length'] / 4,
            'y':
            cy2 + configuration['fab_pin1_marker_length'] / sqrt(8)
        }, {
            'x':
            -dimension_A / 2 - configuration['fab_pin1_marker_length'] / 4,
            'y':
            cy2 + configuration['fab_pin1_marker_length'] / sqrt(8)
        }]
    else:
        poly_pin1_marker = [{
            'x':
            -dimension_A / 2 - configuration['fab_pin1_marker_length'] / 2,
            'y':
            body_edge['top']
        }, {
            'x':
            -dimension_A / 2,
            'y':
            body_edge['top'] +
            configuration['fab_pin1_marker_length'] / sqrt(2)
        }, {
            'x':
            -dimension_A / 2 + configuration['fab_pin1_marker_length'] / 2,
            'y':
            body_edge['top']
        }]
        poly_pin1_marker_small = [{
            'x':
            -dimension_A / 2 - configuration['fab_pin1_marker_length'] / 4,
            'y':
            cy1 - configuration['fab_pin1_marker_length'] / sqrt(8)
        }, {
            'x': -dimension_A / 2,
            'y': cy1
        }, {
            'x':
            -dimension_A / 2 + configuration['fab_pin1_marker_length'] / 4,
            'y':
            cy1 - configuration['fab_pin1_marker_length'] / sqrt(8)
        }, {
            'x':
            -dimension_A / 2 - configuration['fab_pin1_marker_length'] / 4,
            'y':
            cy1 - configuration['fab_pin1_marker_length'] / sqrt(8)
        }]

    if modified_pinside_x_inner < -dimension_A / 2 - configuration[
            'fab_pin1_marker_length'] / 2:
        kicad_mod.append(
            PolygoneLine(polygone=poly_pin1_marker,
                         layer='F.Fab',
                         width=configuration['fab_line_width']))
    else:
        kicad_mod.append(
            PolygoneLine(polygone=poly_pin1_marker_small,
                         layer='F.Fab',
                         width=configuration['fab_line_width']))

    if needs_additional_silk_pin1_marker:
        kicad_mod.append(
            PolygoneLine(polygone=poly_pin1_marker_small,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))

    ######################### Text Fields ###############################
    text_center = series_definition.get('text_inside_pos', 'center')
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position=text_center)

    ########################### file names ###############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(
        man=group_definition['manufacturer'],
        series=series_definition['series'])
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pol, n, configuration):
    off = configuration['silk_fab_offset']
    CrtYd_offset = configuration['courtyard_offset']['default']
    fp_name = 'Samtec_MECF-' + n + '-0_-'
    if pol == False:
        fp_name = fp_name + 'NP-'
    fp_name += 'L-DV'

    fp_name += '_{:d}x{:02d}_P{:.2f}mm'.format(2,int(n),1.27)
    if pol:
        fp_name += '_Polarized'
    fp_name += '_Edge'

    kicad_mod = Footprint(fp_name)

    description = "Highspeed card edge connector for PCB's with " + n + " contacts "

    if pol == True:
        description = description + '(polarized)'
    else:
        description = description + '(not polarized)'

    kicad_mod.setAttribute('virtual')

    #set the FP description
    kicad_mod.setDescription(description)

    tags = "conn samtec card-edge high-speed"

    #set the FP tags
    kicad_mod.setTags(tags)


    # set general values

    top = -(5.0)
    bot =  (5.0)

    left = -(K[n]/2.0)
    right = (K[n]/2.0)
    body_edge={
        'left': left,
        'right': right,
        'top': top,
        'bottom': bot
    }

    top_left =  [left, top]
    bot_right = [ right, bot]

    # create Fab Back(exact outline)
    kicad_mod.append(Line(start=[left + 1.27, bot], end=[right, bot],
        layer='F.Fab', width=configuration['fab_line_width']))   #bot line
    kicad_mod.append(Line(start=[left, top], end=[ right, top],
        layer='F.Fab', width=configuration['fab_line_width']))   #top line
    kicad_mod.append(Line(start=[left, bot - 1.27], end=[left, top],
        layer='F.Fab', width=configuration['fab_line_width']))   #left line
    kicad_mod.append(Line(start=[right, bot], end=[ right, top],
        layer='F.Fab', width=configuration['fab_line_width']))   #right line
    kicad_mod.append(Line(start=[left, bot - 1.27], end=[left + 1.27, bot],
        layer='F.Fab', width=configuration['fab_line_width']))   #corner

    # create Fab Front(exact outline)
    kicad_mod.append(Line(start=[left, bot], end=[right, bot],
        layer='B.Fab', width=configuration['fab_line_width']))   #bot line
    kicad_mod.append(Line(start=[left, top], end=[ right, top],
        layer='B.Fab', width=configuration['fab_line_width']))   #top line
    kicad_mod.append(Line(start=[left, bot ], end=[left, top],
        layer='B.Fab', width=configuration['fab_line_width']))   #left line
    kicad_mod.append(Line(start=[right, bot], end=[ right, top],
        layer='B.Fab', width=configuration['fab_line_width']))   #right line


    top = top - off
    #bot = bot + 0.11
    left = left - off
    right = right + off

    # create silscreen Back(exact + 0.11)
    kicad_mod.append(Line(start=[round(left, 2) + 1.27, round(bot, 2)],
                          end=[round(right, 2), round(bot, 2)],
                          layer='F.SilkS', width=configuration['silk_line_width'])) #bot line
    kicad_mod.append(Line(start=[round(left, 2), round(top, 2)],
                          end=[round(right, 2), round(top, 2)],
                          layer='F.SilkS', width=configuration['silk_line_width'])) #top line
    kicad_mod.append(Line(start=[round(left, 2), round(bot, 2) - 1.27],
                          end=[round(left, 2), round(top, 2)],
                          layer='F.SilkS', width=configuration['silk_line_width'])) #left line
    kicad_mod.append(Line(start=[round(right, 2), round( bot, 2)],
                          end=[round(right, 2), round(top, 2)],
                          layer='F.SilkS', width=configuration['silk_line_width'])) #right line
    kicad_mod.append(Line(start=[round(left, 2) + 1.27, round(bot, 2) ],
                          end=[round(left, 2), round(bot, 2) - 1.27],
                          layer='F.SilkS', width=configuration['silk_line_width']))   #corner

    # create silscreen Front(exact + 0.11)
    kicad_mod.append(Line(start=[round(left, 2), round(bot, 2)],
                          end=[round(right, 2), round(bot, 2)],
                          layer='B.SilkS', width=configuration['silk_line_width'])) #bot line
    kicad_mod.append(Line(start=[round(left, 2), round(top, 2)],
                          end=[round(right, 2), round(top, 2)],
                          layer='B.SilkS', width=configuration['silk_line_width'])) #top line
    kicad_mod.append(Line(start=[round(left, 2), round(bot, 2)],
                          end=[round(left, 2), round(top, 2)],
                          layer='B.SilkS', width=configuration['silk_line_width'])) #left line
    kicad_mod.append(Line(start=[round(right, 2), round( bot, 2)],
                          end=[round(right, 2), round(top, 2)],
                          layer='B.SilkS', width=configuration['silk_line_width'])) #right line

    top = roundToBase(body_edge['top'] - CrtYd_offset, configuration['courtyard_grid'])
    bot = roundToBase(body_edge['bottom'], configuration['courtyard_grid'])
    left = roundToBase(body_edge['left'] - CrtYd_offset, configuration['courtyard_grid'])
    right = roundToBase(body_edge['right'] + CrtYd_offset, configuration['courtyard_grid'])

    cy1 = top
    cy2 = bot

    # create courtyard (exact + 0.25)
    kicad_mod.append(RectLine(start=[left, top], end=[right , bot],
            layer='F.CrtYd', width=configuration['courtyard_line_width']))
    kicad_mod.append(RectLine(start=[left, top], end=[right , bot],
            layer='B.CrtYd', width=configuration['courtyard_line_width']))




    top = body_edge['top']
    bot =  body_edge['bottom']
    slot_height = 7.0


    ## create cutout
    kicad_mod.append(Line(start=[-K[n]/2.0, bot, 2],
                          end=[-K[n]/2.0, top, 2], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #left line
    kicad_mod.append(Line(start=[K[n]/2.0, bot, 2],
                          end=[K[n]/2.0, top], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #right line


    ## grid ends
    nextGrid = math.ceil((K[n]/2.0)/0.25 + 1.0) * 0.25
    #nextGrid = roundToBase(K[n]/2, 0.25)
    kicad_mod.append(Line(start=[-nextGrid, top, 2],
        end=[-K[n]/2.0, top, 2], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #left line
    kicad_mod.append(Line(start=[+nextGrid, top, 2],
        end=[K[n]/2.0, top], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #right line



    if pol == True:   # Cutouts

        kicad_mod.append(Line(start=[-K[n]/2.0, bot],
                              end=[-K[n]/2.0+L[n]-1.24/2.0, bot], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #bot line

        kicad_mod.append(Line(start=[-K[n]/2.0+L[n]-1.24/2.0, bot],
                              end=[-K[n]/2.0+L[n]-1.24/2.0, bot - slot_height], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #up
        kicad_mod.append(Line(start=[-K[n]/2.0+L[n]+1.24/2.0, bot],
                              end=[-K[n]/2.0+L[n]+1.24/2.0, bot - slot_height], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #down
        kicad_mod.append(Line(start=[-K[n]/2.0+L[n]-1.24/2.0, bot - slot_height],
                              end=[-K[n]/2.0+L[n]+1.24/2.0, bot - slot_height], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #cut

        if n in ['60','70']:
            kicad_mod.append(Line(start=[-K[n]/2.0+L[n]+1.24/2.0, bot],
                              end=[-K[n]/2.0+M[n]-1.24/2.0, bot], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #bot line

            kicad_mod.append(Line(start=[-K[n]/2.0+M[n]-1.24/2.0, bot],
                              end=[-K[n]/2.0+M[n]-1.24/2.0, bot - slot_height], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #up
            kicad_mod.append(Line(start=[-K[n]/2.0+M[n]+1.24/2.0, bot],
                              end=[-K[n]/2.0+M[n]+1.24/2.0, bot - slot_height], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #down
            kicad_mod.append(Line(start=[-K[n]/2.0+M[n]-1.24/2.0, bot - slot_height],
                              end=[-K[n]/2.0+M[n]+1.24/2.0, bot - slot_height], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #cut

            kicad_mod.append(Line(start=[-K[n]/2.0+M[n]+1.24/2.0, bot],
                              end=[K[n]/2.0, bot], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #bot line
        else:
            kicad_mod.append(Line(start=[-K[n]/2.0+L[n]+1.24/2.0, bot],
                              end=[K[n]/2.0, bot], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #bot line

    else:
        kicad_mod.append(Line(start=[-K[n]/2.0, bot],
                              end=[K[n]/2.0, bot], layer='Edge.Cuts', width=configuration['edge_cuts_line_width'])) #bot line



    # create pads
    for i in range(0,int(n)):
        start = - K[n]/2.0 + 1.52

        if pol == True:
            if (i*2+1) not in POL[n]:
                kicad_mod.append(Pad(number=i*2 + 1, type=pad_type, shape=Pad.SHAPE_RECT,
                    at=[start + i*1.27, bot - 2.0 - 0.5], size=pad_size, layers=layers_top))
                kicad_mod.append(Pad(number=i*2 + 2, type=pad_type, shape=Pad.SHAPE_RECT,
                    at=[start + i*1.27, bot - 2.0 - 0.5], size=pad_size, layers=layers_bottom))
        else:
            kicad_mod.append(Pad(number=i*2 + 1, type=pad_type, shape=Pad.SHAPE_RECT,
                at=[start + i*1.27, bot - 2.0 - 0.5], size=pad_size, layers=layers_top))
            kicad_mod.append(Pad(number=i*2 + 2, type=pad_type, shape=Pad.SHAPE_RECT,
                at=[start + i*1.27, bot - 2.0 - 0.5], size=pad_size, layers=layers_bottom))



    # output kicad model
    #print(kicad_mod

    # print render tree
    #print(kicad_mod.getRenderTree())
    #print(kicad_mod.getCompleteRenderTree())

    # kicad_mod.append(Text(type='reference', text='REF**', at=[0,-6.35], layer='F.SilkS'))
    # kicad_mod.append(Text(type='user', text='%R', at=[0,-2.54], layer='F.Fab'))
    # kicad_mod.append(Text(type='value', text=fp_name, at=[0,-3.81], layer='F.Fab'))
    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=fp_name, text_y_inside_position=-2.54)

    lib_name = configuration['lib_name_specific_function_format_string'].format(category=lib_name_category)
    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=fp_name)


    # write file
    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins_per_row, configuration):
    mpn = part_code.format(n=pins_per_row * number_of_rows)
    alt_mpn = [
        code.format(n=pins_per_row * number_of_rows)
        for code in alternative_codes
    ]

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins_per_row,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "Molex {:s}, {:s} (compatible alternatives: {:s}), {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
        .format(series_long, mpn, ', '.join(alt_mpn), pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #calculate fp dimensions
    A = (pins_per_row - 1) * pitch
    B = A + 3.1
    C = A + 4

    #connector thickness
    T = 5.75

    #corners
    x1 = -2
    x2 = x1 + C

    T = 3.65

    y1 = -1.5
    y2 = y1 + T

    off = configuration['silk_fab_offset']
    pad_silk_off = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2

    body_edge = {'left': x1, 'right': x2, 'bottom': y2, 'top': y1}
    bounding_box = body_edge.copy()

    #add simple outline to F.Fab layer
    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    #wall-thickness W
    w = 0.4

    #offset
    o = configuration['silk_fab_offset']
    x1 -= o
    y1 -= o
    x2 += o
    y2 += o

    #generate the pads
    kicad_mod.append(
        PadArray(pincount=pins_per_row,
                 x_spacing=pitch,
                 type=Pad.TYPE_THT,
                 shape=pad_shape,
                 size=pad_size,
                 drill=drill,
                 layers=Pad.LAYERS_THT))

    #draw the courtyard

    #draw the connector outline
    out = RectLine(start=[x1, y1],
                   end=[x2, y2],
                   width=configuration['silk_line_width'],
                   layer="F.SilkS")
    kicad_mod.append(out)

    #pin-1 marker
    y = -2
    m = 0.3

    O = 0.3
    L = 2
    pin = [
        {
            'x': x1 + L,
            'y': y1 - O
        },
        {
            'x': x1 - O,
            'y': y1 - O
        },
        {
            'x': x1 - O,
            'y': y1 + L
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     width=configuration['silk_line_width'],
                     layer="F.SilkS"))

    p1m_sl = 1
    pin = [{
        'x': -p1m_sl / 2,
        'y': body_edge['top']
    }, {
        'x': 0,
        'y': body_edge['top'] + p1m_sl / sqrt(2)
    }, {
        'x': p1m_sl / 2,
        'y': body_edge['top']
    }]
    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     width=configuration['fab_line_width'],
                     layer='F.Fab'))

    kicad_mod.append(
        Line(start=[x1, 2 * w],
             end=[x1 + w, 2 * w],
             width=configuration['silk_line_width'],
             layer="F.SilkS"))
    kicad_mod.append(
        Line(start=[x2, 2 * w],
             end=[x2 - w, 2 * w],
             width=configuration['silk_line_width'],
             layer="F.SilkS"))

    #add the 'wall'
    wall = [
        {
            'x': A / 2,
            'y': y1 + w
        },
        {
            'x': x1 + w,
            'y': y1 + w
        },
        {
            'x': x1 + w,
            'y': 0
        },
        {
            'x': x1 + 2 * w,
            'y': 0
        },
        {
            'x': x1 + 2 * w,
            'y': w
        },
        {
            'x': x1 + w,
            'y': w
        },
        {
            'x': x1 + w,
            'y': y2
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=wall,
                     width=configuration['silk_line_width'],
                     layer="F.SilkS"))
    kicad_mod.append(
        PolygoneLine(polygone=wall,
                     x_mirror=A / 2,
                     width=configuration['silk_line_width'],
                     layer="F.SilkS"))

    ########################### CrtYd #################################
    cx1 = roundToBase(
        bounding_box['left'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = roundToBase(
        bounding_box['top'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cx2 = roundToBase(
        bounding_box['right'] + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        bounding_box['bottom'] +
        configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins_per_row, variant, configuration):
    mpn = variant_params[variant]['part_code'].format(n=pins_per_row*number_of_rows)
    alt_mpn = [code.format(n=pins_per_row*number_of_rows) for code in variant_params[variant]['alternative_codes']]

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Molex {:s}, {:s} (compatible alternatives: {:s}), {:d} Pins per row ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, ', '.join(alt_mpn), pins_per_row, variant_params[variant]['datasheet']))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #kicad_mod.setAttribute('smd')

    ########################## Dimensions ##############################
    B = (pins_per_row-1)*pitch
    A = B + 6.65
    C = B + variant_params[variant]['C_minus_B']

    pad_y = 0
    pad1_x = 0

    peg1_x = (B-C)/2
    peg2_x = (B+C)/2
    peg_y = pad_y - 1.96

    tab_w = 1.4
    tab_l = 1.4

    body_edge={
        'left':  (B-A)/2,
        'right': (A+B)/2,
        'top': -2.47+0.5
        }
    body_edge['bottom'] = body_edge['top'] + (4.37-0.5)

    y_top_min = -2.47
    chamfer={'x': 1.2, 'y': 0.63}

    ############################# Pads ##################################
    #
    # Pegs
    #
    kicad_mod.append(Pad(at=[peg1_x, peg_y], number="",
        type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=peg_drill,
        drill=peg_drill, layers=Pad.LAYERS_NPTH))
    kicad_mod.append(Pad(at=[peg2_x, peg_y], number="",
        type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=peg_drill,
        drill=peg_drill, layers=Pad.LAYERS_NPTH))

    #
    # Add pads
    #
    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(start=[pad1_x, pad_y], initial=1,
        pincount=pins_per_row, increment=1,  x_spacing=pitch, size=pad_size,
        type=Pad.TYPE_THT, shape=pad_shape, layers=Pad.LAYERS_THT, drill=drill,
        **optional_pad_params))

    ######################## Fabrication Layer ###########################
    main_body_poly= [
        {'x': body_edge['left'] + chamfer['x'], 'y': body_edge['top']},
        {'x': body_edge['left'] + chamfer['x'], 'y': y_top_min},
        {'x': body_edge['left'], 'y': y_top_min},
        {'x': body_edge['left'], 'y': body_edge['bottom']},
        {'x': body_edge['right'], 'y': body_edge['bottom']},
        {'x': body_edge['right'], 'y': y_top_min},
        {'x': body_edge['right'] - chamfer['x'], 'y': y_top_min},
        {'x': body_edge['right'] - chamfer['x'], 'y': body_edge['top']},
        {'x': body_edge['left'] + chamfer['x'], 'y': body_edge['top']}
    ]
    kicad_mod.append(PolygoneLine(polygone=main_body_poly,
        width=configuration['fab_line_width'], layer="F.Fab"))

    kicad_mod.append(Line(
        start={
            'x': body_edge['left'],
            'y': body_edge['top'] + chamfer['y']
        },
        end={
            'x': body_edge['left'] + chamfer['x'],
            'y': body_edge['top']
        },
        width=configuration['fab_line_width'], layer="F.Fab"
        ))

    kicad_mod.append(Line(
        start={
            'x': body_edge['right'],
            'y': body_edge['top'] + chamfer['y']
        },
        end={
            'x': body_edge['right'] - chamfer['x'],
            'y': body_edge['top']
        },
        width=configuration['fab_line_width'], layer="F.Fab"
        ))


    tab_poly = [
        {'x': B/2-tab_l/2, 'y': body_edge['bottom']},
        {'x': B/2-tab_l/2, 'y': body_edge['bottom'] + tab_w},
        {'x': B/2+tab_l/2, 'y': body_edge['bottom'] + tab_w},
        {'x': B/2+tab_l/2, 'y': body_edge['bottom']},
    ]
    kicad_mod.append(PolygoneLine(polygone=tab_poly,
        width=configuration['fab_line_width'], layer="F.Fab"))

    p1m_sl = 1
    p1m_poly = tab_poly = [
        {'x': pad1_x - p1m_sl/2, 'y': body_edge['top']},
        {'x': pad1_x, 'y': body_edge['top'] + p1m_sl/sqrt(2)},
        {'x': pad1_x + p1m_sl/2, 'y': body_edge['top']}
    ]
    kicad_mod.append(PolygoneLine(polygone=tab_poly,
        width=configuration['fab_line_width'], layer="F.Fab"))

    ############################ SilkS ##################################
    # Top left corner

    silk_pad_off = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2

    xmp_top1 = peg1_x + peg_drill/2 + silk_pad_off
    xmp_top2 = peg2_x - peg_drill/2 - silk_pad_off
    ymp_bottom = peg_y + peg_drill/2 + silk_pad_off
    off = configuration['silk_fab_offset']

    poly_s_b = [
        {'x': body_edge['left'] - off, 'y': ymp_bottom},
        {'x': body_edge['left'] - off, 'y': body_edge['bottom'] + off},
        {'x': body_edge['right'] + off, 'y': body_edge['bottom'] + off},
        {'x': body_edge['right'] + off, 'y': ymp_bottom},
    ]

    kicad_mod.append(PolygoneLine(polygone=poly_s_b,
        width=configuration['silk_line_width'], layer="F.SilkS"))

    poly_s_t = [
        {'x': xmp_top1 + off, 'y': y_top_min - off},
        {'x': body_edge['left'] + chamfer['x'] + off, 'y': y_top_min - off},
        {'x': body_edge['left'] + chamfer['x'] + off, 'y': body_edge['top'] - off},
        {'x': body_edge['right'] - chamfer['x'] - off, 'y': body_edge['top'] - off},
        {'x': body_edge['right'] - chamfer['x'] - off, 'y': y_top_min - off},
        {'x': xmp_top2 - off, 'y': y_top_min - off},
    ]
    kicad_mod.append(PolygoneLine(polygone=poly_s_t,
        width=configuration['silk_line_width'], layer="F.SilkS"))

    ############################ CrtYd ##################################
    CrtYd_offset = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']

    cy_top = roundToBase(y_top_min - CrtYd_offset, CrtYd_grid)
    cy_bottom = roundToBase(body_edge['bottom'] + tab_w + CrtYd_offset, CrtYd_grid)
    cy_left = roundToBase(body_edge['left'] - CrtYd_offset, CrtYd_grid)
    cy_right = roundToBase(body_edge['right'] + CrtYd_offset, CrtYd_grid)

    poly_cy = [
        {'x': cy_left, 'y':cy_top},
        {'x': cy_right, 'y':cy_top},
        {'x': cy_right, 'y':cy_bottom},
        {'x': cy_left, 'y':cy_bottom},
        {'x': cy_left, 'y':cy_top},
    ]

    kicad_mod.append(PolygoneLine(polygone=poly_cy,
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################

    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy_top, 'bottom':cy_bottom}, fp_name=footprint_name, text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #44
0
def generate_one_footprint(pins, params, configuration):
    pad_silk_off = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2
    mpn = params['mpn'].format(n=pins * params['number_of_rows'])

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=params['number_of_rows'],
        pins_per_row=pins_per_row,
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    desc_format_str = "Molex {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(
        desc_format_str.format(series_long, mpn, pins, params['datasheet']))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    if params['number_of_rows'] == 2:
        pad_size = [
            pitch_row - pad_to_pad_clearance, pitch - pad_to_pad_clearance
        ]
    else:
        pad_size = [drill + 2 * max_annular_ring, pitch - pad_to_pad_clearance]

    if pad_size[1] - drill < 2 * min_annular_ring:
        pad_size[1] = drill + 2 * min_annular_ring
    if pad_size[1] - drill > 2 * max_annular_ring:
        pad_size[1] = drill + 2 * max_annular_ring

    if pad_size[0] - drill < 2 * min_annular_ring:
        pad_size[0] = drill + 2 * min_annular_ring
    if pad_size[0] - drill > 2 * max_annular_ring:
        pad_size[0] = drill + 2 * max_annular_ring

    pad_shape = Pad.SHAPE_OVAL
    if pad_size[0] == pad_size[1]:
        pad_shape = Pad.SHAPE_CIRCLE

    #A = connector length
    A = pins * pitch + 0.94

    #B = pin center distance
    B = (pins - 1) * pitch

    #W = thickness of plastic base
    W = 8.46

    #locating pin position
    C = B

    #corner positions for plastic housing outline
    y1 = -(A - B) / 2
    y2 = y1 + A

    x2 = (params['number_of_rows'] - 1) * pitch_row + 10.38
    x1 = x2 - W

    off = configuration['silk_fab_offset']
    pad_silk_off = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2

    body_edge = {'left': x1, 'right': x2, 'bottom': y2, 'top': y1}
    bounding_box = body_edge.copy()

    bounding_box['left'] = -pad_size[0] / 2

    pad_silk_off = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2

    #generate the pads
    for r in range(params['number_of_rows']):
        kicad_mod.append(
            PadArray(pincount=pins,
                     initial=r * pins + 1,
                     start=[r * pitch_row, 0],
                     y_spacing=pitch,
                     type=Pad.TYPE_THT,
                     shape=pad_shape,
                     size=pad_size,
                     drill=drill,
                     layers=Pad.LAYERS_THT))

    #add the locating pins
    y_loc_a = B / 2 - C / 2
    y_loc_b = B / 2 + C / 2
    x_loc = (params['number_of_rows'] - 1) * pitch_row + 7.18
    r_loc = 1.7
    kicad_mod.append(
        Pad(at=[x_loc, y_loc_a],
            size=r_loc,
            drill=r_loc,
            type=Pad.TYPE_NPTH,
            shape=Pad.SHAPE_CIRCLE,
            layers=Pad.LAYERS_NPTH))
    kicad_mod.append(
        Pad(at=[x_loc, y_loc_b],
            size=r_loc,
            drill=r_loc,
            type=Pad.TYPE_NPTH,
            shape=Pad.SHAPE_CIRCLE,
            layers=Pad.LAYERS_NPTH))

    #add outline to F.Fab
    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 offset=off,
                 width=configuration['silk_line_width'],
                 layer="F.SilkS"))

    #draw the pins
    for i in range(pins):
        y = i * pitch
        x = (params['number_of_rows'] -
             1) * pitch_row + pad_size[0] / 2 + pad_silk_off
        w = 0.15
        kicad_mod.append(
            RectLine(start=[x1 - off, y + w],
                     end=[x, y - w],
                     width=configuration['silk_line_width'],
                     layer="F.SilkS"))

    #pin-1 marker
    y = -pad_size[1] / 2 - pad_silk_off
    m = 0.3

    pin = [
        {
            'x': 0,
            'y': y
        },
        {
            'x': m,
            'y': y - m * sqrt(2)
        },
        {
            'x': -m,
            'y': y - m * sqrt(2)
        },
        {
            'x': 0,
            'y': y
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     width=configuration['silk_line_width'],
                     layer="F.SilkS"))
    kicad_mod.append(
        PolygoneLine(polygone=pin,
                     width=configuration['fab_line_width'],
                     layer='F.Fab'))

    ########################### CrtYd #################################
    cx1 = roundToBase(
        bounding_box['left'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = roundToBase(
        bounding_box['top'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cx2 = roundToBase(
        bounding_box['right'] + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        bounding_box['bottom'] +
        configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
    def __createFootprintVariant(self, device_params, header, dimensions, with_thermal_vias):
        fab_line_width = self.configuration.get('fab_line_width', 0.1)
        silk_line_width = self.configuration.get('silk_line_width', 0.12)

        lib_name = self.configuration['lib_name_format_string'].format(category=header['library_Suffix'])

        size_x = dimensions['body_size_x'].nominal
        size_y = dimensions['body_size_y'].nominal

        pincount = device_params['num_pins_x']*2 + device_params['num_pins_y']*2

        ipc_reference = 'ipc_spec_gw_large_pitch' if device_params['pitch'] >= 0.625 else 'ipc_spec_gw_small_pitch'
        if device_params.get('force_small_pitch_ipc_definition', False):
            ipc_reference = 'ipc_spec_gw_small_pitch'

        used_density = device_params.get('ipc_density', ipc_density)
        ipc_data_set = self.ipc_defintions[ipc_reference][used_density]
        ipc_round_base = self.ipc_defintions[ipc_reference]['round_base']

        pitch = device_params['pitch']

        name_format = self.configuration['fp_name_format_string_no_trailing_zero']
        EP_size = {'x':0, 'y':0}
        EP_mask_size = {'x':0, 'y':0}

        if dimensions['has_EP']:
            name_format = self.configuration['fp_name_EP_format_string_no_trailing_zero']
            if 'EP_size_x_overwrite' in device_params:
                EP_size = {
                    'x':device_params['EP_size_x_overwrite'],
                    'y':device_params['EP_size_y_overwrite']
                    }
            else:
                EP_size = {
                    'x':dimensions['EP_size_x'].nominal,
                    'y':dimensions['EP_size_y'].nominal
                    }
            if 'EP_mask_x' in dimensions:
                name_format = self.configuration['fp_name_EP_custom_mask_format_string_no_trailing_zero']
                EP_mask_size = {'x':dimensions['EP_mask_x'].nominal, 'y':dimensions['EP_mask_y'].nominal}
        EP_size = Vector2D(EP_size)

        pad_details = self.calcPadDetails(dimensions, EP_size, ipc_data_set, ipc_round_base)

        if 'custom_name_format' in device_params:
            name_format = device_params['custom_name_format']

        suffix = device_params.get('suffix', '').format(pad_x=pad_details['left']['size'][0],
            pad_y=pad_details['left']['size'][1])
        suffix_3d = suffix if device_params.get('include_suffix_in_3dpath', 'True') == 'True' else ""
        model3d_path_prefix = self.configuration.get('3d_model_prefix','${KISYS3DMOD}')

        fp_name = name_format.format(
            man=device_params.get('manufacturer',''),
            mpn=device_params.get('part_number',''),
            pkg=header['device_type'],
            pincount=pincount,
            size_y=size_y,
            size_x=size_x,
            pitch=device_params['pitch'],
            ep_size_x = EP_size['x'],
            ep_size_y = EP_size['y'],
            mask_size_x = EP_mask_size['x'],
            mask_size_y = EP_mask_size['y'],
            suffix=suffix,
            suffix2="",
            vias=self.configuration.get('thermal_via_suffix', '_ThermalVias') if with_thermal_vias else ''
            ).replace('__','_').lstrip('_')

        fp_name_2 = name_format.format(
            man=device_params.get('manufacturer',''),
            mpn=device_params.get('part_number',''),
            pkg=header['device_type'],
            pincount=pincount,
            size_y=size_y,
            size_x=size_x,
            pitch=device_params['pitch'],
            ep_size_x = EP_size['x'],
            ep_size_y = EP_size['y'],
            mask_size_x = EP_mask_size['x'],
            mask_size_y = EP_mask_size['y'],
            suffix=suffix_3d,
            suffix2="",
            vias=''
            ).replace('__','_').lstrip('_')

        model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'\
            .format(
                model3d_path_prefix=model3d_path_prefix, lib_name=lib_name,
                fp_name=fp_name_2)
        #print(fp_name)
        #print(pad_details)

        kicad_mod = Footprint(fp_name)

                # init kicad footprint
        kicad_mod.setDescription(
            "{manufacturer} {mpn} {package}, {pincount} Pin ({datasheet}), generated with kicad-footprint-generator {scriptname}"\
            .format(
                manufacturer = device_params.get('manufacturer',''),
                package = header['device_type'],
                mpn = device_params.get('part_number',''),
                pincount = pincount,
                datasheet = device_params['size_source'],
                scriptname = os.path.basename(__file__).replace("  ", " ")
                ).lstrip())

        kicad_mod.setTags(self.configuration['keyword_fp_string']\
            .format(
                man=device_params.get('manufacturer',''),
                package=header['device_type'],
                category=header['library_Suffix']
            ).lstrip())
        kicad_mod.setAttribute('smd')

        pad_shape_details = {}
        pad_shape_details['shape'] = Pad.SHAPE_ROUNDRECT
        pad_shape_details['radius_ratio'] = configuration.get('round_rect_radius_ratio', 0)
        if 'round_rect_max_radius' in configuration:
            pad_shape_details['maximum_radius'] = configuration['round_rect_max_radius']

        EP_round_radius = 0
        if dimensions['has_EP']:
            EP_mask_size = EP_mask_size if EP_mask_size['x'] > 0 else None

            if with_thermal_vias:
                thermals = device_params['thermal_vias']
                paste_coverage = thermals.get('EP_paste_coverage',
                                               device_params.get('EP_paste_coverage', DEFAULT_PASTE_COVERAGE))

                EP = ExposedPad(
                    number=pincount+1, size=EP_size, mask_size=EP_mask_size,
                    paste_layout=thermals.get('EP_num_paste_pads'),
                    paste_coverage=paste_coverage,
                    via_layout=thermals.get('count', 0),
                    paste_between_vias=thermals.get('paste_between_vias'),
                    paste_rings_outside=thermals.get('paste_rings_outside'),
                    via_drill=thermals.get('drill', 0.3),
                    via_grid=thermals.get('grid'),
                    paste_avoid_via=thermals.get('paste_avoid_via', True),
                    via_paste_clarance=thermals.get('paste_via_clearance', DEFAULT_VIA_PASTE_CLEARANCE),
                    min_annular_ring=thermals.get('min_annular_ring', DEFAULT_MIN_ANNULAR_RING),
                    bottom_pad_min_size=thermals.get('bottom_min_size', 0),
                    **pad_shape_details
                    )
            else:
                EP = ExposedPad(
                    number=pincount+1, size=EP_size, mask_size=EP_mask_size,
                    paste_layout=device_params.get('EP_num_paste_pads', 1),
                    paste_coverage=device_params.get('EP_paste_coverage', DEFAULT_PASTE_COVERAGE),
                    **pad_shape_details
                    )

            kicad_mod.append(EP)
            EP_round_radius = EP.getRoundRadius()

        pad_radius = add_dual_or_quad_pad_border(kicad_mod, configuration, pad_details, device_params)

        body_edge = {
            'left': -dimensions['body_size_x'].nominal/2,
            'right': dimensions['body_size_x'].nominal/2,
            'top': -dimensions['body_size_y'].nominal/2,
            'bottom': dimensions['body_size_y'].nominal/2
            }

        bounding_box = {
            'left': pad_details['left']['center'][0] - pad_details['left']['size'][0]/2,
            'right': pad_details['right']['center'][0] + pad_details['right']['size'][0]/2,
            'top': pad_details['top']['center'][1] - pad_details['top']['size'][1]/2,
            'bottom': pad_details['bottom']['center'][1] + pad_details['bottom']['size'][1]/2
        }

        if device_params['num_pins_x'] == 0:
            bounding_box['top'] = body_edge['top']
            bounding_box['bottom'] = body_edge['bottom']
            if EP_size['y'] > dimensions['body_size_y'].nominal:
                bounding_box['top'] = -EP_size['y']/2
                bounding_box['bottom'] = EP_size['y']/2

        if device_params['num_pins_y'] == 0:
            bounding_box['left'] = body_edge['left']
            bounding_box['right'] = body_edge['right']
            if EP_size['x'] > dimensions['body_size_x'].nominal:
                bounding_box['left'] = -EP_size['x']/2
                bounding_box['right'] = EP_size['x']/2


        pad_width = pad_details['top']['size'][0]

        # ############################ SilkS ##################################
        silk_pad_offset = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2
        silk_offset = configuration['silk_fab_offset']

        right_pads_silk_bottom = (device_params['num_pins_y']-1)*device_params['pitch']/2\
            +pad_details['right']['size'][1]/2+silk_pad_offset
        silk_bottom = body_edge['bottom']+silk_offset
        if EP_size['y']/2 <= body_edge['bottom'] and right_pads_silk_bottom >= silk_bottom:
            silk_bottom = max(silk_bottom, EP_size['y']/2+silk_pad_offset)

        silk_bottom = max(silk_bottom, right_pads_silk_bottom)
        silk_bottom = min(body_edge['bottom']+silk_pad_offset, silk_bottom)

        bottom_pads_silk_right = (device_params['num_pins_x']-1)*device_params['pitch']/2\
            +pad_details['bottom']['size'][0]/2+silk_pad_offset
        silk_right = body_edge['right']+silk_offset
        if EP_size['x']/2 <= body_edge['right'] and bottom_pads_silk_right >= silk_right:
            silk_right = max(silk_right, EP_size['x']/2+silk_pad_offset)
        silk_right = max(silk_right, bottom_pads_silk_right)
        silk_right = min(body_edge['right']+silk_pad_offset, silk_right)


        min_lenght = configuration.get('silk_line_lenght_min', 0)
        silk_corner_bottom_right = Vector2D(silk_right, silk_bottom)

        silk_point_bottom_inside = nearestSilkPointOnOrthogonalLine(
            pad_size=EP_size,
            pad_position=[0, 0],
            pad_radius=EP_round_radius,
            fixed_point=silk_corner_bottom_right,
            moving_point=Vector2D(0, silk_bottom),
            silk_pad_offset=silk_pad_offset,
            min_lenght=min_lenght)

        if silk_point_bottom_inside is not None and device_params['num_pins_x'] > 0:
            silk_point_bottom_inside = nearestSilkPointOnOrthogonalLine(
                pad_size=pad_details['bottom']['size'],
                pad_position=[
                    pad_details['bottom']['center'][0]+(device_params['num_pins_x']-1)/2*pitch,
                    pad_details['bottom']['center'][1]],
                pad_radius=pad_radius,
                fixed_point=silk_corner_bottom_right,
                moving_point=silk_point_bottom_inside,
                silk_pad_offset=silk_pad_offset,
                min_lenght=min_lenght)

        silk_point_right_inside = nearestSilkPointOnOrthogonalLine(
            pad_size=EP_size,
            pad_position=[0, 0],
            pad_radius=EP_round_radius,
            fixed_point=silk_corner_bottom_right,
            moving_point=Vector2D(silk_right, 0),
            silk_pad_offset=silk_pad_offset,
            min_lenght=min_lenght)
        if silk_point_right_inside is not None and device_params['num_pins_y'] > 0:
            silk_point_right_inside = nearestSilkPointOnOrthogonalLine(
                pad_size=pad_details['right']['size'],
                pad_position=[
                    pad_details['right']['center'][0],
                    pad_details['right']['center'][1]+(device_params['num_pins_y']-1)/2*pitch],
                pad_radius=pad_radius,
                fixed_point=silk_corner_bottom_right,
                moving_point=silk_point_right_inside,
                silk_pad_offset=silk_pad_offset,
                min_lenght=min_lenght)

        if silk_point_bottom_inside is None and silk_point_right_inside is not None:
            silk_corner_bottom_right['y'] = body_edge['bottom']
            silk_corner_bottom_right = nearestSilkPointOnOrthogonalLine(
                pad_size=pad_details['bottom']['size'],
                pad_position=[
                    pad_details['bottom']['center'][0]+(device_params['num_pins_x']-1)/2*pitch,
                    pad_details['bottom']['center'][1]],
                pad_radius=pad_radius,
                fixed_point=silk_point_right_inside,
                moving_point=silk_corner_bottom_right,
                silk_pad_offset=silk_pad_offset,
                min_lenght=min_lenght)

        elif silk_point_right_inside is None and silk_point_bottom_inside is not None:
            silk_corner_bottom_right['x'] = body_edge['right']
            silk_corner_bottom_right = nearestSilkPointOnOrthogonalLine(
                pad_size=pad_details['right']['size'],
                pad_position=[
                    pad_details['right']['center'][0],
                    pad_details['right']['center'][1]+(device_params['num_pins_y']-1)/2*pitch],
                pad_radius=pad_radius,
                fixed_point=silk_point_bottom_inside,
                moving_point=silk_corner_bottom_right,
                silk_pad_offset=silk_pad_offset,
                min_lenght=min_lenght)

        poly_bottom_right = []
        if silk_point_bottom_inside is not None:
            poly_bottom_right.append(silk_point_bottom_inside)
        poly_bottom_right.append(silk_corner_bottom_right)
        if silk_point_right_inside is not None:
            poly_bottom_right.append(silk_point_right_inside)

        if len(poly_bottom_right) > 1 and silk_corner_bottom_right is not None:
            kicad_mod.append(PolygoneLine(
                polygone=poly_bottom_right,
                width=configuration['silk_line_width'],
                layer="F.SilkS"))
            kicad_mod.append(PolygoneLine(
                polygone=poly_bottom_right,
                width=configuration['silk_line_width'],
                layer="F.SilkS", x_mirror=0))
            kicad_mod.append(PolygoneLine(
                polygone=poly_bottom_right,
                width=configuration['silk_line_width'],
                layer="F.SilkS", y_mirror=0))

            if device_params['num_pins_y'] > 0:
                if len(poly_bottom_right)>2:
                    kicad_mod.append(PolygoneLine(
                        polygone=poly_bottom_right,
                        width=configuration['silk_line_width'],
                        layer="F.SilkS", y_mirror=0, x_mirror=0))
                    kicad_mod.append(Line(
                        start={'x': -silk_right, 'y': -right_pads_silk_bottom},
                        end={'x': bounding_box['left'], 'y': -right_pads_silk_bottom},
                        width=configuration['silk_line_width'],
                        layer="F.SilkS"))
                elif silk_corner_bottom_right['y'] >= right_pads_silk_bottom and silk_point_bottom_inside is not None:
                    kicad_mod.append(Line(
                        start=-silk_point_bottom_inside,
                        end={'x': bounding_box['left'], 'y': -silk_point_bottom_inside['y']},
                        width=configuration['silk_line_width'],
                        layer="F.SilkS"))
            else:
                if len(poly_bottom_right)>2:
                    poly_bottom_right[0]['x']=bottom_pads_silk_right
                    kicad_mod.append(PolygoneLine(
                        polygone=poly_bottom_right,
                        width=configuration['silk_line_width'],
                        layer="F.SilkS", y_mirror=0, x_mirror=0))
                    kicad_mod.append(Line(
                        start={'x': -bottom_pads_silk_right, 'y': -silk_corner_bottom_right['y']},
                        end={'x': -bottom_pads_silk_right, 'y': bounding_box['top']},
                        width=configuration['silk_line_width'],
                        layer="F.SilkS"))
                elif silk_corner_bottom_right['x'] >= bottom_pads_silk_right and silk_point_right_inside is not None:
                    kicad_mod.append(Line(
                        start=-silk_point_right_inside,
                        end={'x': -silk_point_right_inside['x'], 'y': bounding_box['top']},
                        width=configuration['silk_line_width'],
                        layer="F.SilkS"))

        # # ######################## Fabrication Layer ###########################

        fab_bevel_size = min(configuration['fab_bevel_size_absolute'], configuration['fab_bevel_size_relative']*min(size_x, size_y))

        poly_fab = [
            {'x': body_edge['left']+fab_bevel_size, 'y': body_edge['top']},
            {'x': body_edge['right'], 'y': body_edge['top']},
            {'x': body_edge['right'], 'y': body_edge['bottom']},
            {'x': body_edge['left'], 'y': body_edge['bottom']},
            {'x': body_edge['left'], 'y': body_edge['top']+fab_bevel_size},
            {'x': body_edge['left']+fab_bevel_size, 'y': body_edge['top']},
        ]

        kicad_mod.append(PolygoneLine(
            polygone=poly_fab,
            width=configuration['fab_line_width'],
            layer="F.Fab"))

        # # ############################ CrtYd ##################################

        off = ipc_data_set['courtyard']
        grid = configuration['courtyard_grid']

        if device_params['num_pins_y'] == 0 or device_params['num_pins_x'] == 0:
            cy1=roundToBase(bounding_box['top']-off, grid)

            kicad_mod.append(RectLine(
                start={
                    'x':roundToBase(bounding_box['left']-off, grid),
                    'y':cy1
                    },
                end={
                    'x':roundToBase(bounding_box['right']+off, grid),
                    'y':roundToBase(bounding_box['bottom']+off, grid)
                    },
                width=configuration['courtyard_line_width'],
                layer='F.CrtYd'))

        else:
            cy1=roundToBase(bounding_box['top']-off, grid)
            cy2=roundToBase(body_edge['top']-off, grid)
            cy3=-roundToBase(
                device_params['pitch']*(device_params['num_pins_y']-1)/2.0
                + pad_width/2.0 + off, grid)



            cx1=-roundToBase(
                device_params['pitch']*(device_params['num_pins_x']-1)/2.0
                + pad_width/2.0 + off, grid)
            cx2=roundToBase(body_edge['left']-off, grid)
            cx3=roundToBase(bounding_box['left']-off, grid)


            crty_poly_tl = [
                {'x':0, 'y':cy1},
                {'x':cx1, 'y':cy1},
                {'x':cx1, 'y':cy2},
                {'x':cx2, 'y':cy2},
                {'x':cx2, 'y':cy3},
                {'x':cx3, 'y':cy3},
                {'x':cx3, 'y':0}
            ]
            kicad_mod.append(PolygoneLine(polygone=crty_poly_tl,
                layer='F.CrtYd', width=configuration['courtyard_line_width']))
            kicad_mod.append(PolygoneLine(polygone=crty_poly_tl,
                layer='F.CrtYd', width=configuration['courtyard_line_width'],
                x_mirror=0))
            kicad_mod.append(PolygoneLine(polygone=crty_poly_tl,
                layer='F.CrtYd', width=configuration['courtyard_line_width'],
                y_mirror=0))
            kicad_mod.append(PolygoneLine(polygone=crty_poly_tl,
                layer='F.CrtYd', width=configuration['courtyard_line_width'],
                x_mirror=0, y_mirror=0))

        # ######################### Text Fields ###############################

        addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
            courtyard={'top': cy1, 'bottom': -cy1}, fp_name=fp_name, text_y_inside_position='center')

        ##################### Output and 3d model ############################

        kicad_mod.append(Model(filename=model_name))

        output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
        if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
            os.makedirs(output_dir)
        filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=fp_name)

        file_handler = KicadFileHandler(kicad_mod)
        file_handler.writeFile(filename)
Example #46
0
def generate_one_footprint(pins, variant, configuration):
    V = variant_params[variant]['V']
    #calculate fp dimensions
    A = (pins - 1) * pitch
    B = A + 4.9

    #Thickness of connector
    T = 11.5

    #corners
    x1 = -2.45
    x2 = x1 + B

    x_mid = (x1 + x2) / 2

    y2 = V
    y1 = y2 - T

    #y at which the plastic tabs end
    y3 = y2 - 7

    #generate the name
    mpn = part_base.format(n=pins, variant=variant)
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pincount,
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator"
        .format(series, mpn, datasheet))

    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    if pins == 2:
        drill = 1.0
    else:
        drill = 0.95

    pad_size = [
        pitch - pad_to_pad_clearance, drill + 2 * pad_copper_y_solder_length
    ]
    if pad_size[0] - drill < 2 * min_annular_ring:
        pad_size[0] = drill + 2 * min_annular_ring

    #generate the pads
    ############################# Pads ##################################
    # kicad_mod.append(Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    #                     at=[0, 0], size=pad_size,
    #                     drill=drill, layers=Pad.LAYERS_THT))

    kicad_mod.append(
        PadArray(initial=1,
                 start=[0, 0],
                 x_spacing=pitch,
                 pincount=pincount,
                 size=pad_size,
                 drill=drill,
                 type=Pad.TYPE_THT,
                 shape=Pad.SHAPE_OVAL,
                 layers=Pad.LAYERS_THT))

    #draw the courtyard
    cx1 = roundToBase(x1 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy1 = roundToBase(y1 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    cx2 = roundToBase(x2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy2 = roundToBase(y2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    #offset the outline around the connector
    off = configuration['silk_fab_offset']

    xo1 = x1 - off
    yo1 = y1 - off

    xo2 = x2 + off
    yo2 = y2 + off

    #thickness of the notches
    notch = 1.5

    #wall thickness of the outline
    wall = 1.2

    #draw the outline of the connector
    outline = [
        {
            'x': x_mid,
            'y': yo2
        },
        {
            'x': xo1,
            'y': yo2
        },
        {
            'x': xo1,
            'y': yo1
        },
        {
            'x': xo1 + wall + 2 * off,
            'y': yo1
        },
        {
            'x': xo1 + wall + 2 * off,
            'y': y3 - off
        },
        {
            'x': A / 2,
            'y': y3 - off
        },
        #{'x': -1.1,'y': y3 + off}
    ]
    if variant == 'A-1':
        outline = outline[:-1]
    kicad_mod.append(
        PolygoneLine(polygone=outline,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=outline,
                     x_mirror=x_mid,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    outline = [
        {
            'x': x_mid,
            'y': y2
        },
        {
            'x': x1,
            'y': y2
        },
        {
            'x': x1,
            'y': y1
        },
        {
            'x': x1 + wall,
            'y': y1
        },
        {
            'x': x1 + wall,
            'y': y3
        },
        {
            'x': A / 2,
            'y': y3
        },
        #{'x': -1.1,'y': y3 + off}
    ]
    kicad_mod.append(
        PolygoneLine(polygone=outline,
                     layer='F.Fab',
                     width=configuration['fab_line_width']))
    kicad_mod.append(
        PolygoneLine(polygone=outline,
                     x_mirror=x_mid,
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    #draw the pinsss
    for i in range(pins):

        x = i * pitch
        w = 0.25
        kicad_mod.append(
            RectLine(start=[x - w, y3 + 1],
                     end=[x + w, y2 - 0.5],
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    #add pin-1 designator
    px = 0
    py = -1.5
    m = 0.3

    pin1 = [
        {
            'x': px,
            'y': py
        },
        {
            'x': px - m,
            'y': py - 2 * m
        },
        {
            'x': px + m,
            'y': py - 2 * m
        },
        {
            'x': px,
            'y': py
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=pin1,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))
    if fab_pin1_marker_type == 1:
        kicad_mod.append(
            PolygoneLine(polygone=pin1,
                         layer='F.Fab',
                         width=configuration['fab_line_width']))

    if fab_pin1_marker_type == 2:
        fab_marker_left = -fab_first_marker_w / 2.0
        fab_marker_bottom = y3 - fab_first_marker_h
        poly_fab_marker = [{
            'x': fab_marker_left,
            'y': y3
        }, {
            'x': 0,
            'y': fab_marker_bottom
        }, {
            'x': fab_marker_left + fab_first_marker_w,
            'y': y3
        }]
        kicad_mod.append(
            PolygoneLine(polygone=poly_fab_marker,
                         layer='F.Fab',
                         width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    text_center_y = 'center'
    body_edge = {'left': x1, 'right': x2, 'top': y1, 'bottom': y2}
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position=text_center_y)

    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def make_module(pin_count, configuration):
    pad_silk_off = configuration['silk_line_width']/2 + configuration['silk_pad_clearance']
    off = configuration['silk_fab_offset']

    mpn = part_code.format(pin_count)

    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_unequal_row_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins=pin_count, mounting_pad = "",
        pitch=cable_pitch*2, orientation=orientation_str)

    footprint_name = footprint_name.replace("__",'_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setAttribute('smd')
    kicad_mod.setDescription("Molex {:s}, {:s}, {:d} Circuits ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, pin_count, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))


    pad_to_pad_inside = 2
    pad_to_pad_outside = pad_to_pad_inside + odd_pad_size[0] + even_pad_size[0]
    row_spacing = pad_to_pad_outside - odd_pad_size[0]/2 - even_pad_size[0]/2

    odd_pad_x = -pad_to_pad_outside/2 + odd_pad_size[0]/2
    even_pad_x = odd_pad_x + row_spacing


    B = cable_pitch * (pin_count - 1)

    A = B + (7.05-4.8)
    bar_width_max = 2*3.8
    bar_chamfer_y = 1
    bar_from_side_min = 0.1

    bar_width = A - 2*bar_from_side_min
    if bar_width > bar_width_max:
        bar_width = bar_width_max

    body_edge = {
        'top': -A/2,
        'bottom': A/2,
        'left': odd_pad_x - odd_pad_size[0]/2 + 0.35
    }
    body_edge['right'] = body_edge['left'] + 2.85

    bar_down_edge = body_edge['left'] + 3.23


    bounding_box = {
        'top': body_edge['top'],
        'bottom': body_edge['bottom'],
        'left': odd_pad_x - odd_pad_size[0]/2,
        'right': bar_down_edge
    }

    kicad_mod.append(RectLine(
        start=[body_edge['left'], body_edge['top']],
        end=[body_edge['right'], body_edge['bottom']],
        layer="F.Fab", width=configuration['fab_line_width']
    ))
    kicad_mod.append(PolygoneLine(
        polygone=[
            {'x': body_edge['right'], 'y': -bar_width/2},
            {'x': bar_down_edge, 'y': -bar_width/2 + bar_chamfer_y},
            {'x': bar_down_edge, 'y': bar_width/2 - bar_chamfer_y},
            {'x': body_edge['right'], 'y': bar_width/2}
        ],
        layer="F.Fab", width=configuration['fab_line_width']
    ))

    odd_pins_outside = B/2 + odd_pad_size[1]/2 + pad_silk_off
    silk_outline = [
        {'x': body_edge['left']-off, 'y':odd_pins_outside},
        {'x': body_edge['left']-off, 'y':body_edge['bottom']+off},
        {'x': body_edge['right'] + off, 'y':body_edge['bottom']+off},
        {'x': body_edge['right'] + off, 'y': bar_width/2 + off},
        {'x': bar_down_edge + off, 'y': bar_width/2 - bar_chamfer_y + off},
        {'x': bar_down_edge + off, 'y': 0}
    ]
    kicad_mod.append(PolygoneLine(
        polygone=silk_outline,
        layer="F.SilkS", width=configuration['silk_line_width']
    ))
    kicad_mod.append(PolygoneLine(
        polygone=silk_outline, y_mirror=0,
        layer="F.SilkS", width=configuration['silk_line_width']
    ))

    even_pins = pin_count//2
    odd_pins = pin_count - even_pins
    kicad_mod.append(PadArray(
            center=[odd_pad_x,0], pincount=odd_pins,
            initial=1, increment=2, y_spacing=2*cable_pitch,
            type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT,
            size=odd_pad_size, layers=Pad.LAYERS_SMT))
    kicad_mod.append(PadArray(
            center=[even_pad_x, 0], pincount=even_pins,
            initial=2, increment=2, y_spacing=2*cable_pitch,
            type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT,
            size=even_pad_size, layers=Pad.LAYERS_SMT))

    pin1_y = -B/2
    ps1_m = 0.3
    p1s_x = bounding_box['left'] - pad_silk_off
    pin = [
        {'x': p1s_x -  ps1_m/sqrt(2), 'y': pin1_y-ps1_m/2},
        {'x': p1s_x, 'y': pin1_y},
        {'x': p1s_x -  ps1_m/sqrt(2), 'y': pin1_y+ps1_m/2},
        {'x': p1s_x -  ps1_m/sqrt(2), 'y': pin1_y-ps1_m/2}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin,
        layer="F.SilkS", width=configuration['silk_line_width']))

    sl=0.6
    pin = [
        {'x': body_edge['left'], 'y': pin1_y-sl/2},
        {'x': body_edge['left'] + sl/sqrt(2), 'y': pin1_y},
        {'x': body_edge['left'], 'y': pin1_y+sl/2}
    ]
    kicad_mod.append(PolygoneLine(polygone=pin,
        width=configuration['fab_line_width'], layer='F.Fab'))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='right')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    if lib_by_conn_category:
        lib_name = configuration['lib_name_specific_function_format_string'].format(category=conn_category)
    else:
        lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)

    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    mpn = part_base.format(n=pins *
                           number_of_rows)  #JST part number format string
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription(
        "JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator"
        .format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #calculate fp dimensions
    A = (pins - 1) * pitch
    B = A + 4

    #generate the pads (row 1)
    size = [pitch - pad_to_pad_clearance, row_pitch - pad_to_pad_clearance]
    if size[0] - drill < 2 * min_annular_ring:
        size[0] = drill + 2 * min_annular_ring
    if size[0] - drill > 2 * pad_copper_y_solder_length:
        size[0] = drill + 2 * pad_copper_y_solder_length

    if size[1] - drill < 2 * min_annular_ring:
        size[1] = drill + 2 * min_annular_ring
    if size[1] - drill > 2 * pad_copper_y_solder_length:
        size[1] = drill + 2 * pad_copper_y_solder_length

    pa1 = PadArray(pincount=pins,
                   x_spacing=pitch,
                   type=Pad.TYPE_THT,
                   shape=Pad.SHAPE_OVAL,
                   increment=2,
                   size=size,
                   drill=drill,
                   layers=Pad.LAYERS_THT)
    pa2 = PadArray(pincount=pins,
                   x_spacing=pitch,
                   type=Pad.TYPE_THT,
                   shape=Pad.SHAPE_OVAL,
                   start=[0, row_pitch],
                   initial=2,
                   increment=2,
                   size=size,
                   drill=drill,
                   layers=Pad.LAYERS_THT)

    kicad_mod.append(pa1)
    kicad_mod.append(pa2)

    #draw the component outline
    x1 = A / 2 - B / 2
    x2 = x1 + B
    y2 = row_pitch + 7.7 + 2.4
    y1 = y2 - 12.7
    body_edge = {'left': x1, 'right': x2, 'top': y1, 'bottom': y2}

    #draw simple outline on F.Fab layer
    kicad_mod.append(
        RectLine(start=[x1, y1],
                 end=[x2, y2],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))
    ########################### CrtYd #################################
    cx1 = roundToBase(x1 - configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    if y1 < -size[1] / 2:
        cy1 = roundToBase(y1 - configuration['courtyard_offset']['connector'],
                          configuration['courtyard_grid'])
    else:
        cy1 = roundToBase(
            -size[1] / 2 - configuration['courtyard_offset']['connector'],
            configuration['courtyard_grid'])

    cx2 = roundToBase(x2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])
    cy2 = roundToBase(y2 + configuration['courtyard_offset']['connector'],
                      configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    #offset off
    off = configuration['silk_fab_offset']

    x1 -= off
    y1 -= off
    x2 += off
    y2 += off

    #outline
    side = [
        {
            'x': -1,
            'y': y1
        },
        {
            'x': x1,
            'y': y1
        },
        {
            'x': x1,
            'y': y2
        },
        {
            'x': A / 2,
            'y': y2
        },
    ]

    kicad_mod.append(
        PolygoneLine(polygone=side,
                     width=configuration['silk_line_width'],
                     layer='F.SilkS'))
    kicad_mod.append(
        PolygoneLine(polygone=side,
                     x_mirror=A / 2,
                     width=configuration['silk_line_width'],
                     layer='F.SilkS'))

    #add mounting holes
    m1 = Pad(at=[-0.9, mh_y],
             layers=Pad.LAYERS_NPTH,
             shape=Pad.SHAPE_CIRCLE,
             type=Pad.TYPE_NPTH,
             size=mh_drill,
             drill=mh_drill)
    m2 = Pad(at=[A + 0.9, mh_y],
             layers=Pad.LAYERS_NPTH,
             shape=Pad.SHAPE_CIRCLE,
             type=Pad.TYPE_NPTH,
             size=mh_drill,
             drill=mh_drill)

    kicad_mod.append(m1)
    kicad_mod.append(m2)

    D = 0.3
    L = 2.5

    #add p1 marker
    marker = [{
        'x': pitch / 2,
        'y': y1 - D + 0.25
    }, {
        'x': pitch / 2,
        'y': y1 - D
    }, {
        'x': x1 - D,
        'y': y1 - D
    }, {
        'x': x1 - D,
        'y': y1 - D + L
    }]

    kicad_mod.append(
        PolygoneLine(polygone=marker,
                     width=configuration['silk_line_width'],
                     layer='F.SilkS'))
    sl = 1
    marker = [{
        'x': sl / 2,
        'y': body_edge['top']
    }, {
        'x': 0,
        'y': body_edge['top'] + sl / sqrt(2)
    }, {
        'x': -sl / 2,
        'y': body_edge['top']
    }]
    kicad_mod.append(
        PolygoneLine(polygone=marker,
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='center')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    mpn = part_base.format(n=pins)
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator".format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #calculate dimensions
    A = (pins - 1) * pitch
    B = A + 5

    #draw the component outline
    x1 = A/2 - B/2
    x2 = x1 + B
    y2 = 4.8
    y1 = y2 - 8.5

    body_edge={'left':x1, 'right':x2, 'top':y1, 'bottom':y2}

    #draw the main outline on F.Fab layer
    kicad_mod.append(RectLine(start={'x':x1,'y':y1}, end={'x':x2,'y':y2}, layer='F.Fab', width=configuration['fab_line_width']))

    #draw horizontal line for latch
    kicad_mod.append(PolygoneLine(polygone=[{'x':x1,'y':(y1+1.7)},{'x':x2,'y':(y1+1.7)}],layer='F.Fab',width=0.1))

	#draw pin1 mark on F.Fab
    kicad_mod.append(PolygoneLine(polygone=[{'x':x1,'y':-1},{'x':(x1+1),'y':0}],layer='F.Fab',width=0.1))
    kicad_mod.append(PolygoneLine(polygone=[{'x':x1,'y':1},{'x':(x1+1),'y':0}],layer='F.Fab',width=0.1))

    ########################### CrtYd #################################
    cx1 = roundToBase(x1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(y1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(x2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(y2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    #draw silk outline
    off = configuration['silk_fab_offset']
    x1 -= off
    y1 -= off
    x2 += off
    y2 += off
    kicad_mod.append(RectLine(start=[x1,y1], end=[x2,y2], layer='F.SilkS', width=configuration['silk_line_width']))

    #add pin1 mark on silk
    px = x1 - 0.2
    m = 0.3

    marker = [{'x': px,'y': 0},{'x': px-2*m,'y': m},{'x': px-2*m,'y': -m},{'x': px,'y': 0}]

    kicad_mod.append(PolygoneLine(polygone=marker, layer='F.SilkS', width=configuration['silk_line_width']))

    #generate tht pads (1.65mm drill with 2.35x3mm oval pads)
    pad_size = [pitch - pad_to_pad_clearance, drill + 2*pad_copper_y_solder_length]
    if pad_size[0] - drill > 2*pad_copper_y_solder_length:
        pad_size[0] = 2*pad_copper_y_solder_length + drill

    if pad_size[0] - drill < 2*min_annular_ring:
        pad_size[0] = drill + 2*min_annular_ring

    shape=Pad.SHAPE_OVAL
    if pad_size[0] == pad_size[1]:
        shape=Pad.SHAPE_CIRCLE

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(
        pincount=pins, x_spacing=pitch,
        type=Pad.TYPE_THT, shape=shape,
        size=pad_size, drill=drill, layers=Pad.LAYERS_THT,
        **optional_pad_params))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #50
0
def generate_one_footprint(pins, variant, configuration):
    #calculate fp dimensions
    boss = variant_params[variant]['boss']
    A = (pins - 1) * pitch
    B = A + 4.9

    #connector thickness
    T = 5.75

    #corners
    x1 = -2.45
    x2 = x1 + B


    x_mid = (x1 + x2) / 2

    y1 = -2.35
    y2 = y1 + T

    #generate the name
    mpn = part_base.format(n=pins, variant=variant)
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pincount, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s}{:s} ({:s}), generated with kicad-footprint-generator".format(
        series, mpn, ', with boss' if boss else '', datasheet))

    tags = configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation])
    if boss:
        tags += " boss"
    #set the FP tags
    kicad_mod.setTags(tags)

    #draw simple outline on F.Fab layer
    kicad_mod.append(RectLine(start=[x1,y1],end=[x2,y2],layer='F.Fab', width=configuration['fab_line_width']))

    # set general values
    #kicad_mod.append(Text(type='reference', text='REF**', at=[x_mid,-3.5], layer='F.SilkS'))

    if pins == 2:
        drill = 1.0
    else:
        drill = 0.95

    pad_size = [pitch - pad_to_pad_clearance, drill + 2*pad_copper_y_solder_length]
    if pad_size[0] - drill < 2*min_annular_ring:
        pad_size[0] = drill + 2*min_annular_ring

    #generate the pads
    ############################# Pads ##################################
    # kicad_mod.append(Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    #                     at=[0, 0], size=pad_size,
    #                     drill=drill, layers=Pad.LAYERS_THT))

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(initial=1, start=[0, 0],
        x_spacing=pitch, pincount=pins,
        size=pad_size, drill=drill,
        type=Pad.TYPE_THT, shape=Pad.SHAPE_OVAL, layers=Pad.LAYERS_THT,
        **optional_pad_params))

    if boss:
        if pins == 1:
            boss_y = 4.35
            boss_x = 0
            boss_drill = 1.75
            kicad_mod.append(Pad(type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
                                 at=[boss_x, boss_y], size=boss_drill,
                                 drill=boss_drill, layers=Pad.LAYERS_NPTH))
        else:
            boss_y = 2
            boss_x = -1.6
            boss_drill = 1.2
            kicad_mod.append(Pad(type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
                                 at=[boss_x, boss_y], size=boss_drill,
                                 drill=boss_drill, layers=Pad.LAYERS_NPTH))

    if boss and pins == 1:
        boss_size_1pin = 1.5
        off = configuration['silk_fab_offset']
        x_boss_fab_off = boss_size_1pin/2 + off
        x_boss_pad_off = boss_drill/2 + configuration['silk_line_width']/2 + configuration['silk_pad_clearance']
        x_boss = x_boss_fab_off
        if x_boss_pad_off > x_boss:
            x_boss=x_boss_pad_off
        out_silk = PolygoneLine(polygone=[
            {'x': -x_boss, 'y':boss_y},
            {'x': -x_boss, 'y':y2+off},
            {'x': x1-off, 'y':y2+off},
            {'x': x1-off, 'y':y1-off},
            {'x': x2+off, 'y':y1-off},
            {'x': x2+off, 'y':y2+off},
            {'x': x_boss, 'y':y2+off},
            {'x': x_boss, 'y':boss_y}
        ], layer='F.SilkS', width=configuration['silk_line_width'])
        kicad_mod.append(out_silk)
        kicad_mod.append(Arc(center=[0,boss_y], start=[-x_boss, boss_y], angle=-180,
            layer="F.SilkS", width=configuration['silk_line_width']))

        out_fab = PolygoneLine(polygone=[
            {'x': -boss_size_1pin/2, 'y':boss_y},
            {'x': -boss_size_1pin/2, 'y':y2},
            {'x': x1, 'y':y2},
            {'x': x1, 'y':y1},
            {'x': x2, 'y':y1},
            {'x': x2, 'y':y2},
            {'x': boss_size_1pin/2, 'y':y2},
            {'x': boss_size_1pin/2, 'y':boss_y}
        ], layer='F.Fab', width=configuration['fab_line_width'])
        kicad_mod.append(out_fab)
        kicad_mod.append(Arc(center=[0,boss_y], start=[-boss_size_1pin/2, boss_y], angle=-180,
            layer="F.Fab", width=configuration['fab_line_width']))


    else:
        out = RectLine(start=[x1,y1], end=[x2,y2], offset=configuration['silk_fab_offset'],
            layer='F.SilkS', width=configuration['silk_line_width'])
        kicad_mod.append(out)
    body_edge={'left':x1, 'right':x2, 'top':y1, 'bottom':y2}

    #draw the courtyard
    cx1 = roundToBase(x1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(y1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(x2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(y2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    if boss and pins == 1:
        cy2 = roundToBase(boss_y+boss_drill/2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    #draw the connector outline


    if fab_pin1_marker_type == 2:
        fab_marker_left = -fab_first_marker_w/2.0
        fab_marker_bottom = y1 + fab_first_marker_h
        poly_fab_marker = [
            {'x':fab_marker_left, 'y':y1},
            {'x':0, 'y':fab_marker_bottom},
            {'x':fab_marker_left + fab_first_marker_w, 'y':y1}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_fab_marker, layer='F.Fab', width=configuration['fab_line_width']))

    #wall thickness w
    w = 0.75

    #gap size g
    g = 1.5

    off = 0.1

    x1 -= off
    y1 -= off

    x2 += off
    y2 += off

    #draw the center tab
    kicad_mod.append(RectLine(start=[g/2,y1], end=[A-g/2,y1+w], layer='F.SilkS', width=configuration['silk_line_width']))

    #add left tab
    kicad_mod.append(RectLine(start=[x1,y1], end=[-g/2,y1+w], layer='F.SilkS', width=configuration['silk_line_width']))
    #right tab
    kicad_mod.append(RectLine(start=[A+g/2,y1], end=[x2,y1+w], layer='F.SilkS', width=configuration['silk_line_width']))

    #add other line
    line = [
    {'x': x1,'y': y1+w+g},
    {'x': x1+w,'y': y1+w+g},
    {'x': x1+w,'y': y2-w},
    {'x': A/2,'y': y2-w}
    ]
    if boss and pins > 1:
        line2 = line[:2]
        line2.append({'x': x1+w,'y': boss_y - boss_drill/2 - configuration['silk_line_width']/2 - configuration['silk_pad_clearance']})
        kicad_mod.append(PolygoneLine(polygone=line2, layer='F.SilkS', width=configuration['silk_line_width']))

        kicad_mod.append(Line(start=[A/2, y2-w],
            end=[boss_x+boss_drill/2+ configuration['silk_line_width']/2 + configuration['silk_pad_clearance'], y2-w],
            layer='F.SilkS', width=configuration['silk_line_width']))
    else:
        kicad_mod.append(PolygoneLine(polygone=line, layer='F.SilkS', width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=line, x_mirror=A/2, layer='F.SilkS', width=configuration['silk_line_width']))

    #pin-1 marker
    y =  -2.75
    m = 0.3

    poly_pin1_marker = [
        {'x':x1-pin1_marker_offset+pin1_marker_linelen, 'y':y1-pin1_marker_offset},
        {'x':x1-pin1_marker_offset, 'y':y1-pin1_marker_offset},
        {'x':x1-pin1_marker_offset, 'y':y1-pin1_marker_offset+pin1_marker_linelen}
    ]
    if fab_pin1_marker_type == 2:
        kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker, layer='F.SilkS', width=configuration['silk_line_width']))
    if fab_pin1_marker_type == 3:
        kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker, layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly_pin1_marker, layer='F.Fab', width=configuration['fab_line_width']))

    pin = [
    {'x': 0,'y': y},
    {'x': -m,'y': y-2*m},
    {'x': m,'y': y-2*m},
    {'x': 0,'y': y},
    ]


    if fab_pin1_marker_type == 1:
        kicad_mod.append(PolygoneLine(polygone=pin, layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=pin, layer='F.Fab', width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    text_center_y = 'bottom'
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position=text_center_y)


    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    pins_per_row = pins//2

    mpn = part_code.format(n=pins)
    alt_mpn = [code.format(n=pins) for code in alternative_codes]

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "-1MP",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Molex {:s}, {:s} (compatible alternatives: {:s}), {:d} Pins per row ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, ', '.join(alt_mpn), pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))


    kicad_mod.setAttribute('smd')

    # Calculate dimensions
    if (pins < 4):
        B = 0
    else:
        B = ((pins / 2) - 1) * pitch

    A = B + 6.65
    C = B + 11.2
    # D = pitch_y + PadSiseY
    pad_row_1_y = -pitch_y/2
    pad_row_2_y = pad_row_1_y + pitch_y
    pad1_x = -B/2

    mount_pad_x = ((C - mount_pad_size[0]) / 2)
    mount_pad_y = pad_row_1_y - (6.93 - pad_size[1]/2)

    body_edge={
        'left':-A/2,
        'right':A/2,
        'top': mount_pad_y - 4.6
        }
    body_edge['bottom'] = body_edge['top'] + 9.91

    #
    # Add solder nails
    #
    kicad_mod.append(Pad(at=[-mount_pad_x, mount_pad_y], number=configuration['mounting_pad_number'],
        type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, size=mount_pad_size,
        layers=Pad.LAYERS_SMT))
    kicad_mod.append(Pad(at=[mount_pad_x, mount_pad_y], number=configuration['mounting_pad_number'],
        type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, size=mount_pad_size,
        layers=Pad.LAYERS_SMT))

    #
    # Add pads
    #
    kicad_mod.append(PadArray(start=[pad1_x, pad_row_1_y], initial=1,
        pincount=pins_per_row, increment=1,  x_spacing=pitch, size=pad_size,
        type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT))
    kicad_mod.append(PadArray(start=[pad1_x, pad_row_2_y], initial=pins_per_row+1,
        pincount=pins_per_row, increment=1, x_spacing=pitch, size=pad_size,
        type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT))

    #
    # Add F.Fab
    #
    LayerA = ['F.Fab', 'F.SilkS', 'F.CrtYd']
    LineDXA = [
        0,
        configuration['silk_fab_offset'],
        configuration['courtyard_offset']['connector']
        ]
    LindeDeltaA = [0, configuration['silk_pad_clearance'] + configuration['silk_line_width']/2, 0]
    LineWidthA = [
        configuration['fab_line_width'],
        configuration['silk_line_width'],
        configuration['courtyard_line_width']
        ]
    gridA = [0, 0, configuration['courtyard_grid']]
    for i in range(0,3):
        LineDX = LineDXA[i]
        Layer = LayerA[i]
        LineWidth = LineWidthA[i]
        LindeDelta = LindeDeltaA[i]
        points = []
        grid = gridA[i]

        x1 = 0
        y1 = body_edge['top'] - LineDX

        points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
        #
        x1 = (A / 2) - 1 + LineDX
        y1 = y1
        points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
        #
        x1 = (A / 2) + LineDX
        y1 = y1 + 2
        points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
        #
        x1 = x1
        y1 = mount_pad_y - ((mount_pad_size[1] / 2) + LineDX + LindeDelta)
        points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
        #
        if (i == 1): # SilkS
            kicad_mod.append(PolygoneLine(polygone=points, layer=Layer, width=LineWidth))
            #
            # Need to do something ugly here, becosue we will do points = []
            # We need to reflect these points already here
            #
            points2 = []
            for pp in points:
                points2.append([-pp[0], pp[1]])
            kicad_mod.append(PolygoneLine(polygone=points2, layer=Layer, width=LineWidth))
            #
            #
            points = []
            x1 = x1
            y1 =mount_pad_y + ((mount_pad_size[1] / 2) + LineDX + LindeDelta)
            points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
        elif (i == 2): # CrtYd
            x1 = mount_pad_x + (mount_pad_size[0] / 2) +  LineDX
            y1 = y1
            points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
            #
            x1 = x1
            y1 =mount_pad_y + ((mount_pad_size[1] / 2) + LineDX)
            points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
            #
            x1 = (A / 2) + LineDX
            y1 = y1
            points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
        #
        x1 = x1
        y1 = body_edge['bottom'] + LineDX
        points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
        #
        x1 = (B / 2) + (pad_size[0] / 2) + LineDX  + LindeDelta
        y1 = y1
        points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
        #
        if (i == 0):
            x1 = 0
            y1 = y1
            points.append([roundToBase(x1, grid), roundToBase(y1, grid)])

        if (i == 1):
            ttx1 = x1
            tty1 = y1 + (pad_size[1] / 2)

        if (i == 2):
            x1 = x1
            y1 = ((pitch_y / 2) + (pad_size[1] / 2) + LineDX)
            ttx1 = x1
            tty1 = y1
            points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
            #
            #
            x1 = 0
            y1 = y1
            points.append([roundToBase(x1, grid), roundToBase(y1, grid)])
        #
        # Reflect right part around the X-axis
        #
        points2 = []
        for pp in points:
            points2.append([0 - pp[0], pp[1]])
        #
        #
        if (i == 0): # Fab
            # Add pin 1 marker
            tt = len(points2)
            ps = points2[tt - 1]
            p1 = points2[tt - 2]
            p2 = [(0 - (B / 2)) - 1, p1[1]]
            p3 = [(0 - (B / 2)), p1[1] - 1]
            p4 = [(0 - (B / 2)) + 1, p1[1]]
            points2[tt - 2] = p2
            points2[tt - 1] = p3
            points2.append(p4)
            points2.append(ps)
        elif (i == 1): # silk
            points2.append([roundToBase(0 - ttx1, grid), roundToBase(tty1, grid)])

        #
        #
        kicad_mod.append(PolygoneLine(polygone=points, layer=Layer, width=LineWidth))
        #
        kicad_mod.append(PolygoneLine(polygone=points2, layer=Layer, width=LineWidth))

    ######################### Text Fields ###############################
    cy1 = roundToBase(body_edge['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cy2 = roundToBase(pad_row_2_y + pad_size[1]/2 + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_footprint(params, mpn, configuration):
    fp_params = params['footprint']
    mech_params = params['mechanical']
    part_params = params['parts'][mpn]

    if 'id' in mech_params:
        size = str(mech_params['id'])
    elif 'ext_thread' in mech_params:
        size = str(mech_params['ext_thread']['od'])

    if 'M' not in size:
        size = "{}mm".format(size)

    td = ""
    size_prefix = ""
    hole_type = "inside through hole"
    if 'thread_depth' in part_params:
        hole_type = "inside blind hole"
        td = "_ThreadDepth{}mm".format(part_params['thread_depth'])
    elif 'ext_thread' in mech_params:
        hole_type = "external"
        size_prefix = 'External'

    h = part_params['h'] if 'h' in part_params else part_params['h1']

    suffix = ''
    if 'suffix' in params:
        suffix = '_{}'.format(params['suffix'])

    fp_name = "Mounting_Wuerth_{series}-{size_prefix}{size}_H{h}mm{td}{suffix}_{mpn}".format(
                    size=size, h=h, mpn=mpn, td=td, size_prefix=size_prefix,
                    series=params['series_prefix'], suffix=suffix)

    kicad_mod = Footprint(fp_name)
    kicad_mod.setAttribute('smd')

    kicad_mod.setDescription("Mounting Hardware, {hole_type} {size}, height {h}, Wuerth electronics {mpn} ({ds:s}), generated with kicad-footprint-generator".format(size=size, h=h, mpn=mpn, ds=part_params['datasheet'], hole_type=hole_type))

    kicad_mod.setTags('Mounting {} {}'.format(size, mpn))

    paste_count = fp_params['ring']['paste'].get('paste_count', 4)

    kicad_mod.append(
        RingPad(
            number='1', at=(0, 0),
            size=fp_params['ring']['od'], inner_diameter=fp_params['ring']['id'],
            num_anchor=4, num_paste_zones=paste_count,
            paste_round_radius_radio=0.25,
            paste_max_round_radius=0.1,
            paste_to_paste_clearance=fp_params['ring']['paste']['clearance'],
            paste_inner_diameter=fp_params['ring']['paste']['id'],
            paste_outer_diameter=fp_params['ring']['paste']['od']
            ))
    if 'npth' in fp_params:
        kicad_mod.append(
            Pad(at=[0, 0], number="",
                type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=fp_params['npth'],
                drill=fp_params['npth'], layers=Pad.LAYERS_NPTH))

    kicad_mod.append(
        Circle(
            center=[0, 0], radius=mech_params['od']/2,
            layer='F.Fab', width=configuration['fab_line_width']
            ))

    ########################### CrtYd #################################
    rc = max(mech_params['od'], fp_params['ring']['od'])/2+configuration['courtyard_offset']['default']
    rc = roundToBase(rc, configuration['courtyard_grid'])


    kicad_mod.append(
        Circle(
            center=[0, 0], radius=rc,
            layer='F.CrtYd', width=configuration['courtyard_line_width']
            ))

    ########################### SilkS #################################



    ######################### Text Fields ###############################
    rb = mech_params['od']/2
    body_edge={'left':-rb, 'right':rb, 'top':-rb, 'bottom':rb}
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':-rc, 'bottom':rc}, fp_name=fp_name, text_y_inside_position='center')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = "Mounting_Wuerth"
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=fp_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=fp_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins_per_row, params, configuration):
    mpn = part_code.format(n=pins_per_row, shield=params['mpn_option'])

    CrtYd_off = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']
    off = configuration['silk_fab_offset']
    pad_silk_off = configuration['silk_pad_clearance'] + configuration['silk_line_width']/2
    body_edge = {}
    bounding_box = {}

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    if params['shield_pad']:
        footprint_name = configuration['fp_name_format_string_shielded'].format(man=manufacturer,
            series=series,
            mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row,
            pitch=pitch, orientation=orientation_str, shield_pins=1)
    else:
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    footprint_name = footprint_name.replace('__','_')

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setAttribute('smd')
    kicad_mod.setDescription("Molex {:s}, {:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    A = (pins_per_row-1)*pitch
    B = A + 2.5
    C = A + 5.45
    D = A + 6.75
    E = A + 5.2

    pad_to_pad_inside = 1.95+0.25
    pad_y = (pad_to_pad_inside + pad_size[1])/2

    boss_x = B/2
    boss_y = -pad_y + pad_size[1]/2 + 0.25

    shield_pad_x = C/2
    shield_pad_y = boss_y + 2

    body_chamfer = 0.3


    body_edge['left'] = -D/2 if params['shield_pad'] else -E/2
    body_edge['right'] = -body_edge['left']
    body_edge['top'] = -4.98/2
    body_edge['bottom'] = -body_edge['top']

    bounding_box['left'] = (-shield_pad_x - shield_pad_size/2) if params['shield_pad'] else body_edge['left']
    bounding_box['right'] = -bounding_box['left']
    bounding_box['top'] = -pad_y - pad_size[1]/2
    bounding_box['bottom'] = -bounding_box['top']


    ################################ Pads #####################################

    kicad_mod.append(PadArray(initial=1, increment=2,
        center=[0, -pad_y], x_spacing=pitch, pincount=pins_per_row,
        size=pad_size, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT))
    kicad_mod.append(PadArray(initial=2, increment=2,
        center=[0, pad_y], x_spacing=pitch, pincount=pins_per_row,
        size=pad_size, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT))

    kicad_mod.append(Pad(number ='""', type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
                        at=[boss_x, boss_y],
                        size=boss_drill, drill=boss_drill,
                        layers=Pad.LAYERS_NPTH))
    kicad_mod.append(Pad(number ='""', type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE,
                        at=[-boss_x, boss_y],
                        size=boss_drill, drill=boss_drill,
                        layers=Pad.LAYERS_NPTH))

    if params['shield_pad']:
        kicad_mod.append(Pad(number = pin_number_shield,
                            type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE,
                            at=[shield_pad_x, shield_pad_y],
                            size=shield_pad_size, drill=shield_pad_drill,
                            layers=Pad.LAYERS_THT))
        kicad_mod.append(Pad(number = pin_number_shield,
                            type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE,
                            at=[-shield_pad_x, shield_pad_y],
                            size=shield_pad_size, drill=shield_pad_drill,
                            layers=Pad.LAYERS_THT))

    ########################### Outline ################################
    poly_fab = [
        {'x': 0, 'y': body_edge['top']},
        {'x': body_edge['left']+body_chamfer, 'y': body_edge['top']},
        {'x': body_edge['left'], 'y': body_edge['top']+body_chamfer},
        {'x': body_edge['left'], 'y': body_edge['bottom']-body_chamfer},
        {'x': body_edge['left']+body_chamfer, 'y': body_edge['bottom']},
        {'x': 0, 'y': body_edge['bottom']}
    ]
    kicad_mod.append(PolygoneLine(polygone=poly_fab,
        layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(PolygoneLine(polygone=poly_fab, x_mirror=0,
        layer='F.Fab', width=configuration['fab_line_width']))

    pad_x_outside_edge = A/2 + pad_size[0]/2 + pad_silk_off
    if not params['shield_pad']:
        poly_silk = [
            {'x': -pad_x_outside_edge, 'y': body_edge['top']-off},
            {'x': body_edge['left']+body_chamfer-off, 'y': body_edge['top']-off},
            {'x': body_edge['left']-off, 'y': body_edge['top']+body_chamfer-off},
            {'x': body_edge['left']-off, 'y': body_edge['bottom']-body_chamfer+off},
            {'x': body_edge['left']+body_chamfer-off, 'y': body_edge['bottom']+off},
            {'x': -pad_x_outside_edge, 'y': body_edge['bottom']+off}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_silk,
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly_silk, x_mirror=0,
            layer='F.SilkS', width=configuration['silk_line_width']))

    else:
        r = (shield_pad_size/2 + pad_silk_off)
        x = (D-C)/2
        dy = sqrt(r**2 - x**2)
        poly_silk_top = [
            {'x': -pad_x_outside_edge, 'y': body_edge['top']-off},
            {'x': body_edge['left']+body_chamfer-off, 'y': body_edge['top']-off},
            {'x': body_edge['left']-off, 'y': body_edge['top']+body_chamfer-off},
            {'x': body_edge['left']-off, 'y': shield_pad_y-dy},
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_silk_top,
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly_silk_top, x_mirror=0,
            layer='F.SilkS', width=configuration['silk_line_width']))

        poly_silk_bottom = [
            {'x': body_edge['left']-off, 'y': shield_pad_y+dy},
            {'x': body_edge['left']-off, 'y': body_edge['bottom']-body_chamfer+off},
            {'x': body_edge['left']+body_chamfer-off, 'y': body_edge['bottom']+off},
            {'x': -pad_x_outside_edge, 'y': body_edge['bottom']+off}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_silk_bottom,
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(PolygoneLine(polygone=poly_silk_bottom, x_mirror=0,
            layer='F.SilkS', width=configuration['silk_line_width']))

    ########################### Pin 1 #################################
    p1s_sl = 0.4
    p1s_y = -pad_y - pad_size[1]/2 - pad_silk_off
    p1_x = -A/2
    p1s_poly = [
        {'x': p1_x, 'y':p1s_y},
        {'x': p1_x-p1s_sl/2, 'y':p1s_y-p1s_sl/sqrt(2)},
        {'x': p1_x+p1s_sl/2, 'y':p1s_y-p1s_sl/sqrt(2)},
        {'x': p1_x, 'y':p1s_y}
    ]
    kicad_mod.append(PolygoneLine(polygone=p1s_poly,
        layer='F.SilkS', width=configuration['silk_line_width']))

    p1f_sl = 2*pitch
    p1f_poly = [
        {'x': p1_x-p1f_sl/2, 'y':body_edge['top']},
        {'x': p1_x, 'y':body_edge['top']+p1f_sl/sqrt(2)},
        {'x': p1_x+p1f_sl/2, 'y':body_edge['top']}
    ]
    kicad_mod.append(PolygoneLine(polygone=p1f_poly,
        layer='F.Fab', width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(bounding_box['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(bounding_box['top']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(bounding_box['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(bounding_box['bottom'] + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2},
        fp_name=footprint_name, text_y_inside_position='center')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='use confing .yaml files to create footprints.')
    parser.add_argument('--global_config', type=str, nargs='?', help='the config file defining how the footprint will look like. (KLC)', default='../../tools/global_config_files/config_KLCv3.0.yaml')
    parser.add_argument('--series_config', type=str, nargs='?', help='the config file defining series parameters.', default='../conn_config_KLCv3.yaml')
    args = parser.parse_args()

    with open(args.global_config, 'r') as config_stream:
        try:
            configuration = yaml.load(config_stream)
        except yaml.YAMLError as exc:
            print(exc)

    with open(args.series_config, 'r') as config_stream:
        try:
            configuration.update(yaml.load(config_stream))
        except yaml.YAMLError as exc:
            print(exc)
    for variant in variant_params:
        for pins_per_row in pins_per_row_range:
            generate_one_footprint(pins_per_row, variant_params[variant], configuration)
def generate_one_footprint(pincount, configuration):
    mpn = "B{pincount}B-EH-A".format(pincount=pincount)
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pincount, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator".format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))


    A = (pincount - 1) * pitch
    B = A + 5.0

    # set general values


    if pincount == 2:
        drill = 1.0
    else:
        drill = 0.95

    pad_size = [pitch - pad_to_pad_clearance, drill + 2*pad_copper_y_solder_length]
    if pad_size[0] - drill < 2*min_annular_ring:
        pad_size[0] = drill + 2*min_annular_ring

    # create pads
    # kicad_mod.append(Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    #                     at=[0, 0], size=pad_size,
    #                     drill=drill, layers=Pad.LAYERS_THT))

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(initial=1, start=[0, 0],
        x_spacing=pitch, pincount=pincount,
        size=pad_size, drill=drill,
        type=Pad.TYPE_THT, shape=Pad.SHAPE_OVAL, layers=Pad.LAYERS_THT,
        **optional_pad_params))



    x1 = -2.5
    y1 = -1.6
    x2 = x1 + B
    y2 = y1 + 3.8
    body_edge={'left':x1, 'right':x2, 'top':y1, 'bottom':y2}

    #draw the main outline on F.Fab layer
    kicad_mod.append(RectLine(start={'x':x1,'y':y1}, end={'x':x2,'y':y2}, layer='F.Fab', width=configuration['fab_line_width']))
    ########################### CrtYd #################################
    cx1 = roundToBase(x1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(y1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(x2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(y2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    #line offset
    off = configuration['silk_fab_offset']

    x1 -= off
    y1 -= off

    x2 += off
    y2 += off

    #draw the main outline around the footprint
    kicad_mod.append(RectLine(start={'x':x1,'y':y1},end={'x':x2,'y':y2}, layer='F.SilkS', width=configuration['silk_line_width']))

    T = 0.5

    #add top line
    kicad_mod.append(PolygoneLine(polygone=[{'x': x1,'y': 0},
                               {'x': x1 + T,'y': 0},
                               {'x': x1 + T,'y': y1 + T},
                               {'x': x2 - T,'y': y1 + T},
                               {'x': x2 - T,'y': 0},
                               {'x': x2,'y':0}], layer='F.SilkS', width=configuration['silk_line_width']))

    #add bottom line (left)
    kicad_mod.append(PolygoneLine(polygone=[{'x':x1,'y':y2-3*T},
                               {'x':x1+2*T,'y':y2-3*T},
                               {'x':x1+2*T,'y':y2}], layer='F.SilkS', width=configuration['silk_line_width']))

    #add bottom line (right)
    kicad_mod.append(PolygoneLine(polygone=[{'x':x2,'y':y2-3*T},
                               {'x':x2-2*T,'y':y2-3*T},
                               {'x':x2-2*T,'y':y2}], layer='F.SilkS', width=configuration['silk_line_width']))

    #add pin-1 marker
    D = 0.3
    L = 2.5
    pin = [
        {'x': x1-D,'y': y2+D-L},
        {'x': x1-D,'y': y2+D},
        {'x': x1-D+L,'y': y2+D},
    ]

    kicad_mod.append(PolygoneLine(polygone=pin))
    kicad_mod.append(PolygoneLine(polygone=pin, layer='F.Fab', width=configuration['fab_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    pins_per_row = pins

    mpn = part_code.format(n=pins)
    alt_mpn = [code.format(n=pins) for code in alternative_codes]

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Molex {:s}, {:s} (compatible alternatives: {:s}), {:d} Pins per row ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, ', '.join(alt_mpn), pins_per_row, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    ########################## Dimensions ##############################
    B = (pins_per_row-1)*pitch
    A = B + 6.65

    #Centra os pinos em metade do pitch
    pad_row_1_y = 0
    pad_row_2_y = pad_row_1_y + pitch
    pad1_x = 0

    C = 1.7 + pitch*(pins-3) #1º need be 4.7mm

    body_edge={
        'left':-3.325,
        'right':A-3.325,
        'top': -8.92
        }
    body_edge['bottom'] = body_edge['top'] + 9.90

    ############################# Pads ##################################
    #
    # Pegs
    #
    if pins_per_row == 2:
        kicad_mod.append(Pad(at=[pitch/2, pad_row_1_y - 4.32], number="",
            type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=peg_drill,
            drill=peg_drill, layers=Pad.LAYERS_NPTH))
    elif pins_per_row == 3:
        kicad_mod.append(Pad(at=[pitch, pad_row_1_y - 4.32], number="",
            type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=peg_drill,
            drill=peg_drill, layers=Pad.LAYERS_NPTH))
    else:
        kicad_mod.append(Pad(at=[pad1_x + 2.15, pad_row_1_y - 4.32], number="",
            type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=peg_drill,
            drill=peg_drill, layers=Pad.LAYERS_NPTH))
        kicad_mod.append(Pad(at=[pad1_x + 2.15 + C, pad_row_1_y - 4.32], number="",
            type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=peg_drill,
            drill=peg_drill, layers=Pad.LAYERS_NPTH))

    #
    # Add pads
    #
    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    kicad_mod.append(PadArray(start=[pad1_x, pad_row_1_y], initial=1,
        pincount=pins_per_row, increment=1,  x_spacing=pitch, size=pad_size,
        type=Pad.TYPE_THT, shape=pad_shape, layers=Pad.LAYERS_THT, drill=drill,
        **optional_pad_params))

    ######################## Fabrication Layer ###########################
    main_body_poly= [
        {'x': body_edge['left'], 'y': body_edge['bottom']},
        {'x': body_edge['left'], 'y': body_edge['top']+1},
        {'x': body_edge['left']+1, 'y': body_edge['top']},
        {'x': body_edge['right']-1, 'y': body_edge['top']},
        {'x': body_edge['right'], 'y': body_edge['top']+1},
        {'x': body_edge['right'], 'y': body_edge['bottom']},
        {'x': body_edge['left'], 'y': body_edge['bottom']}
    ]
    kicad_mod.append(PolygoneLine(polygone=main_body_poly,
        width=configuration['fab_line_width'], layer="F.Fab"))

    main_arrow_poly= [
        {'x': -.75, 'y': body_edge['bottom']},
        {'x': 0, 'y': 0},
        {'x': 0.75, 'y': body_edge['bottom']}
    ]
    kicad_mod.append(PolygoneLine(polygone=main_arrow_poly,
        width=configuration['fab_line_width'], layer="F.Fab"))

    ######################## SilkS Layer ###########################

    off = configuration['silk_fab_offset']
    pad_silk_off = configuration['silk_line_width']/2 + configuration['silk_pad_clearance']

    r_no_silk = max(pad_size)/2 + pad_silk_off # simplified to circle instead of oval
    dy = abs(body_edge['bottom']) + off
    pin_center_silk_x = 0 if dy >= r_no_silk else sqrt(r_no_silk**2-dy**2)
    pin1_center_silk_x = pad_size[0]/2 + pad_silk_off # simplified to rectangle instead of rounded rect

    poly_s_t= [
        {'x': body_edge['left'] - off, 'y': body_edge['bottom'] + off},
        {'x': body_edge['left'] - off, 'y': body_edge['top'] + 1 - off},
        {'x': body_edge['left'] + 1 - off, 'y': body_edge['top'] - off},
        {'x': body_edge['right'] - 1 + off, 'y': body_edge['top'] - off},
        {'x': body_edge['right'] + off, 'y': body_edge['top'] + 1 - off},
        {'x': body_edge['right'] + off, 'y': body_edge['bottom'] + off}
    ]
    kicad_mod.append(PolygoneLine(polygone=poly_s_t,
        width=configuration['silk_line_width'], layer="F.SilkS"))

    if pin_center_silk_x == 0:
        kicad_mod.append(Line(
            start=[body_edge['left']-off, body_edge['bottom']],
            end=[body_edge['right']-off, body_edge['bottom']],
            layer="F.SilkS", width=configuration['silk_line_width']
        ))
    else:
        kicad_mod.append(Line(
            start=[body_edge['left']-off, body_edge['bottom']+off],
            end=[-pin1_center_silk_x, body_edge['bottom']+off],
            layer="F.SilkS", width=configuration['silk_line_width']
        ))
        kicad_mod.append(Line(
            start=[body_edge['right']+off, body_edge['bottom']+off],
            end=[(pins_per_row-1)*pitch + pin_center_silk_x, body_edge['bottom']+off],
            layer="F.SilkS", width=configuration['silk_line_width']
        ))
        kicad_mod.append(Line(
            start=[pin1_center_silk_x, body_edge['bottom']+off],
            end=[pitch - pin_center_silk_x, body_edge['bottom']+off],
            layer="F.SilkS", width=configuration['silk_line_width']
        ))
        for i in range(1, pins_per_row-1):
            xl = i*pitch + pin_center_silk_x
            xr = (i+1)*pitch - pin_center_silk_x
            kicad_mod.append(Line(
                start=[xl, body_edge['bottom']+off],
                end=[xr, body_edge['bottom']+off],
                layer="F.SilkS", width=configuration['silk_line_width']
            ))

    ######################## CrtYd Layer ###########################
    CrtYd_offset = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']

    poly_yd = [
        {'x': roundToBase(body_edge['left'] - CrtYd_offset, CrtYd_grid), 'y': roundToBase(body_edge['bottom'] + CrtYd_offset, CrtYd_grid)},
        {'x': roundToBase(body_edge['left'] - CrtYd_offset, CrtYd_grid), 'y': roundToBase(body_edge['top'] - CrtYd_offset, CrtYd_grid)},
        {'x': roundToBase(body_edge['right'] + CrtYd_offset, CrtYd_grid), 'y': roundToBase(body_edge['top'] - CrtYd_offset, CrtYd_grid)},
        {'x': roundToBase(body_edge['right'] + CrtYd_offset, CrtYd_grid), 'y': roundToBase(body_edge['bottom'] + CrtYd_offset, CrtYd_grid)},
        {'x': roundToBase(body_edge['left'] - CrtYd_offset, CrtYd_grid), 'y': roundToBase(body_edge['bottom'] + CrtYd_offset, CrtYd_grid)}
    ]

    kicad_mod.append(PolygoneLine(polygone=poly_yd,
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    cy1 = roundToBase(body_edge['top'] - configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(pad_size[1] + configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='top')

    ##################### Write to File and 3D ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins_per_row, variant, configuration):
    peg = variant_params[variant]['mount_pins'] == 'plastic_peg'

    silk_pad_off = configuration['silk_pad_clearance']+configuration['silk_line_width']/2

    mpn = variant_params[variant]['part_code']['mpn'].format(n=pins_per_row*2)
    old_mpn = variant_params[variant]['part_code']['eng_num'].format(n=pins_per_row*2)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=old_mpn, num_rows=number_of_rows, pins_per_row=pins_per_row, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    descr_format_str = "Molex {:s}, old mpn/engineering number: {:s}, example for new mpn: {:s}, {:d} Pins per row, Mounting: {:s} ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(descr_format_str.format(
        series_long, old_mpn, mpn, pins_per_row,
        variant_params[variant]['descriptive_name'], variant_params[variant]['datasheet']))
    tags = configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation])
    tags += variant_params[variant]['mount_pins']
    kicad_mod.setTags(tags)


    #calculate fp dimensions

    #connector length
    A = pins_per_row * pitch + 1.2

    #pin centers
    B = (pins_per_row - 1) * pitch

    #plasic pin-lock
    C = A + 4

    #connector width
    W = 9.6

    #corner positions
    x1 = -(A-B)/2
    x2 = x1 + A

    y2 = row + 1.85
    y1 = y2 - W

    #tab length
    tab_l = 3.4
    #tab width
    tab_w = 1.4

    body_edge={
        'left':x1,
        'right':x2,
        'bottom':y2,
        'top': y1
        }
    bounding_box = body_edge.copy()
    bounding_box['bottom'] = body_edge['bottom'] + tab_w

    off = configuration['silk_fab_offset']

    #generate the pads
    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT
    else:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_ROUNDRECT

    for row_idx in range(2):
        kicad_mod.append(PadArray(
            pincount=pins_per_row, initial=row_idx*pins_per_row+1,
            start=[0, row_idx*row], x_spacing=pitch,
            type=Pad.TYPE_THT, shape=pad_shape,
            size=pad_size, drill=drill, layers=Pad.LAYERS_THT,
            **optional_pad_params))

    #add PCB locators if needed
    pad_silk_offset = configuration['silk_pad_clearance']+configuration['silk_line_width']/2
    if peg:
        loc = 3.00
        mounting_pin_y = row - 0.46
        lx1 = B/2-C/2
        lx2 = B/2+C/2
        kicad_mod.append(Pad(at=[lx1, mounting_pin_y],type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=loc,drill=loc, layers=Pad.LAYERS_NPTH))
        kicad_mod.append(Pad(at=[lx2, mounting_pin_y],type=Pad.TYPE_NPTH, shape=Pad.SHAPE_CIRCLE, size=loc,drill=loc, layers=Pad.LAYERS_NPTH))

        bounding_box['left'] = lx1-loc/2
        bounding_box['right'] = lx2+loc/2
        ######################## Fab ############################
        mount_pin_radius = loc/2

        kicad_mod.append(Arc(center=[lx1,mounting_pin_y],
            start=[lx1,mounting_pin_y+mount_pin_radius], angle=180,
            layer='F.Fab', width=configuration['fab_line_width']))

        kicad_mod.append(Line(start=[lx1,mounting_pin_y-mount_pin_radius],
            end=[x1,mounting_pin_y-mount_pin_radius],
            layer='F.Fab', width=configuration['fab_line_width']))
        kicad_mod.append(Line(start=[lx1,mounting_pin_y+mount_pin_radius],
            end=[x1,mounting_pin_y+mount_pin_radius],
            layer='F.Fab', width=configuration['fab_line_width']))


        kicad_mod.append(Arc(center=[lx2,mounting_pin_y],
            start=[lx2,mounting_pin_y-mount_pin_radius], angle=180,
            layer='F.Fab', width=configuration['fab_line_width']))

        kicad_mod.append(Line(start=[lx2,mounting_pin_y-mount_pin_radius],
            end=[x2,mounting_pin_y-mount_pin_radius],
            layer='F.Fab', width=configuration['fab_line_width']))
        kicad_mod.append(Line(start=[lx2,mounting_pin_y+mount_pin_radius],
            end=[x2,mounting_pin_y+mount_pin_radius],
            layer='F.Fab', width=configuration['fab_line_width']))

        ######################## Silk ############################
        mount_pin_radius = loc/2 + silk_pad_off
        kicad_mod.append(Arc(center=[lx1,mounting_pin_y],
            start=[lx1,mounting_pin_y+mount_pin_radius], angle=180,
            layer='F.SilkS', width=configuration['silk_line_width']))

        kicad_mod.append(Line(start=[lx1,mounting_pin_y-mount_pin_radius],
            end=[x1-off,mounting_pin_y-mount_pin_radius],
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(Line(start=[lx1,mounting_pin_y+mount_pin_radius],
            end=[x1-off,mounting_pin_y+mount_pin_radius],
            layer='F.SilkS', width=configuration['silk_line_width']))


        kicad_mod.append(Arc(center=[lx2,mounting_pin_y],
            start=[lx2,mounting_pin_y-mount_pin_radius], angle=180,
            layer='F.SilkS', width=configuration['silk_line_width']))

        kicad_mod.append(Line(start=[lx2,mounting_pin_y-mount_pin_radius],
            end=[x2+off,mounting_pin_y-mount_pin_radius],
            layer='F.SilkS', width=configuration['silk_line_width']))
        kicad_mod.append(Line(start=[lx2,mounting_pin_y+mount_pin_radius],
            end=[x2+off,mounting_pin_y+mount_pin_radius],
            layer='F.SilkS', width=configuration['silk_line_width']))

    #draw the outline of the shape
    kicad_mod.append(RectLine(start=[x1,y1],end=[x2,y2],layer='F.Fab',width=configuration['fab_line_width']))

    #draw the outline of the tab
    kicad_mod.append(PolygoneLine(polygone=[
        {'x': B/2 - tab_l/2,'y': y2},
        {'x': B/2 - tab_l/2,'y': y2 + tab_w},
        {'x': B/2 + tab_l/2,'y': y2 + tab_w},
        {'x': B/2 + tab_l/2,'y': y2},
    ], layer='F.Fab', width=configuration['fab_line_width']))

    #draw the outline of each pin slot (alternating shapes)
    #slot size
    S = 3.3

    def square_slot(x,y):
        kicad_mod.append(RectLine(start=[x-S/2,y-S/2], end=[x+S/2,y+S/2],
            layer='F.Fab', width=configuration['fab_line_width']))

    def notch_slot(x,y):
        kicad_mod.append(PolygoneLine(polygone=[
        {'x': x-S/2, 'y': y+S/2},
        {'x': x-S/2, 'y': y-S/4},
        {'x': x-S/4, 'y': y-S/2},
        {'x': x+S/4, 'y': y-S/2},
        {'x': x+S/2, 'y': y-S/4},
        {'x': x+S/2, 'y': y+S/2},
        {'x': x-S/2, 'y': y+S/2},
        ], layer='F.Fab', width=configuration['fab_line_width']))

    q = 1
    notch = True
    for i in range(pins_per_row):
        if notch:
            y_square = row/2 - 4.2/2
            y_notch = row/2 + 4.2/2
        else:
            y_square = row/2 + 4.2/2
            y_notch = row/2 - 4.2/2

        square_slot(i * pitch, y_square)
        notch_slot(i*pitch, y_notch)

        q -= 1

        if (q == 0):
            q = 2
            notch = not notch


    #draw the outline of the connector on the silkscreen
    outline = [
    {'x': B/2,'y': y1-off},
    {'x': x1-off,'y': y1-off},
    {'x': x1-off,'y': y2+off},
    {'x': B/2 - tab_l/2 - off,'y': y2+off},
    {'x': B/2 - tab_l/2 - off,'y': y2 + off + tab_w},
    {'x': B/2, 'y': y2 + off + tab_w},
    ]

    kicad_mod.append(PolygoneLine(polygone=outline, layer="F.SilkS", width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=outline, x_mirror=B/2, layer="F.SilkS", width=configuration['silk_line_width']))

    #pin-1 marker

    L = 2.5
    O = 0.35

    pin = [
        {'x': x1 + L,'y': y1 - O},
        {'x': x1 - O,'y': y1 - O},
        {'x': x1 - O,'y': y1 + L},
    ]

    kicad_mod.append(PolygoneLine(polygone=pin, layer="F.SilkS", width=configuration['silk_line_width']))
    kicad_mod.append(PolygoneLine(polygone=pin, width=configuration['fab_line_width'], layer='F.Fab'))

    ########################### CrtYd #################################
    CrtYd_offset = configuration['courtyard_offset']['connector']
    CrtYd_grid = configuration['courtyard_grid']

    cx1 = roundToBase(bounding_box['left'] - CrtYd_offset, CrtYd_grid)
    cy1 = roundToBase(bounding_box['top'] - CrtYd_offset, CrtYd_grid)

    cx2 = roundToBase(bounding_box['right'] + CrtYd_offset, CrtYd_grid)
    cy2 = roundToBase(bounding_box['bottom'] + CrtYd_offset, CrtYd_grid)


    if peg:
        cx3 = roundToBase(body_edge['left']-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
        cx4 = roundToBase(body_edge['right']+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
        mount_pin_radius = loc/2
        cy3=roundToBase(mounting_pin_y - mount_pin_radius - configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

        poly_crtyd = [
            {'x': cx3, 'y': cy1},
            {'x': cx3, 'y': cy3},
            {'x': cx1, 'y': cy3},
            {'x': cx1, 'y': cy2},
            {'x': cx2, 'y': cy2},
            {'x': cx2, 'y': cy3},
            {'x': cx4, 'y': cy3},
            {'x': cx4, 'y': cy1},
            {'x': cx3, 'y': cy1}
        ]
        kicad_mod.append(PolygoneLine(polygone=poly_crtyd,
            layer='F.CrtYd', width=configuration['courtyard_line_width']))
    else:
        kicad_mod.append(RectLine(
            start=[cx1, cy1], end=[cx2, cy2],
            layer='F.CrtYd', width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def generate_one_footprint(pins, configuration):
    mpn = part_base.format(n=pins*number_of_rows) #JST part number format string
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pins, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("JST {:s} series connector, {:s} ({:s}), generated with kicad-footprint-generator".format(series, mpn, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    #calculate fp dimensions
    A = (pins - 1) * pitch
    B = A + 3.9

    #draw the component outline
    x1 = A/2.0 - B/2.0
    x2 = x1 + B
    y2 = 2 + 1.5
    y1 = y2 - 5
    body_edge={'left':x1, 'right':x2, 'top':y1, 'bottom':y2}

    #wall thickness
    t_short = 0.75 #short side (fixed at 5mm)
    t_long = 0.4 #long side (A/B dimension)
    
    #draw simple outline on F.Fab layer
    kicad_mod.append(RectLine(start=[x1,y1],end=[x2,y2],layer='F.Fab',width=configuration['fab_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(x1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy1 = roundToBase(y1-configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    cx2 = roundToBase(x2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])
    cy2 = roundToBase(y2+configuration['courtyard_offset']['connector'], configuration['courtyard_grid'])

    kicad_mod.append(RectLine(
        start=[cx1, cy1], end=[cx2, cy2],
        layer='F.CrtYd', width=configuration['courtyard_line_width']))

    #draw silk polarity lines
    kicad_mod.append(RectLine(start=[x1+t_short,y1+t_long],end=[x2-t_short,y2-t_long],layer='F.SilkS',width=configuration['silk_line_width']))
    
    #offset off
    off = configuration['silk_fab_offset']

    #draw silk keying/polarity marks measured from 3D model on JST's site
    # from bottom (pin 2 row) of connector, notches are 1.6mm up and 0.8mm wide
    kicad_mod.append(Line(start=[x1-off,y2-2.4],end=[x1+t_short,y2-2.4],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x2+off,y2-2.4],end=[x2-t_short,y2-2.4],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x1-off,y2-1.6],end=[x1+t_short,y2-1.6],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x2+off,y2-1.6],end=[x2-t_short,y2-1.6],layer='F.SilkS',width=configuration['silk_line_width']))
    # from sides, inner edge of notches are 3.42mm inside and 0.94mm wide at the top (pin 1 row) and 1.50mm wide at the bottom (pin 2 row)
    kicad_mod.append(Line(start=[x1+3.42,y1-off],end=[x1+3.42,y1+t_long],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x1+2.48,y1-off],end=[x1+2.48,y1+t_long],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x2-3.42,y1-off],end=[x2-3.42,y1+t_long],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x2-2.48,y1-off],end=[x2-2.48,y1+t_long],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x1+3.42,y2+off],end=[x1+3.42,y2-t_long],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x1+1.92,y2+off],end=[x1+1.92,y2-t_long],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x2-3.42,y2+off],end=[x2-3.42,y2-t_long],layer='F.SilkS',width=configuration['silk_line_width']))
    kicad_mod.append(Line(start=[x2-1.92,y2+off],end=[x2-1.92,y2-t_long],layer='F.SilkS',width=configuration['silk_line_width']))

    x1 -= off
    y1 -= off
    x2 += off
    y2 += off

    #draw silk outline
    kicad_mod.append(RectLine(start=[x1,y1],end=[x2,y2],width=configuration['silk_line_width'],layer='F.SilkS'))

    #add p1 marker
    px = x1 - 0.2
    m = 0.3

    marker = [
    {'x': px,'y': 0},
    {'x': px-2*m,'y': m},
    {'x': px-2*m,'y': -m},
    {'x': px,'y': 0}
    ]

    kicad_mod.append(PolygoneLine(polygone=marker,width=configuration['silk_line_width'],layer='F.SilkS'))
    sl = 0.5
    marker =[
        {'x': body_edge['left'], 'y': sl},
        {'x': body_edge['left'] + (2*sl)/sqrt(2) , 'y': 0},
        {'x': body_edge['left'] , 'y': -sl}
    ]
    kicad_mod.append(PolygoneLine(polygone=marker,layer='F.Fab',width=configuration['fab_line_width']))

    #generate the pads (row 1)

    size = [pitch - pad_to_pad_clearance, row_pitch - pad_to_pad_clearance]
    if size[0] - drill < 2*min_annular_ring:
        size[0] = drill + 2*min_annular_ring
    if size[0] - drill > 2*pad_copper_y_solder_length:
        size[0] = drill + 2*pad_copper_y_solder_length

    if size[1] - drill < 2*min_annular_ring:
        size[1] = drill + 2*min_annular_ring
    if size[1] - drill > 2*pad_copper_y_solder_length:
        size[1] = drill + 2*pad_copper_y_solder_length

    if size[0] == size[1]:
        pad_shape = Pad.SHAPE_CIRCLE
    else:
        pad_shape = Pad.SHAPE_OVAL

    optional_pad_params = {}
    if configuration['kicad4_compatible']:
        optional_pad_params['tht_pad1_shape'] = Pad.SHAPE_RECT

    for row_idx in range(2):
        kicad_mod.append(PadArray(
            pincount=pins, x_spacing=pitch,
            type=Pad.TYPE_THT, shape=pad_shape,
            start=[0, row_idx*row_pitch], initial=row_idx+1, increment=2,
            size=size, drill=drill, layers=Pad.LAYERS_THT,
            **optional_pad_params))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy1, 'bottom':cy2}, fp_name=footprint_name, text_y_inside_position='top')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
def gen_footprint(pinnum, manpart, configuration):
	orientation_str = configuration['orientation_options']['H']
	footprint_name = configuration['fp_name_format_string'].format(
		man=manufacturer,
		series='',
		mpn=manpart,
		num_rows=1,
		pins_per_row=pinnum,
		pitch=pitch,
		orientation=orientation_str)
	footprint_name = footprint_name.replace('__','_')

	kicad_mod = Footprint(footprint_name)
	kicad_mod.setDescription("{manufacturer} {series}, {mpn}{alt_mpn}, {pins_per_row} Pins per row ({datasheet}), generated with kicad-footprint-generator".format(
		manufacturer = manufacturer,
		series = series_long,
		mpn = manpart, 
		alt_mpn = '', 
		pins_per_row = pinnum,
		datasheet = datasheet))
		
	kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
		orientation=orientation_str, man=manufacturer,
		entry='horizontal'))

	kicad_mod.setAttribute('smd')
	
	# Pads
	kicad_mod.append(PadArray(start=[-6.775+padsize[0]/2, -(pitch*(pinnum-1))/2], initial=1,
		pincount=pinnum, increment=1,  y_spacing=pitch, size=padsize,
		type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, layers=Pad.LAYERS_SMT, drill=None))

	# Fab
	for y in range(0, pinnum):
		gen_fab_pins(-6.775+padsize[0]/2, -(pitch*(pinnum-1))/2+pitch+(y-1)*2.54, kicad_mod, configuration)
	poly_f_body = [
        {'x': -6.775+padsize[0]/2+3.8, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2+0.4+2.54},
        {'x': -6.775+padsize[0]/2+3.8+0.4, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2+2.54},
        {'x': -6.775+padsize[0]/2+6.3, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2+2.54},
        {'x': -6.775+padsize[0]/2+6.3, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2+2.54*pinnum+2.54},
        {'x': -6.775+padsize[0]/2+3.8, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2+2.54*pinnum+2.54},
        {'x': -6.775+padsize[0]/2+3.8, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2+0.4+2.54},
    ]
	kicad_mod.append(PolygoneLine(polygone=poly_f_body,
        width=configuration['fab_line_width'], layer="F.Fab"))

	# SilkS
	silkslw = configuration['silk_line_width']
	s_body = [
		{'x': -6.775+padsize[0]/2+3.8-silkslw, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2-silkslw+2.54},
		{'x': -6.775+padsize[0]/2+6.3+silkslw, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2-silkslw+2.54},
		{'x': -6.775+padsize[0]/2+6.3+silkslw, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2+2.54*pinnum+silkslw+2.54},
		{'x': -6.775+padsize[0]/2+3.8-silkslw, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2+2.54*pinnum+silkslw+2.54},
		{'x': -6.775+padsize[0]/2+3.8-silkslw, 'y': -(pitch*(pinnum-1))/2-pitch-2.54/2-silkslw+2.54},
	]
	kicad_mod.append(PolygoneLine(polygone=s_body,
            width=configuration['silk_line_width'], layer="F.SilkS"))
	for y in range(0, pinnum):
		gen_silk_pins(-6.775+padsize[0]/2, -(pitch*(pinnum-1))/2+pitch+(y-1)*2.54, kicad_mod, configuration, y==0)
	s_pin1 = [
        {'x': -6.775+padsize[0]/2-(2.5/2+configuration['silk_pad_clearance']+configuration['silk_line_width']), 'y': -(pitch*(pinnum-1))/2},
        {'x': -6.775+padsize[0]/2-(2.5/2+configuration['silk_pad_clearance']+configuration['silk_line_width']), 'y': -(pitch*(pinnum-1))/2-1/2-configuration['silk_line_width']-configuration['silk_pad_clearance']},
        {'x': -6.775+padsize[0]/2, 'y': -(pitch*(pinnum-1))/2-1/2-configuration['silk_line_width']-configuration['silk_pad_clearance']},
	]
	kicad_mod.append(PolygoneLine(polygone=s_pin1,
            width=configuration['silk_line_width'], layer="F.SilkS"))
	
	
	# CrtYd
	cy_offset = configuration['courtyard_offset']['connector']
	cy_grid = configuration['courtyard_grid']
	bounding_box={
		'left': -6.775+padsize[0]/2-2.5/2,
		'right': -6.775+padsize[0]/2+12.3,
        'top': -(pitch*(pinnum-1))/2-pitch-2.54/2+2.54,
        'bottom': -(pitch*(pinnum-1))/2-pitch-2.54/2+2.54*pinnum+2.54,
	}
	cy_top = roundToBase(bounding_box['top'] - cy_offset, cy_grid)
	cy_bottom = roundToBase(bounding_box['bottom'] + cy_offset, cy_grid)
	cy_left = roundToBase(bounding_box['left'] - cy_offset, cy_grid)
	cy_right = roundToBase(bounding_box['right'] + cy_offset, cy_grid)
	poly_cy = [
		{'x': cy_left, 'y': cy_top},
		{'x': cy_right, 'y': cy_top},
		{'x': cy_right, 'y': cy_bottom},
		{'x': cy_left, 'y': cy_bottom},
		{'x': cy_left, 'y': cy_top},
	]
	kicad_mod.append(PolygoneLine(polygone=poly_cy,
		layer='F.CrtYd', width=configuration['courtyard_line_width']))

	# Text Fields
	body_edge={
        'left': -6.775+padsize[0]/2+3.8,
        'right': -6.775+padsize[0]/2+6.3,
        'top': -(pitch*(pinnum-1))/2-pitch-2.54/2-silkslw+2.54,
        'bottom': -(pitch*(pinnum-1))/2-pitch-2.54/2+2.54*pinnum+silkslw+2.54,
    }
	addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':cy_top, 'bottom':cy_bottom}, fp_name=footprint_name, text_y_inside_position='center', allow_rotation=True)

	# 3D model
	model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')
	lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
	model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
	kicad_mod.append(Model(filename=model_name))
	
	# Output
	output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
	if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
		os.makedirs(output_dir)
	filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

	file_handler = KicadFileHandler(kicad_mod)
	file_handler.writeFile(filename)
def generate_one_footprint(pincount, configuration):
    mpn = part_code.format(n=pincount)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(man=manufacturer,
        series=series,
        mpn=mpn, num_rows=number_of_rows, pins_per_row=pincount//2, mounting_pad = "",
        pitch=pitch, orientation=orientation_str)

    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("Molex {:s}, {:s}, {:d} Pins ({:s}), generated with kicad-footprint-generator".format(series_long, mpn, pincount, datasheet))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(series=series,
        orientation=orientation_str, man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    kicad_mod.setAttribute('smd')

    # calculate working values
    pad_x_spacing = 0.5
    pad_y_spacing = 2.4 + 1.1
    pad_width = 0.3
    pad_height = 1.1
    pad_x_span = (pad_x_spacing * ((pincount / 2) - 1))

    h_body_width = 3.1 / 2.0
    h_body_length = (pad_x_span / 2.0) + 1.4 + 0.37

    fab_width = configuration['fab_line_width']

    outline_x = h_body_length - (pad_x_span / 2.0) - pad_width/2 - (configuration['silk_pad_clearance'] + configuration['silk_line_width']/2)
    marker_y = 0.8
    silk_width = configuration['silk_line_width']
    nudge = configuration['silk_fab_offset']

    courtyard_width = configuration['courtyard_line_width']
    courtyard_precision = configuration['courtyard_grid']
    courtyard_clearance = configuration['courtyard_offset']['connector']
    courtyard_x = roundToBase(h_body_length + courtyard_clearance, courtyard_precision)
    courtyard_y = roundToBase((pad_y_spacing + pad_height) / 2.0 + courtyard_clearance, courtyard_precision)

    # create pads
    kicad_mod.append(PadArray(pincount=pincount//2, x_spacing=pad_x_spacing, y_spacing=0,\
        center=[0,-pad_y_spacing/2.0], initial=1, increment=2, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, size=[pad_width, pad_height],\
        layers=Pad.LAYERS_SMT))
    kicad_mod.append(PadArray(pincount=pincount//2, x_spacing=pad_x_spacing, y_spacing=0,\
        center=[0,pad_y_spacing/2.0], initial=2, increment=2, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, size=[pad_width, pad_height],\
        layers=Pad.LAYERS_SMT))

    # create fab outline and pin 1 marker
    kicad_mod.append(RectLine(start=[-h_body_length, -h_body_width], end=[h_body_length, h_body_width], layer='F.Fab', width=fab_width))
    body_edge={
        'left':-h_body_length,
        'top':-h_body_width
    }
    body_edge['right'] = -body_edge['left']
    body_edge['bottom'] = -body_edge['top']
    kicad_mod.append(Line(start=[-h_body_length+outline_x, -h_body_width-nudge], end=[-h_body_length+outline_x, -h_body_width-marker_y], layer='F.Fab', width=fab_width))

    # create silkscreen outline and pin 1 marker
    left_outline = [[-h_body_length+outline_x, h_body_width+nudge], [-h_body_length-nudge, h_body_width+nudge], [-h_body_length-nudge, -h_body_width-nudge],\
                    [-h_body_length+outline_x, -h_body_width-nudge], [-h_body_length+outline_x, -h_body_width-marker_y]]
    right_outline = [[h_body_length-outline_x, h_body_width+nudge], [h_body_length+nudge, h_body_width+nudge], [h_body_length+nudge, -h_body_width-nudge],\
                     [h_body_length-outline_x, -h_body_width-nudge]]
    kicad_mod.append(PolygoneLine(polygone=left_outline, layer='F.SilkS', width=silk_width))
    kicad_mod.append(PolygoneLine(polygone=right_outline, layer='F.SilkS', width=silk_width))

    # create courtyard
    kicad_mod.append(RectLine(start=[-courtyard_x, -courtyard_y], end=[courtyard_x, courtyard_y], layer='F.CrtYd', width=courtyard_width))

    ######################### Text Fields ###############################

    addTextFields(kicad_mod=kicad_mod, configuration=configuration, body_edges=body_edge,
        courtyard={'top':-courtyard_y, 'bottom':+courtyard_y},
        fp_name=footprint_name, text_y_inside_position='center')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix','${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series, man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix, lib_name=lib_name, fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(output_dir): #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename =  '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir, fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)
Example #60
0
def generate_one_footprint(pins, params, configuration):
    pad_silk_off = configuration[
        'silk_pad_clearance'] + configuration['silk_line_width'] / 2
    off = configuration['silk_fab_offset']

    mpn = params['mpn'].format(n=pins * number_of_rows)

    # handle arguments
    orientation_str = configuration['orientation_options'][orientation]
    footprint_name = configuration['fp_name_format_string'].format(
        man=manufacturer,
        series=series,
        mpn=mpn,
        num_rows=number_of_rows,
        pins_per_row=pins_per_row,
        mounting_pad="",
        pitch=pitch,
        orientation=orientation_str)
    footprint_name += params['fp_name_suffix']

    kicad_mod = Footprint(footprint_name)
    desc_format_str = "Molex {:s}, {:s}{:s}, {:d} Pins per row ({:s}), generated with kicad-footprint-generator"
    kicad_mod.setDescription(
        desc_format_str.format(series_long, mpn, params['description'], pins,
                               params['datasheet']))
    kicad_mod.setTags(configuration['keyword_fp_string'].format(
        series=series,
        orientation=orientation_str,
        man=manufacturer,
        entry=configuration['entry_direction'][orientation]))

    # Dimensions
    P = (pins - 1) * pitch
    B = P + 2 * 6.79  # connector length
    W = 14.76  # connector width

    body_edge = {}
    body_edge['left'] = (P - B) / 2
    body_edge['right'] = body_edge['left'] + B
    body_edge['top'] = 0.925
    body_edge['bottom'] = body_edge['top'] + 14.76

    bounding_box = body_edge.copy()
    bounding_box['top'] = -offset_second_pad - pad_size[1] / 2

    ##################################  Pins ##################################
    kicad_mod.append(
        PadArray(pincount=pins,
                 start=[0, 0],
                 x_spacing=pitch,
                 size=pad_size,
                 drill=drill,
                 type=Pad.TYPE_THT,
                 shape=Pad.SHAPE_RECT,
                 layers=Pad.LAYERS_THT))
    kicad_mod.append(
        PadArray(pincount=pins,
                 start=[0, -offset_second_pad],
                 x_spacing=pitch,
                 size=pad_size,
                 drill=drill,
                 shape=Pad.SHAPE_RECT,
                 type=Pad.TYPE_THT,
                 layers=Pad.LAYERS_THT))

    d_small = 0.3
    s_small = d_small + 2 * min_annular_ring
    thermal_to_pad_edge = s_small / 2 + 0.15

    if params['thermals']:
        for xi in range(pins):
            n = xi + 1
            pad_center_y = -offset_second_pad / 2
            pad_center_x = xi * pitch
            pad_h = offset_second_pad + pad_size[1]
            dx = (pad_size[0] - 2 * thermal_to_pad_edge) / 2
            dy = (pad_h - 2 * thermal_to_pad_edge) / 4

            #draw rectangle on F.Fab layer

            # kicad_mod.append(RectLine(
            #     start=[pad_center_x - pad_l/2, pad_center_y - pad_size[1]/2],
            #     end=[pad_center_x + pad_l/2, pad_center_y + pad_size[1]/2],
            #     layer='F.Fab', width=configuration['fab_line_width']))

            kicad_mod.append(
                PadArray(center=[pad_center_x, pad_center_y],
                         pincount=3,
                         y_spacing=dy * 2,
                         drill=d_small,
                         size=s_small,
                         initial=n,
                         increment=0,
                         shape=Pad.SHAPE_CIRCLE,
                         type=Pad.TYPE_THT,
                         layers=Pad.LAYERS_THT))
            kicad_mod.append(
                PadArray(center=[pad_center_x - dx, pad_center_y],
                         pincount=5,
                         y_spacing=dy,
                         drill=d_small,
                         size=s_small,
                         initial=n,
                         increment=0,
                         type=Pad.TYPE_THT,
                         shape=Pad.SHAPE_CIRCLE,
                         layers=Pad.LAYERS_THT))
            kicad_mod.append(
                PadArray(center=[pad_center_x + dx, pad_center_y],
                         pincount=5,
                         y_spacing=dy,
                         drill=d_small,
                         size=s_small,
                         initial=n,
                         increment=0,
                         type=Pad.TYPE_THT,
                         shape=Pad.SHAPE_CIRCLE,
                         layers=Pad.LAYERS_THT))

    if params['lock']:
        kicad_mod.append(
            Pad(at=[-ret_dx, ret_dy],
                type=Pad.TYPE_THT,
                shape=Pad.SHAPE_CIRCLE,
                size=ret_size,
                drill=ret_drill,
                layers=Pad.LAYERS_THT))
        kicad_mod.append(
            Pad(at=[P + ret_dx, ret_dy],
                type=Pad.TYPE_THT,
                shape=Pad.SHAPE_CIRCLE,
                size=ret_size,
                drill=ret_drill,
                layers=Pad.LAYERS_THT))

    kicad_mod.append(
        RectLine(
            start=[-pad_size[0] / 2, -offset_second_pad - pad_size[1] / 2],
            end=[pad_size[0] / 2, pad_size[1] / 2],
            offset=pad_silk_off,
            width=configuration['silk_line_width'],
            layer='B.SilkS'))

    ############################ Outline ##############################
    #kicad_mod.append(RectLine(start=[xl1, yt1], end=[xr1, yb1], layer='F.Fab', width=configuration['fab_line_width']))
    kicad_mod.append(
        RectLine(start=[body_edge['left'], body_edge['top']],
                 end=[body_edge['right'], body_edge['bottom']],
                 layer='F.Fab',
                 width=configuration['fab_line_width']))

    if params['lock']:
        silk1 = [
            {
                'x': -pad_size[0] / 2 - pad_silk_off,
                'y': body_edge['top'] - off
            },
            {
                'x': body_edge['left'] - off,
                'y': body_edge['top'] - off
            },
            {
                'x': body_edge['left'] - off,
                'y': ret_dy - ret_size / 2
            },
        ]
        kicad_mod.append(
            PolygoneLine(polygone=silk1,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))
        kicad_mod.append(
            PolygoneLine(polygone=silk1,
                         layer='F.SilkS',
                         width=configuration['silk_line_width'],
                         x_mirror=P / 2))
        silk2 = [
            {
                'x': body_edge['left'] - off,
                'y': ret_dy + ret_size / 2
            },
            {
                'x': body_edge['left'] - off,
                'y': body_edge['bottom'] + off
            },
            {
                'x': P / 2,
                'y': body_edge['bottom'] + off
            },
        ]
        kicad_mod.append(
            PolygoneLine(polygone=silk2,
                         layer='F.SilkS',
                         width=configuration['silk_line_width']))
        kicad_mod.append(
            PolygoneLine(polygone=silk2,
                         layer='F.SilkS',
                         width=configuration['silk_line_width'],
                         x_mirror=P / 2))
    else:
        kicad_mod.append(
            RectLine(start=[body_edge['left'], body_edge['top']],
                     end=[body_edge['right'], body_edge['bottom']],
                     offset=off,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    for i in range(pins - 1):
        kicad_mod.append(
            Line(start=[
                i * pitch + pad_size[0] / 2 + pad_silk_off,
                body_edge['top'] - off
            ],
                 end=[(i + 1) * pitch - pad_size[0] / 2 - pad_silk_off,
                      body_edge['top'] - off],
                 layer='F.SilkS',
                 width=configuration['silk_line_width']))

    for i in range(pins):
        w_pin = 1
        kicad_mod.append(
            RectLine(
                start=[i * pitch - w_pin / 2, body_edge['top']],
                end=[i * pitch + w_pin / 2, -offset_second_pad - drill / 2],
                layer='F.Fab',
                width=configuration['fab_line_width']))

    ############################ Pin 1 ################################
    # Pin 1 designator
    pin1_sl = 2.4
    pin1 = [{
        'x': -pin1_sl / 2,
        'y': body_edge['top']
    }, {
        'x': 0,
        'y': body_edge['top'] + pin1_sl / sqrt(2)
    }, {
        'x': pin1_sl / 2,
        'y': body_edge['top']
    }]
    kicad_mod.append(
        PolygoneLine(polygone=pin1,
                     layer='F.Fab',
                     width=configuration['fab_line_width']))

    pin1 = [{
        'x': -pad_size[0] / 2 - pad_silk_off,
        'y': body_edge['top'] - off
    }, {
        'x': -pad_size[0] / 2 - pad_silk_off,
        'y': -offset_second_pad - pad_size[1] / 2
    }]
    kicad_mod.append(
        PolygoneLine(polygone=pin1,
                     layer='F.SilkS',
                     width=configuration['silk_line_width']))

    # pin1 = [
    #     {'x': 0, 'y': 8},
    #     {'x': 0.5, 'y': 9},
    #     {'x': -0.5, 'y': 9},
    #     {'x': 0, 'y': 8},
    # ]
    # kicad_mod.append(PolygoneLine(polygone=pin1, layer='F.SilkS', width=configuration['silk_line_width']))

    ########################### CrtYd #################################
    cx1 = roundToBase(
        bounding_box['left'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy1 = roundToBase(
        bounding_box['top'] - configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    cx2 = roundToBase(
        bounding_box['right'] + configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])
    cy2 = roundToBase(
        bounding_box['bottom'] +
        configuration['courtyard_offset']['connector'],
        configuration['courtyard_grid'])

    kicad_mod.append(
        RectLine(start=[cx1, cy1],
                 end=[cx2, cy2],
                 layer='F.CrtYd',
                 width=configuration['courtyard_line_width']))

    ######################### Text Fields ###############################
    addTextFields(kicad_mod=kicad_mod,
                  configuration=configuration,
                  body_edges=body_edge,
                  courtyard={
                      'top': cy1,
                      'bottom': cy2
                  },
                  fp_name=footprint_name,
                  text_y_inside_position='bottom')

    ##################### Output and 3d model ############################
    model3d_path_prefix = configuration.get('3d_model_prefix',
                                            '${KISYS3DMOD}/')

    lib_name = configuration['lib_name_format_string'].format(series=series,
                                                              man=manufacturer)
    model_name = '{model3d_path_prefix:s}{lib_name:s}.3dshapes/{fp_name:s}.wrl'.format(
        model3d_path_prefix=model3d_path_prefix,
        lib_name=lib_name,
        fp_name=footprint_name)
    kicad_mod.append(Model(filename=model_name))

    output_dir = '{lib_name:s}.pretty/'.format(lib_name=lib_name)
    if not os.path.isdir(
            output_dir
    ):  #returns false if path does not yet exist!! (Does not check path validity)
        os.makedirs(output_dir)
    filename = '{outdir:s}{fp_name:s}.kicad_mod'.format(outdir=output_dir,
                                                        fp_name=footprint_name)

    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile(filename)