#!/usr/bin/env python3

'''
kicad-footprint-generator is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

kicad-footprint-generator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with kicad-footprint-generator. If not, see < http://www.gnu.org/licenses/ >.
'''

import sys
import os
#sys.path.append(os.path.join(sys.path[0],"..","..","kicad_mod")) # load kicad_mod path

# export PYTHONPATH="${PYTHONPATH}<path to kicad-footprint-generator directory>"
sys.path.append(os.path.join(sys.path[0], "..", "..", ".."))  # load parent path of KicadModTree
from math import sqrt
import argparse
import yaml
from helpers import *
from KicadModTree import *

sys.path.append(os.path.join(sys.path[0], "..", "..", "tools"))  # load parent path of tools
from footprint_text_fields import addTextFields

series = "Mini-Fit_Sr"
series_long = 'Mini-Fit Sr. Power Connectors'
manufacturer = 'Molex'
orientation = 'V'
number_of_rows = 2
datasheet = 'http://www.molex.com/pdm_docs/sd/439151404_sd.pdf'

#pins_per_row per row
pins_per_row_range = [3, 4, 5, 6, 7]

#Molex part number
#n = number of circuits per row
part_code = "43915-xx{n:02}"

pitch = 10
drill = 2.8

offset_second_pad = 4.4
pitch_row = offset_second_pad + 8.06

pad_to_pad_clearance = 3
max_annular_ring = 1
min_annular_ring = 0.15

#locating pins
x_loc = 8.43
r_loc = 3.0



pad_size = [offset_second_pad + 0.1, 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

version_params = {
    'with_thermals':{
        'description': ', With thermal vias in pads',
        'fp_name_suffix': '_ThermalVias',
        'thermals': True
    },
    'only_pads':{
        'description': '',
        'fp_name_suffix': '',
        'thermals': False
    }
}

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','${KICAD6_3DMODEL_DIR}/')

    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 version in version_params:
        for pins_per_row in pins_per_row_range:
            generate_one_footprint(pins_per_row, version_params[version], configuration)

#!/usr/bin/env python3

'''
kicad-footprint-generator is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

kicad-footprint-generator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with kicad-footprint-generator. If not, see < http://www.gnu.org/licenses/ >.
'''

import sys
import os
#sys.path.append(os.path.join(sys.path[0],"..","..","kicad_mod")) # load kicad_mod path

# export PYTHONPATH="${PYTHONPATH}<path to kicad-footprint-generator directory>"
sys.path.append(os.path.join(sys.path[0], "..", "..", ".."))  # load parent path of KicadModTree
from math import sqrt
import argparse
import yaml
from helpers import *
from KicadModTree import *

sys.path.append(os.path.join(sys.path[0], "..", "..", "tools"))  # load parent path of tools
from footprint_text_fields import addTextFields

series = "Mini-Fit_Sr"
series_long = 'Mini-Fit Sr. Power Connectors'
manufacturer = 'Molex'
orientation = 'V'
number_of_rows = 2
datasheet = 'http://www.molex.com/pdm_docs/sd/439151404_sd.pdf'

#pins_per_row per row
pins_per_row_range = [3, 4, 5, 6, 7]

#Molex part number
#n = number of circuits per row
part_code = "43915-xx{n:02}"

pitch = 10
drill = 2.8

offset_second_pad = 4.4
pitch_row = offset_second_pad + 8.06

pad_to_pad_clearance = 3
max_annular_ring = 1
min_annular_ring = 0.15

#locating pins
x_loc = 8.43
r_loc = 3.0



pad_size = [offset_second_pad + 0.1, 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

version_params = {
    'with_thermals':{
        'description': ', With thermal vias in pads',
        'fp_name_suffix': '_ThermalVias',
        'thermals': True
    },
    'only_pads':{
        'description': '',
        'fp_name_suffix': '',
        'thermals': False
    }
}

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','${KICAD6_3DMODEL_DIR}/')

    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 version in version_params:
        for pins_per_row in pins_per_row_range:
            generate_one_footprint(pins_per_row, version_params[version], configuration)

#!/usr/bin/env python3 kicad-footprint-generator is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.  kicad-footprint-generator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.  You should have received a copy of the GNU General Public License along with kicad-footprint-generator. If not, see < http://www.gnu.org/licenses/ >. #sys.path.append(os.path.join(sys.path[0],"..","..","kicad_mod")) # load kicad_mod path # export PYTHONPATH="${PYTHONPATH}<path to kicad-footprint-generator directory>" # load parent path of KicadModTree # load parent path of tools #pins_per_row per row #Molex part number #n = number of circuits per row #locating pins # handle arguments #calculate fp dimensions #ref: http://www.molex.com/pdm_docs/sd/439151404_sd.pdf #A = distance between mounting holes #B = distance between end pin centers #E = length of part #connector width #corner positions #generate the pads #thermal vias #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'])) # locating pins #mark pin-1 (bottom layer) #draw connector outline (basic) #connector outline on F.SilkScreen # kicad_mod.append(PolygoneLine(polygone=corner, #     width=configuration['silk_line_width'], layer='F.SilkS')) #silk-screen between each pad #draw the tabs at each end #inner-tab #pin-1 marker ########################### CrtYd ################################# ######################### Text Fields ############################### ##################### Output and 3d model ############################ #returns false if path does not yet exist!! (Does not check path validity)