master 76fedd51e868 cached
414 files
3.8 MB
1.0M tokens
1014 symbols
1 requests
Download .txt
Showing preview only (4,031K chars total). Download the full file or copy to clipboard to get everything.
Repository: pointhi/kicad-footprint-generator
Branch: master
Commit: 76fedd51e868
Files: 414
Total size: 3.8 MB

Directory structure:
gitextract_dm0b98jf/

├── .codeclimate.yml
├── .gitignore
├── .travis.yml
├── AUTHORS.md
├── KicadModTree/
│   ├── FileHandler.py
│   ├── KicadFileHandler.py
│   ├── ModArgparser.py
│   ├── Point.py
│   ├── PolygonPoints.py
│   ├── Vector.py
│   ├── __init__.py
│   ├── examples/
│   │   ├── __init__.py
│   │   ├── argparse_example.py
│   │   ├── padArrayWithOutline.py
│   │   ├── params.csv
│   │   ├── params.yml
│   │   ├── polygon.py
│   │   └── simpleFootprint.py
│   ├── nodes/
│   │   ├── Footprint.py
│   │   ├── Node.py
│   │   ├── __init__.py
│   │   ├── base/
│   │   │   ├── Arc.py
│   │   │   ├── Circle.py
│   │   │   ├── Line.py
│   │   │   ├── Model.py
│   │   │   ├── Pad.py
│   │   │   ├── Polygon.py
│   │   │   ├── Text.py
│   │   │   └── __init__.py
│   │   └── specialized/
│   │       ├── ChamferedPad.py
│   │       ├── ChamferedPadGrid.py
│   │       ├── ExposedPad.py
│   │       ├── FilledRect.py
│   │       ├── PadArray.py
│   │       ├── PolygoneLine.py
│   │       ├── RectFill.py
│   │       ├── RectLine.py
│   │       ├── RingPad.py
│   │       ├── Rotation.py
│   │       ├── Translation.py
│   │       └── __init__.py
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── datatypes/
│   │   │   ├── __init__.py
│   │   │   ├── test_Vector2D.py
│   │   │   └── test_Vector3D.py
│   │   ├── moduletests/
│   │   │   ├── __init__.py
│   │   │   ├── test_arc.py
│   │   │   ├── test_exposed_pad.py
│   │   │   ├── test_kicad5_padshapes.py
│   │   │   ├── test_rotation.py
│   │   │   └── test_simple_footprints.py
│   │   ├── nodes/
│   │   │   ├── __init__.py
│   │   │   └── test_Node.py
│   │   └── test.py
│   └── util/
│       ├── __init__.py
│       ├── geometric_util.py
│       ├── kicad_util.py
│       └── paramUtil.py
├── LICENSE
├── README.md
├── docs/
│   ├── KicadModTree.nodes.base.rst
│   ├── KicadModTree.nodes.rst
│   ├── KicadModTree.nodes.specialized.rst
│   ├── KicadModTree.rst
│   ├── KicadModTree.util.rst
│   ├── Makefile
│   ├── conf.py
│   └── index.rst
├── manage.sh
├── requirements-dev.txt
├── requirements.txt
├── scripts/
│   ├── Battery/
│   │   ├── BatteryHolder.py
│   │   ├── BatteryHolder.yml
│   │   └── README.txt
│   ├── Buttons_Switches/
│   │   ├── make_DIPSwitches.py
│   │   ├── rotary_coded_switch.py
│   │   └── rotary_coded_switch.yml
│   ├── Buzzers_Beepers/
│   │   ├── buzzer_round_tht.py
│   │   └── buzzer_round_tht_star_mictronics.csv
│   ├── Capacitors_SMD/
│   │   ├── CP_Elec_round.py
│   │   ├── CP_Elec_round.yaml
│   │   ├── C_Elec_round.py
│   │   ├── C_Elec_round.yaml
│   │   ├── C_Trimmer_config.yaml
│   │   ├── C_Trimmer_factory.py
│   │   ├── C_Trimmer_make.py
│   │   ├── bump.py
│   │   ├── chamfers.py
│   │   ├── corners.py
│   │   ├── ipc7351B_capae_crystal.yaml
│   │   └── tantal and normal smd generator found under SMD_chip_package_rlc-etc
│   ├── Capacitors_THT/
│   │   └── make_Capacitors_THT.py
│   ├── Chokes_THT/
│   │   └── make_Chokes_THT.py
│   ├── Connector/
│   │   ├── Connector_Audio/
│   │   │   └── Jack_3.5mm_Switronic_ST-005-G_horizontal.py
│   │   ├── Connector_Harwin/
│   │   │   ├── conn_harwin_m20-781xx45_smd_top_dual_row.py
│   │   │   └── m20-89xx.py
│   │   ├── Connector_Hirose/
│   │   │   ├── 00-SMD footprint generators can be found in Connector_SMD_single_row_plus_mounting_pad.md
│   │   │   ├── conn_ffc_hirose_fh12_smd_side.py
│   │   │   ├── conn_hirose_df11_tht_top.py
│   │   │   ├── conn_hirose_df12c_ds_smd_top.py
│   │   │   ├── conn_hirose_df12e_dp_smd_top.py
│   │   │   ├── conn_hirose_df13_tht_side.py
│   │   │   ├── conn_hirose_df13_tht_top.py
│   │   │   ├── conn_hirose_df13c_smd_top.py
│   │   │   ├── conn_hirose_df63_tht_top.py
│   │   │   ├── helpers.py
│   │   │   └── not_in_official_lib/
│   │   │       ├── df33_straight_pth.py
│   │   │       └── df63_angled.py
│   │   ├── Connector_IEC_DIN/
│   │   │   └── generate_din41612.py
│   │   ├── Connector_JAE/
│   │   │   ├── conn_ffc_jae_ff08.py
│   │   │   ├── conn_jae_LY20_tht_side.py
│   │   │   ├── conn_jae_LY20_tht_top.py
│   │   │   └── helpers.py
│   │   ├── Connector_JST/
│   │   │   ├── 00-SMD footprint generators can be found in Connector_SMD_single_row_plus_mounting_pad.md
│   │   │   ├── JST-PH-SMT-SIDE_ENTRY.fcstd
│   │   │   ├── JST-PH-SMT-TOP_ENTRY.fcstd
│   │   │   ├── JST_ZE_top_entry_pad_size.fcstd
│   │   │   ├── conn_jst_J2100_tht_side.py
│   │   │   ├── conn_jst_J2100_tht_top.py
│   │   │   ├── conn_jst_JWPF_tht_top.py
│   │   │   ├── conn_jst_NV_tht_top.py
│   │   │   ├── conn_jst_PHD_horizontal.py
│   │   │   ├── conn_jst_PHD_vertical.py
│   │   │   ├── conn_jst_PUD_tht_side.py
│   │   │   ├── conn_jst_PUD_tht_top.py
│   │   │   ├── conn_jst_VH_tht_side-stabilizer.py
│   │   │   ├── conn_jst_VH_tht_side.py
│   │   │   ├── conn_jst_VH_tht_top-shrouded.py
│   │   │   ├── conn_jst_eh_tht_side.py
│   │   │   ├── conn_jst_eh_tht_top.py
│   │   │   ├── conn_jst_ph_tht_side.py
│   │   │   ├── conn_jst_ph_tht_top.py
│   │   │   ├── conn_jst_vh_tht_top.py
│   │   │   ├── conn_jst_xh_tht_side.py
│   │   │   ├── conn_jst_xh_tht_top.py
│   │   │   ├── conn_jst_ze_tht_side.py
│   │   │   ├── conn_jst_ze_tht_top.py
│   │   │   └── helpers.py
│   │   ├── Connector_Molex/
│   │   │   ├── 00-SMD footprint generators can be found in Connector_SMD_single_row_plus_mounting_pad.md
│   │   │   ├── conn_ffc_molex_200528.py
│   │   │   ├── conn_ffc_molex_502250.py
│   │   │   ├── conn_molex_SPOX_tht_side.py
│   │   │   ├── conn_molex_SPOX_tht_top.py
│   │   │   ├── conn_molex_kk_254_tht_top.py
│   │   │   ├── conn_molex_kk_396_tht_top.py
│   │   │   ├── conn_molex_mega-fit_tht_side_dual-row.py
│   │   │   ├── conn_molex_mega-fit_tht_top_dual_row.py
│   │   │   ├── conn_molex_micro-clasp_tht_side.py
│   │   │   ├── conn_molex_micro-clasp_tht_top.py
│   │   │   ├── conn_molex_micro-fit-3.0_smd_side_dual_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_smd_top_dual_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_tht_side_dual_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_tht_side_single_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_tht_top_dual_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_tht_top_single_row.py
│   │   │   ├── conn_molex_micro-latch_tht_side.py
│   │   │   ├── conn_molex_micro-latch_tht_top.py
│   │   │   ├── conn_molex_mini-fit-sr_tht_side.py
│   │   │   ├── conn_molex_mini-fit-sr_tht_top.py
│   │   │   ├── conn_molex_mini-fit-sr_tht_top_dual.py
│   │   │   ├── conn_molex_mini-fit_Jr_tht_side_dual-row.py
│   │   │   ├── conn_molex_mini-fit_Jr_tht_top_dual-row.py
│   │   │   ├── conn_molex_nano-fit_tht_side.py
│   │   │   ├── conn_molex_nano-fit_tht_top.py
│   │   │   ├── conn_molex_picoblade_tht_side.py
│   │   │   ├── conn_molex_picoblade_tht_top.py
│   │   │   ├── conn_molex_picoflex_smd_top.py
│   │   │   ├── conn_molex_picoflex_tht_top.py
│   │   │   ├── conn_molex_sabre_tht_side.py
│   │   │   ├── conn_molex_sabre_tht_top.py
│   │   │   ├── conn_molex_slimstack-501920.py
│   │   │   ├── conn_molex_slimstack-502426.py
│   │   │   ├── conn_molex_slimstack-502430.py
│   │   │   ├── conn_molex_slimstack-52991.py
│   │   │   ├── conn_molex_slimstack-53748.py
│   │   │   ├── conn_molex_slimstack-54722.py
│   │   │   ├── conn_molex_slimstack-55560.py
│   │   │   ├── conn_molex_stackable-linear_tht_top.py
│   │   │   └── helpers.py
│   │   ├── Connector_PCBEdge/
│   │   │   └── molex_EDGELOCK.py
│   │   ├── Connector_PhoenixContact/
│   │   │   ├── config_phoenix_KLCv1.0.yaml
│   │   │   ├── config_phoenix_KLCv1.1.yaml
│   │   │   ├── config_phoenix_KLCv2.0.yaml
│   │   │   ├── config_phoenix_KLCv3.0.yaml
│   │   │   ├── config_phoenix_TERA.yaml
│   │   │   ├── helpers.py
│   │   │   ├── mc.py
│   │   │   ├── mc_params.py
│   │   │   ├── mstb.py
│   │   │   └── mstb_params.py
│   │   ├── Connector_SMD_single_row_plus_mounting_pad/
│   │   │   ├── conn_hirose.yaml
│   │   │   ├── conn_jst.yaml
│   │   │   ├── conn_molex.yaml
│   │   │   ├── helpers.py
│   │   │   └── smd_single_row_plus_mounting_pad.py
│   │   ├── Connector_Samtec/
│   │   │   ├── conn_samtec_LSHM_smd_top.py
│   │   │   ├── conn_samtec_hle.py
│   │   │   ├── helpers.py
│   │   │   ├── mecf_connector.py
│   │   │   └── mecf_socket.py
│   │   ├── Connector_Stocko/
│   │   │   └── conn_Stocko_MKS_16xx.py
│   │   ├── Connector_TE-Connectivity/
│   │   │   ├── conn_ffc_te_84952-84953.py
│   │   │   ├── conn_fpc_te_1734839.py
│   │   │   ├── conn_te_826576.py
│   │   │   ├── conn_te_mate-n-lock_tht_side.py
│   │   │   ├── conn_te_mate-n-lock_tht_top.py
│   │   │   └── helpers.py
│   │   ├── Connector_Wago/
│   │   │   ├── conn_wago_734_horizontal.py
│   │   │   ├── conn_wago_734_vertical.py
│   │   │   └── helpers.py
│   │   ├── Connector_Wire/
│   │   │   ├── Research/
│   │   │   │   └── sources.md
│   │   │   ├── solder_wire_tht.py
│   │   │   └── wire_MC_Flexivolt.yaml
│   │   ├── Connector_Wuerth/
│   │   │   └── wuerth_6480xx11622.py
│   │   ├── conn_config_KLCv2.yaml
│   │   └── conn_config_KLCv3.yaml
│   ├── Connector_PinSocket/
│   │   ├── canvas.py
│   │   ├── cq_base_parameters.py
│   │   ├── main_generator.py
│   │   ├── parameters.py
│   │   ├── parameters.yaml
│   │   └── socket_strips.py
│   ├── Connectors_DSub/
│   │   └── make_dsubs.py
│   ├── Converter_DCDC/
│   │   ├── Converter_DCDC.py
│   │   ├── Converter_DCDC.yml
│   │   ├── XP_Power_SF_THT.py
│   │   └── conv_config_KLCv3.yaml
│   ├── Crystals_Resonators_SMD/
│   │   └── make_crystal_smd.py
│   ├── Crystals_Resonators_THT/
│   │   └── make_crystal.py
│   ├── Diodes_SMD/
│   │   └── generator found under SMD_chip_package_rlc-etc
│   ├── Diodes_THT/
│   │   └── make_Diodes_THT.py
│   ├── Fuse/
│   │   ├── ptc-fuse-tht.py
│   │   └── ptc-fuse-tht.yaml
│   ├── Inductor_SMD/
│   │   ├── Inductor_SMD.py
│   │   └── Inductor_SMD.yml
│   ├── Inductors/
│   │   ├── Choke_Schaffner_RNXXX.py
│   │   ├── Murata_DEM35xxC.py
│   │   ├── bourns-srn.py
│   │   ├── generator for normal packages found under SMD_chip_package_rlc-etc
│   │   ├── vishay_IHSM.py
│   │   ├── we-hci.py
│   │   ├── we-hcm.py
│   │   └── we-mapi.py
│   ├── LEDs_SMD/
│   │   ├── generator for normal packages  found under SMD_chip_package_rlc-etc
│   │   ├── plcc4.py
│   │   ├── plcc4.yml
│   │   └── smlvn6.py
│   ├── LEDs_THT/
│   │   └── make_LEDs_THT.py
│   ├── Mounting_Hardware/
│   │   ├── mounting_hole.py
│   │   ├── wuerth_smt_spacer.py
│   │   └── wuerth_smt_spacer.yaml
│   ├── Mounting_Holes/
│   │   └── mounting_hole_long.yaml
│   ├── Multicomp/
│   │   ├── connectors_multicomp_mc9a12.py
│   │   ├── connectors_multicomp_mc9a22.py
│   │   └── create_connectors_multicomp.sh
│   ├── Oscillators_SMD/
│   │   └── make_oscillators.py
│   ├── Packages/
│   │   ├── Package_BGA/
│   │   │   ├── bga.yaml
│   │   │   ├── bga_xilinx.yaml
│   │   │   ├── csp.yaml
│   │   │   ├── ipc_7351b_bga_land_patterns.yaml
│   │   │   ├── ipc_bga_generator.py
│   │   │   └── test_ipc.yaml
│   │   ├── Package_DIP/
│   │   │   └── make_DIP_footprints.py
│   │   ├── Package_Gullwing__QFP_SOIC_SO/
│   │   │   ├── Readme.md
│   │   │   ├── ipc_gullwing_generator.py
│   │   │   └── size_definitions/
│   │   │       ├── eqfp.yaml
│   │   │       ├── hsoic.yaml
│   │   │       ├── hsop.yaml
│   │   │       ├── htsop.yaml
│   │   │       ├── htssop.yaml
│   │   │       ├── hvssop.yaml
│   │   │       ├── infineon.yaml
│   │   │       ├── lqfp.yaml
│   │   │       ├── mqfp.yaml
│   │   │       ├── msop.yaml
│   │   │       ├── pqfp.yaml
│   │   │       ├── sc-74.yaml
│   │   │       ├── so.yaml
│   │   │       ├── soic.yaml
│   │   │       ├── soj.yaml
│   │   │       ├── sop.yaml
│   │   │       ├── sot.yaml
│   │   │       ├── sso.yaml
│   │   │       ├── ssop.yaml
│   │   │       ├── test_hidden_deleted_pins.yaml
│   │   │       ├── test_so.yaml
│   │   │       ├── tqfp.yaml
│   │   │       ├── tsop-i.yaml
│   │   │       ├── tsop-ii.yaml
│   │   │       ├── tsot.yaml
│   │   │       ├── tssop.yaml
│   │   │       ├── vqfp.yaml
│   │   │       └── vssop.yaml
│   │   ├── Package_NoLead__DFN_QFN_LGA_SON/
│   │   │   ├── Readme.md
│   │   │   ├── ipc_noLead_generator.py
│   │   │   ├── qfn.py
│   │   │   ├── qfn.yml
│   │   │   └── size_definitions/
│   │   │       ├── MicroSiP.yaml
│   │   │       ├── csp.yaml
│   │   │       ├── dfn.yaml
│   │   │       ├── hvson8.yaml
│   │   │       ├── lfcsp.yaml
│   │   │       ├── lga.yaml
│   │   │       ├── oscillator.yaml
│   │   │       ├── qfn/
│   │   │       │   ├── hvqfn.yaml
│   │   │       │   ├── qfn-1x.yaml
│   │   │       │   ├── qfn-20.yaml
│   │   │       │   ├── qfn-24.yaml
│   │   │       │   ├── qfn-28.yaml
│   │   │       │   ├── qfn-3x.yaml
│   │   │       │   ├── qfn-4x.yaml
│   │   │       │   ├── qfn-5x.yaml
│   │   │       │   ├── qfn-64_9x9.yaml
│   │   │       │   ├── qfn-6x.yaml
│   │   │       │   ├── qfn-7x.yaml
│   │   │       │   ├── qfn-mini-circuits.yaml
│   │   │       │   ├── qfn-onsemi-vct.yml
│   │   │       │   ├── qfn-other-pincounts.yaml
│   │   │       │   ├── qfn_texas.yaml
│   │   │       │   ├── special_qfn.yaml
│   │   │       │   ├── tqfn.yaml
│   │   │       │   ├── ufqfpn.yaml
│   │   │       │   ├── uqfn.yaml
│   │   │       │   ├── vqfn.yaml
│   │   │       │   └── wqfn.yaml
│   │   │       ├── vson.yaml
│   │   │       ├── wdfn-8.yml
│   │   │       └── wson.yaml
│   │   ├── Package_PLCC/
│   │   │   ├── ipc_plcc_jLead_generator.py
│   │   │   └── plcc_jLead_definitions.yaml
│   │   ├── TO_SOT_Packages_SMD/
│   │   │   ├── DPAK.py
│   │   │   ├── DPAK_README.md
│   │   │   ├── DPAK_config.yaml
│   │   │   └── make_DPAK.py
│   │   ├── TO_SOT_THT/
│   │   │   ├── TO_SOT_THT_generate.py
│   │   │   ├── TO_THT_packages.py
│   │   │   └── tools.py
│   │   ├── ipc_definitions.yaml
│   │   ├── package_config_KLCv3.yaml
│   │   └── utils/
│   │       └── ep_handling_utils.py
│   ├── PadGenerator/
│   │   └── RingPad.py
│   ├── Potentiometers/
│   │   ├── make_Potentiometer_SMD.py
│   │   ├── make_Potentiometer_THT.py
│   │   ├── slide_Potentiometer.py
│   │   └── slide_Potentiometer.yaml
│   ├── Recom_DCDC/
│   │   └── Recom_SIP.py
│   ├── ResistorArrays_SIP_THT/
│   │   └── make_Resistor_array_SIP.py
│   ├── Resistor_THT/
│   │   └── make_Resistors_THT.py
│   ├── Resistors_SMD/
│   │   ├── README.md
│   │   ├── generator found under SMD_chip_package_rlc-etc
│   │   └── smd_chip_resistors_smd.csv
│   ├── SMD_chip_package_rlc-etc/
│   │   ├── SMD_chip_devices.yaml
│   │   ├── SMD_chip_package_rlc-etc.py
│   │   ├── config_KLCv3.0.yaml
│   │   ├── ipc7351B_smd_two_terminal_chip.yaml
│   │   ├── ipc_smd_two_terminal_chip.yaml
│   │   └── size_definitions/
│   │       ├── size_capacitor_chip_devices.yaml
│   │       ├── size_default_chip_devices.yaml
│   │       ├── size_default_chip_devices_smaller_0402.yaml
│   │       ├── size_default_chip_devices_smaller_0603.yaml
│   │       ├── size_diode.yaml
│   │       ├── size_fuse.yaml
│   │       ├── size_inductor.yaml
│   │       ├── size_resistor.yaml
│   │       ├── size_tantal.yaml
│   │       └── size_wide_body_chip_resistor.yaml
│   ├── Shielding/
│   │   ├── laird_technologies_smd_shielding.kicad_mod.yaml
│   │   ├── smd_shielding.py
│   │   ├── wuerth_electronic_smd_shielding.py
│   │   ├── wuerth_electronic_tht_shielding.py
│   │   └── wuerth_smd_shielding.kicad_mod.yaml
│   ├── Socket/
│   │   ├── 3M_Textool.py
│   │   └── 3M_Textool.yaml
│   ├── TerminalBlock_4Ucon/
│   │   └── make_TerminalBlock_4Ucon.py
│   ├── TerminalBlock_Altech/
│   │   ├── Altech.py
│   │   └── Altech.yml
│   ├── TerminalBlock_MetzConnect/
│   │   ├── make_SingleTerminalBlock_MetzConnect.py
│   │   └── make_TerminalBlock_MetzConnect.py
│   ├── TerminalBlock_Philmore/
│   │   └── make_TerminalBlock_Philmore.py
│   ├── TerminalBlock_Phoenix/
│   │   └── make_TerminalBlock_Phoenix.py
│   ├── TerminalBlock_RND/
│   │   └── make_TerminalBlock_RND.py
│   ├── TerminalBlock_TE-Connectivity/
│   │   └── make_TerminalBlock_TE-Connectivity.py
│   ├── TerminalBlock_WAGO/
│   │   └── make_TerminalBlock_WAGO.py
│   ├── Vigortronix/
│   │   └── vigotronix.py
│   ├── example_kicadmodtree_script.py
│   ├── general/
│   │   ├── StandardBox.py
│   │   ├── new more powerfull generator found under SMD_chip_package_rlc-etc
│   │   └── smd_chip.py
│   ├── pin-headers_socket-strips/
│   │   ├── make_idc_headers.py
│   │   ├── make_pin_headers.py
│   │   └── make_socket_strips.py
│   └── tools/
│       ├── dict_tools.py
│       ├── drawing_tools.py
│       ├── footprint_global_properties.py
│       ├── footprint_keepout_area.py
│       ├── footprint_scripts_DIP.py
│       ├── footprint_scripts_LEDs.py
│       ├── footprint_scripts_crystals.py
│       ├── footprint_scripts_dsub.py
│       ├── footprint_scripts_pin_headers.py
│       ├── footprint_scripts_potentiometers.py
│       ├── footprint_scripts_resistorlike.py
│       ├── footprint_scripts_sip.py
│       ├── footprint_scripts_terminal_blocks.py
│       ├── footprint_text_fields.py
│       ├── global_config_files/
│       │   ├── config_KLCv1.0.yaml
│       │   ├── config_KLCv2.0.yaml
│       │   ├── config_KLCv3.0.yaml
│       │   └── config_Tera.yaml
│       ├── ipc_pad_size_calculators.py
│       ├── pad_number_generators.py
│       └── quad_dual_pad_border.py
├── setup.py
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .codeclimate.yml
================================================
engines:
  duplication:
    enabled: true
    config:
      languages:
      - python
  fixme:
    enabled: true
  radon:
    enabled: true
  pep8:
    enabled: true
  shellcheck:
    enabled: true
ratings:
  paths:
  - "**.py"
  - "**.sh"
exclude_paths:
- doc/**/*
- scripts/**/*
- "**/tests/"


================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Sphinx documentation
docs/_build/

# pyenv
.python-version

# kicad specific files
*.kicad_mod
*.pretty/


================================================
FILE: .travis.yml
================================================
sudo: false
cache:
  - pip
  - directories:
    - $HOME/.cache/pip
language: python
python:
  - "2.7"
  - "3.4"
  - "3.5"
  - "3.6"
  - "3.7"
install:
  - ./manage.sh update_dev_packages
script:
  - ./manage.sh pep8_check
  - ./manage.sh unit_tests
  - ./manage.sh py_test_coverage


================================================
FILE: AUTHORS.md
================================================
**Maintainer:**

* Thomas Pointhuber <thomas.pointhuber@gmx.at> @pointhi
* Rene Pöschl, @poeschlr
* @evanshultz

**Contributors:**

People who have submitted patches, reported bugs, consulted features or generally made KicadModTree better

* Oliver, @SchrodingersGat
* Jan W. Krieger, @jkriege2
* Frank, @Frankkkkk
* @Hackscribble
* @stoth
* Patrick Pelletier, @ppelleti
* @DASFrank
* Dominik Baack, @matyro
* Jordi Pakey-Rodriguez, @0xdec
* George, @grob6000
* Tobias Müller, @twam
* Terje Io, @terjeio
* Frank Severinsen, @Shackmeister
* @robertlong13
* Julien Cassette, @jcassette
* Trevor Vannoy,  @tvannoy
* Kari Hautio, @kh4
* Stefan, @Misca1234
* Antonio Vazquez, @antoniovazquezblanco
* Hendrik v. Raven, @lorem-ipsum
* Asuki Kono, @asukiaaa
* Xathar, @jneiva08
* @matthuszagh
* @ferdymercury
* @jhalmen
* @herostrat
* @fauxpark
* @matthijskooijman
* Clara Hobbs, @Ratfink
* @MRQ
* Stefan Krüger, @s-light
* John Whitmore, @johnfwhitmore
* Daniel Mack, @zonque
* @dominformant
* @tpambor
* @nivekg
* Joel, @myfreescalewebpage
* JonRB, @eeyrjmr
* Alexander Ransmann, @cronJ
* Christian Schlüter, @chschlue
* Chase Patterson, @chapatt
* Rolf Schäuble, @rschaeuble
* @penoud
* @ki5libs
* @fvollmer
* @cp-aquila
* Anders Wallin, @aewallin
* Jonas Schievink, @jonas-schievink
* Diego Herranz, @diegoherranz
* Alexandre Oliveira, @RockyTV
* Konstantin Oblaukhov, @ObKo
* Jesper, @JeppeSRC
* Jacob E. F. Overgaard @JacobEFO
* Ed Peguillan III, @yankee14
* Thomas Schmid, @rckTom
* @mitch354
* Jan Krueger, @einball
* @dogtopus
* Darrell Harmon, @dlharmon
* David Imhoff, @dimhoff
* marble, @cyber-murmel
* @chemicstry
* @awygle
* @TiZed
* Sean Leavey, @SeanDS
* @Schlumpf
* Daniel Giesbrecht, @DanSGiesbrecht
* Caleb Reister, @calebreister
* Greg Cormier, @gcormier
* Ilya Elenskiy, @EvilMav
* Mathias Walter, @tolot27
* Michael Munch, @Munken
* @waschhauser


================================================
FILE: KicadModTree/FileHandler.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016-2018 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

import sys
import io


class FileHandler(object):
    r"""some basic methods to write footprints, and which is the base class of footprint writer implementations

    :param kicad_mod:
        Main object representing the footprint
    :type kicad_mod: ``KicadModTree.Footprint``

    :Example:

    >>> from KicadModTree import *
    >>> kicad_mod = Footprint("example_footprint")
    >>> file_handler = KicadFileHandler(kicad_mod)  # KicadFileHandler is a implementation of FileHandler
    >>> file_handler.writeFile('example_footprint.kicad_mod')
    """

    def __init__(self, kicad_mod):
        self.kicad_mod = kicad_mod

    def writeFile(self, filename, **kwargs):
        r"""Write the output of FileHandler.serialize to a file

        :param filename:
            path of the output file
        :type filename: ``str``

        :Example:

        >>> from KicadModTree import *
        >>> kicad_mod = Footprint("example_footprint")
        >>> file_handler = KicadFileHandler(kicad_mod)  # KicadFileHandler is a implementation of FileHandler
        >>> file_handler.writeFile('example_footprint.kicad_mod')
        """

        with io.open(filename, "w", newline='\n') as f:
            output = self.serialize(**kwargs)

            # convert to unicode if running python2
            if sys.version_info[0] == 2 and type(output) != unicode:
                output = unicode(output, "utf-8")

            f.write(output)

            f.close()

    def serialize(self, **kwargs):
        r"""Get a valid string representation of the footprint in the specified format

        :Example:

        >>> from KicadModTree import *
        >>> kicad_mod = Footprint("example_footprint")
        >>> file_handler = KicadFileHandler(kicad_mod)  # KicadFileHandler is a implementation of FileHandler
        >>> print(file_handler.serialize())
        """

        raise NotImplementedError("serialize has to be implemented by child class")


================================================
FILE: KicadModTree/KicadFileHandler.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016-2018 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.FileHandler import FileHandler
from KicadModTree.util.kicad_util import *
from KicadModTree.nodes.base.Pad import Pad  # TODO: why .KicadModTree is not enough?
from KicadModTree.nodes.base.Arc import Arc
from KicadModTree.nodes.base.Circle import Circle
from KicadModTree.nodes.base.Line import Line
from KicadModTree.nodes.base.Polygon import Polygon


DEFAULT_LAYER_WIDTH = {'F.SilkS': 0.12,
                       'B.SilkS': 0.12,
                       'F.Fab': 0.10,
                       'B.Fab': 0.10,
                       'F.CrtYd': 0.05,
                       'B.CrtYd': 0.05}

DEFAULT_WIDTH_POLYGON_PAD = 0

DEFAULT_WIDTH = 0.15


def _get_layer_width(layer, width=None):
    if width is not None:
        return width
    else:
        return DEFAULT_LAYER_WIDTH.get(layer, DEFAULT_WIDTH)


class KicadFileHandler(FileHandler):
    r"""Implementation of the FileHandler for .kicad_mod files

    :param kicad_mod:
        Main object representing the footprint
    :type kicad_mod: ``KicadModTree.Footprint``

    :Example:

    >>> from KicadModTree import *
    >>> kicad_mod = Footprint("example_footprint")
    >>> file_handler = KicadFileHandler(kicad_mod)
    >>> file_handler.writeFile('example_footprint.kicad_mod')
    """

    def __init__(self, kicad_mod):
        FileHandler.__init__(self, kicad_mod)

    def serialize(self, **kwargs):
        r"""Get a valid string representation of the footprint in the .kicad_mod format

        :Example:

        >>> from KicadModTree import *
        >>> kicad_mod = Footprint("example_footprint")
        >>> file_handler = KicadFileHandler(kicad_mod)
        >>> print(file_handler.serialize())
        """

        sexpr = ['module', self.kicad_mod.name,
                 ['layer', 'F.Cu'],
                 ['tedit', formatTimestamp(kwargs.get('timestamp'))],
                 SexprSerializer.NEW_LINE
                ]  # NOQA

        if self.kicad_mod.description:
            sexpr.append(['descr', self.kicad_mod.description])
            sexpr.append(SexprSerializer.NEW_LINE)

        if self.kicad_mod.tags:
            sexpr.append(['tags', self.kicad_mod.tags])
            sexpr.append(SexprSerializer.NEW_LINE)

        if self.kicad_mod.attribute:
            sexpr.append(['attr', self.kicad_mod.attribute])
            sexpr.append(SexprSerializer.NEW_LINE)

        if self.kicad_mod.maskMargin:
            sexpr.append(['solder_mask_margin', self.kicad_mod.maskMargin])
            sexpr.append(SexprSerializer.NEW_LINE)

        if self.kicad_mod.pasteMargin:
            sexpr.append(['solder_paste_margin', self.kicad_mod.pasteMargin])
            sexpr.append(SexprSerializer.NEW_LINE)

        if self.kicad_mod.pasteMarginRatio:
            sexpr.append(['solder_paste_ratio', self.kicad_mod.pasteMarginRatio])
            sexpr.append(SexprSerializer.NEW_LINE)

        sexpr.extend(self._serializeTree())

        return str(SexprSerializer(sexpr))

    def _serializeTree(self):
        nodes = self.kicad_mod.serialize()

        grouped_nodes = {}

        for single_node in nodes:
            node_type = single_node.__class__.__name__

            current_nodes = grouped_nodes.get(node_type, [])
            current_nodes.append(single_node)

            grouped_nodes[node_type] = current_nodes

        sexpr = []

        # serialize initial text nodes
        if 'Text' in grouped_nodes:
            reference_nodes = list(filter(lambda node: node.type == 'reference', grouped_nodes['Text']))
            for node in reference_nodes:
                sexpr.append(self._serialize_Text(node))
                sexpr.append(SexprSerializer.NEW_LINE)
                grouped_nodes['Text'].remove(node)

            value_nodes = list(filter(lambda node: node.type == 'value', grouped_nodes['Text']))
            for node in value_nodes:
                sexpr.append(self._serialize_Text(node))
                sexpr.append(SexprSerializer.NEW_LINE)
                grouped_nodes['Text'].remove(node)

        for key, value in sorted(grouped_nodes.items()):
            # check if key is a base node, except Model
            if key not in {'Arc', 'Circle', 'Line', 'Pad', 'Polygon', 'Text'}:
                continue

            # render base nodes
            for node in value:
                sexpr.append(self._callSerialize(node))
                sexpr.append(SexprSerializer.NEW_LINE)

        # serialize 3D Models at the end
        if grouped_nodes.get('Model'):
            for node in grouped_nodes.get('Model'):
                sexpr.append(self._serialize_Model(node))
                sexpr.append(SexprSerializer.NEW_LINE)

        return sexpr

    def _callSerialize(self, node):
        '''
        call the corresponding method to serialize the node
        '''
        method_type = node.__class__.__name__
        method_name = "_serialize_{0}".format(method_type)
        if hasattr(self, method_name):
            return getattr(self, method_name)(node)
        else:
            exception_string = "{name} (node) not found, cannot serialized the node of type {type}"
            raise NotImplementedError(exception_string.format(name=method_name, type=method_type))

    def _serialize_ArcPoints(self, node):
        # in KiCAD, some file attributes of Arc are named not in the way of their real meaning
        center_pos = node.getRealPosition(node.center_pos)
        end_pos = node.getRealPosition(node.start_pos)

        return [
                ['start', center_pos.x, center_pos.y],
                ['end', end_pos.x, end_pos.y],
                ['angle', node.angle]
               ]

    def _serialize_Arc(self, node):
        sexpr = ['fp_arc']
        sexpr += self._serialize_ArcPoints(node)
        sexpr += [
                  ['layer', node.layer],
                  ['width', _get_layer_width(node.layer, node.width)]
                 ]  # NOQA

        return sexpr

    def _serialize_CirclePoints(self, node):
        center_pos = node.getRealPosition(node.center_pos)
        end_pos = node.getRealPosition(node.center_pos + (node.radius, 0))

        return [
                ['center', center_pos.x, center_pos.y],
                ['end', end_pos.x, end_pos.y]
               ]

    def _serialize_Circle(self, node):
        sexpr = ['fp_circle']
        sexpr += self._serialize_CirclePoints(node)
        sexpr += [
                  ['layer', node.layer],
                  ['width', _get_layer_width(node.layer, node.width)]
                 ]  # NOQA

        return sexpr

    def _serialize_LinePoints(self, node):
        start_pos = node.getRealPosition(node.start_pos)
        end_pos = node.getRealPosition(node.end_pos)
        return [
                ['start', start_pos.x, start_pos.y],
                ['end', end_pos.x, end_pos.y]
               ]

    def _serialize_Line(self, node):
        start_pos = node.getRealPosition(node.start_pos)
        end_pos = node.getRealPosition(node.end_pos)

        sexpr = ['fp_line']
        sexpr += self._serialize_LinePoints(node)
        sexpr += [
                ['layer', node.layer],
                 ['width', _get_layer_width(node.layer, node.width)]
                ]  # NOQA

        return sexpr

    def _serialize_Text(self, node):
        sexpr = ['fp_text', node.type, node.text]

        position, rotation = node.getRealPosition(node.at, node.rotation)
        if rotation:
            sexpr.append(['at', position.x, position.y, rotation])
        else:
            sexpr.append(['at', position.x, position.y])

        sexpr.append(['layer', node.layer])
        if node.hide:
            sexpr.append('hide')
        sexpr.append(SexprSerializer.NEW_LINE)

        effects = [
                'effects',
                ['font',
                    ['size', node.size.x, node.size.y],
                    ['thickness', node.thickness]]]

        if node.mirror:
            effects.append(['justify', 'mirror'])

        sexpr.append(effects)
        sexpr.append(SexprSerializer.NEW_LINE)

        return sexpr

    def _serialize_Model(self, node):
        sexpr = ['model', node.filename,
                 SexprSerializer.NEW_LINE,
                 ['at', ['xyz', node.at.x, node.at.y, node.at.z]],
                 SexprSerializer.NEW_LINE,
                 ['scale', ['xyz', node.scale.x, node.scale.y, node.scale.z]],
                 SexprSerializer.NEW_LINE,
                 ['rotate', ['xyz', node.rotate.x, node.rotate.y, node.rotate.z]],
                 SexprSerializer.NEW_LINE
                ]  # NOQA

        return sexpr

    def _serialize_CustomPadPrimitives(self, pad):
        all_primitives = []
        for p in pad.primitives:
            all_primitives.extend(p.serialize())

        grouped_nodes = {}

        for single_node in all_primitives:
            node_type = single_node.__class__.__name__

            current_nodes = grouped_nodes.get(node_type, [])
            current_nodes.append(single_node)

            grouped_nodes[node_type] = current_nodes

        sexpr_primitives = []

        for key, value in sorted(grouped_nodes.items()):
            # check if key is a base node, except Model
            if key not in {'Arc', 'Circle', 'Line', 'Pad', 'Polygon', 'Text'}:
                continue

            # render base nodes
            for p in value:
                if isinstance(p, Polygon):
                    sp = ['gr_poly',
                          self._serialize_PolygonPoints(p, newline_after_pts=True)
                         ]  # NOQA
                elif isinstance(p, Line):
                    sp = ['gr_line'] + self._serialize_LinePoints(p)
                elif isinstance(p, Circle):
                    sp = ['gr_circle'] + self._serialize_CirclePoints(p)
                elif isinstance(p, Arc):
                    sp = ['gr_arc'] + self._serialize_ArcPoints(p)
                else:
                    raise TypeError('Unsuported type of primitive for custom pad.')
                sp.append(['width', DEFAULT_WIDTH_POLYGON_PAD if p.width is None else p.width])
                sexpr_primitives.append(sp)
                sexpr_primitives.append(SexprSerializer.NEW_LINE)

        return sexpr_primitives

    def _serialize_Pad(self, node):
        sexpr = ['pad', node.number, node.type, node.shape]

        position, rotation = node.getRealPosition(node.at, node.rotation)
        if not rotation % 360 == 0:
            sexpr.append(['at', position.x, position.y, rotation])
        else:
            sexpr.append(['at', position.x, position.y])

        sexpr.append(['size', node.size.x, node.size.y])

        if node.type in [Pad.TYPE_THT, Pad.TYPE_NPTH]:
            if node.drill.x == node.drill.y:
                sexpr.append(['drill', node.drill.x])
            else:
                sexpr.append(['drill', 'oval', node.drill.x, node.drill.y])

        sexpr.append(['layers'] + node.layers)
        if node.shape == Pad.SHAPE_ROUNDRECT:
            sexpr.append(['roundrect_rratio', node.radius_ratio])

        if node.shape == Pad.SHAPE_CUSTOM:
            # gr_line, gr_arc, gr_circle or gr_poly
            sexpr.append(SexprSerializer.NEW_LINE)
            sexpr.append(['options',
                         ['clearance', node.shape_in_zone],
                         ['anchor', node.anchor_shape]
                        ])  # NOQA
            sexpr.append(SexprSerializer.NEW_LINE)
            sexpr_primitives = self._serialize_CustomPadPrimitives(node)
            sexpr.append(['primitives', SexprSerializer.NEW_LINE] + sexpr_primitives)

        if node.solder_paste_margin_ratio != 0 or node.solder_mask_margin != 0 or node.solder_paste_margin != 0:
            sexpr.append(SexprSerializer.NEW_LINE)
            if node.solder_mask_margin != 0:
                sexpr.append(['solder_mask_margin', node.solder_mask_margin])
            if node.solder_paste_margin_ratio != 0:
                sexpr.append(['solder_paste_margin_ratio', node.solder_paste_margin_ratio])
            if node.solder_paste_margin != 0:
                sexpr.append(['solder_paste_margin', node.solder_paste_margin])

        return sexpr

    def _serialize_PolygonPoints(self, node, newline_after_pts=False):
        node_points = ['pts']
        if newline_after_pts:
            node_points.append(SexprSerializer.NEW_LINE)
        points_appended = 0
        for n in node.nodes:
            if points_appended >= 4:
                points_appended = 0
                node_points.append(SexprSerializer.NEW_LINE)
            points_appended += 1

            n_pos = node.getRealPosition(n)
            node_points.append(['xy', n_pos.x, n_pos.y])

        return node_points

    def _serialize_Polygon(self, node):
        node_points = self._serialize_PolygonPoints(node)

        sexpr = ['fp_poly',
                 node_points,
                 ['layer', node.layer],
                 ['width', _get_layer_width(node.layer, node.width)]
                ]  # NOQA

        return sexpr


================================================
FILE: KicadModTree/ModArgparser.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2017 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

import sys
import argparse
import csv

try:
    import yaml
    YAML_AVAILABLE = True
except ImportError:
    YAML_AVAILABLE = False


class ParserException(Exception):
    def __itruediv__(self, *args, **kwargs):
        Exception.__init__(self, *args, **kwargs)


class ModArgparser(object):
    r"""A general data loading class, which allows us to specify parts using .yml or .csv files.

    Using this class allows us to seperate between the implementation of a footprint generator, and the data which
    represents a single footprint. To do so, we need to define which parameters are expected in those data-files.

    To improve the usablity of this class, it is able to do type checks of provided parameters, as well as defining
    default values and do a simple check if a parameter can be considered as required or optional.

    :param footprint_function:
        A function which is called for every footprint we want to generate
    :type footprint_function: ``function reference``

    :Example:

    >>> from KicadModTree import *
    >>> def footprint_gen(args):
    ...    print("create footprint: {}".format(args['name']))
    ...
    >>> parser = ModArgparser(footprint_gen)
    >>> parser.add_parameter("name", type=str, required=True)  # the root node of .yml files is parsed as name
    >>> parser.add_parameter("datasheet", type=str, required=False)
    >>> parser.add_parameter("courtyard", type=float, required=False, default=0.25)
    >>> parser.add_parameter("pincount", type=int, required=True)
    >>> parser.run()  # now run our script which handles the whole part of parsing the files
    """

    def __init__(self, footprint_function):
        self._footprint_function = footprint_function
        self._params = {}

    def add_parameter(self, name, **kwargs):
        r"""Add a parameter to the ModArgparser

        :param name:
            name of the argument
        :param \**kwargs:
            See below
        :type name: ``str``

        :Keyword Arguments:
            * *type* (``type``) --
              type of the argument
            * *required* (``bool``) --
              is the argument required or optional
            * *default* --
              a default value which is used when there is no value defined

        :Example:

        >>> from KicadModTree import *
        >>> def footprint_gen(args):
        ...    print("create footprint: {}".format(args['name']))
        ...
        >>> parser = ModArgparser(footprint_gen)
        >>> parser.add_parameter("name", type=str, required=True)  # the root node of .yml files is parsed as name
        >>> parser.add_parameter("datasheet", type=str, required=False)
        >>> parser.add_parameter("courtyard", type=float, required=False, default=0.25)
        """

        self._params[name] = kwargs

    def run(self):
        r"""Execute the ModArgparser and run all tasks defined via the commandline arguments of this script

        This method parses the commandline arguments to determine which actions to take. Beside of parsing .yml and .csv
        files, it also allows us to output example files.

        >>> from KicadModTree import *
        >>> def footprint_gen(args):
        ...    print("create footprint: {}".format(args['name']))
        ...
        >>> parser = ModArgparser(footprint_gen)
        >>> parser.add_parameter("name", type=str, required=True)  # the root node of .yml files is parsed as name
        >>> parser.run()  # now run our script which handles the whole part of parsing the files
        """

        parser = argparse.ArgumentParser(description='Parse footprint defintion file(s) and create matching footprints')
        parser.add_argument('files', metavar='file', type=str, nargs='*', help='.yml or .csv files which contains data')
        parser.add_argument('-v', '--verbose', help='show some additional information', action='store_true')  # TODO
        parser.add_argument('--print_yml', help='print example .yml file', action='store_true')
        parser.add_argument('--print_csv', help='print example .csv file', action='store_true')

        # TODO: allow writing into sub dir

        args = parser.parse_args()

        if args.print_yml:
            self._print_example_yml()
            return

        if args.print_csv:
            self._print_example_csv()
            return

        if len(args.files) == 0:
            parser.print_help()
            return

        for filepath in args.files:
            print("use file: {0}".format(filepath))
            if filepath.endswith('.yml') or filepath.endswith('.yaml'):
                self._parse_and_execute_yml(filepath)
            elif filepath.endswith('.csv'):
                self._parse_and_execute_csv(filepath)
            else:
                print("unexpected filetype: {0}".format(filepath))

    def _parse_and_execute_yml(self, filepath):
        if not YAML_AVAILABLE:
            print("pyyaml not available!")
            sys.exit(1)

        with open(filepath, 'r') as stream:
            try:
                parsed = yaml.safe_load(stream)  # parse file

                if parsed is None:
                    print("empty file!")
                    return

                for footprint in parsed:
                    kwargs = parsed.get(footprint)

                    # name is a reserved key
                    if 'name' in kwargs:
                        print("ERROR: name is already used for root name!")
                        continue
                    kwargs['name'] = footprint

                    self._execute_script(**kwargs)  # now we can execute the script

            except yaml.YAMLError as exc:
                print(exc)

    def _create_example_data_required(self, **kwargs):
        params = {}
        for k, v in self._params.items():
            if kwargs.get('include_name', False) is False and k == "name":
                continue
            if v.get('required', False):
                params[k] = self._create_example_datapoint(v.get('type', str), v.get('default'))

        return params

    def _create_example_data_full(self, **kwargs):
        params = {}
        for k, v in self._params.items():
            if kwargs.get('include_name', False) is False and k == "name":
                continue
            params[k] = self._create_example_datapoint(v.get('type', str), v.get('default'))

        return params

    def _create_example_datapoint(self, type, default):
        if default:
            return type(default)

        if type is bool:
            return False
        elif type is int:
            return 0
        elif type is float:
            return 0.0
        elif type is str:
            return "some string"
        else:
            return "??"

    def _print_example_yml(self):
        if not YAML_AVAILABLE:
            print("pyyaml not available!")
            sys.exit(1)

        data = {'footprint_required': self._create_example_data_required(),
                'footprint_full': self._create_example_data_full()}
        print(yaml.dump(data, default_flow_style=False))

    def _parse_and_execute_csv(self, filepath):
        with open(filepath, 'r') as stream:
            # dialect = csv.Sniffer().sniff(stream.read(1024))  # check which type of formating the csv file likel has
            # stream.seek(0)

            reader = csv.DictReader(stream, dialect=csv.excel)  # parse file

            for row in reader:
                # we wan't to remove spaces before and after the fields
                kwargs = {}
                for k, v in row.items():
                    kwargs[k.strip()] = v.strip()

                self._execute_script(**kwargs)  # now we can execute the script

    def _print_example_csv(self):
        writer = csv.DictWriter(sys.stdout, fieldnames=self._params.keys())

        writer.writeheader()
        writer.writerow(self._create_example_data_required(include_name=True))
        writer.writerow(self._create_example_data_full(include_name=True))

    def _execute_script(self, **kwargs):
        parsed_args = {}
        error = False

        for k, v in self._params.items():
            try:
                if kwargs.get(k) not in [None, '']:
                    parsed_args[k] = v.get('type', str)(kwargs[k])
                elif v.get('required', False):
                    raise ParserException("parameter expected: {}".format(k))
                else:
                    type = v.get('type', str)
                    if type is bool:
                        parsed_args[k] = type(v.get('default', False))
                    elif type is int:
                        parsed_args[k] = type(v.get('default', 0))
                    elif type is float:
                        parsed_args[k] = type(v.get('default', 0.0))
                    elif type is str:
                        parsed_args[k] = type(v.get('default', ''))
                    else:
                        parsed_args[k] = type(v.get('default'))
            except (ValueError, ParserException) as e:
                error = True
                print("ERROR: {}".format(e))

        print("  - generate {name}.kicad_mod".format(name=kwargs.get('name', '<anon>')))

        if error:
            return

        self._footprint_function(parsed_args)


================================================
FILE: KicadModTree/Point.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016-2018 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

import warnings

from KicadModTree.util.kicad_util import formatFloat
from KicadModTree.Vector import *
from math import sqrt


class Point2D(Vector2D):
    def __init__(self, coordinates=None, y=None):
        Vector2D.__init__(self, coordinates, y)
        warnings.warn(
            "Point2D is deprecated, use Vector2D instead",
            DeprecationWarning
        )


class Point3D(Vector3D):
    def __init__(self, coordinates=None, y=None, z=None):
        Vector3D.__init__(self, coordinates, y, z)
        warnings.warn(
            "Point3D is deprecated, use Vector3D instead",
            DeprecationWarning
        )


class Point(Vector3D):
    def __init__(self, coordinates=None, y=None, z=None):
        Vector3D.__init__(self, coordinates, y, z)
        warnings.warn(
            "Point is deprecated, use Vector2D or Vector3D instead",
            DeprecationWarning
        )


================================================
FILE: KicadModTree/PolygonPoints.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016-2018 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
# (C) 2018 by Rene Poeschl, github @poeschlr

import warnings

from KicadModTree.Vector import Vector2D
from KicadModTree.nodes.Node import Node


class PolygonPoints(object):
    r"""Representation of multiple points for creating polygons

    :Keyword Arguments:
        * *nodes* (``list(Point)``) --
          2D points describing the "polygon"
        * *polygone* (``list(Point)``) --
          alternative naming for the nodes parameter for backwards compatibility.
        * *x_mirror* (``[int, float](mirror offset)``) --
          mirror x direction around offset "point"
        * *y_mirror* (``[int, float](mirror offset)``) --
          mirror y direction around offset "point"

    :Example:

    >>> from KicadModTree import *
    >>> PolyPoint([(0, 0),(1, 0)])
    >>> PolyPoint([{'x': 0, 'y':0}, {'x': 1, 'y':0}])
    """
    def __init__(self, **kwargs):
        self._initMirror(**kwargs)
        self._initNodes(**kwargs)

    def _initNodes(self, **kwargs):
        self.nodes = []
        if 'nodes' in kwargs:
            for n in kwargs['nodes']:
                self.nodes.append(Vector2D(n))
            if 'polygone' in kwargs:
                raise KeyError('Use of "nodes" and "polygone" parameter at the same time is not supported.')
        elif 'polygone' in kwargs:
            warnings.warn(
                "polygone argument is deprecated, use nodes instead",
                DeprecationWarning
            )
            for n in kwargs['polygone']:
                self.nodes.append(Vector2D(n))
        else:
            raise KeyError('Either "nodes" or "polygone" parameter is required for creating a PolyPoint instance.')

        for point in self.nodes:
            if self.mirror[0] is not None:
                point.x = 2 * self.mirror[0] - point.x
            if self.mirror[1] is not None:
                point.y = 2 * self.mirror[1] - point.y

    def _initMirror(self, **kwargs):
        self.mirror = [None, None]
        if 'x_mirror' in kwargs and type(kwargs['x_mirror']) in [float, int]:
            self.mirror[0] = kwargs['x_mirror']
        if 'y_mirror' in kwargs and type(kwargs['y_mirror']) in [float, int]:
            self.mirror[1] = kwargs['y_mirror']

    def calculateBoundingBox(self):
        min = max = self.getRealPosition(self.nodes[0])

        for n in self.nodes:
            min.x = min([min.x, n.x])
            min.y = min([min.y, n.y])
            max.x = max([max.x, n.x])
            max.y = max([max.y, n.y])

        return Node.calculateBoundingBox({'min': min, 'max': max})

    def findNearestPoints(self, other):
        r""" Find the nearest points for two polygons

        Find the two points for both polygons that are nearest to each other.


        :param other: the polygon points of the other polygon
        :return: a tuble with the indexes of the two points
                 (pint in self, point in other)
        """

        min_distance = self[0].distance_to(other[0])
        pi = 0
        pj = 0
        for i in range(len(self)):
            for j in range(len(other)):
                d = self[i].distance_to(other[j])
                if d < min_distance:
                    pi = i
                    pj = j
                    min_distance = d

        return (pi, pj)

    def getPoints(self):
        r""" get the points contained within self

        :return: the array of points contained within this instance
        """
        return self.nodes

    def cut(self, other):
        r""" Cut other polygon points from self

        As kicad has no native support for cuting one polygon from the other,
        the cut is done by connecting the nearest points of the two polygons
        with two lines on top of each other.

        This function assumes that the other polygon is fully within this one.
        It also assumes that connecting the two nearest points creates a valid
        polygon. (There are no geometry checks)

        :param other: the polygon points that are cut from this polygon
        """

        warnings.warn(
            "No geometry checks are implement for cutting polygons.\n"
            "Make sure the second polygon is fully inside the main polygon\n"
            "Check resulting polygon carefully.",
            Warning
        )
        idx_self, idx_other = self.findNearestPoints(other)

        self.nodes.insert(idx_self+1, self[idx_self])
        for i in range(len(other)):
            self.nodes.insert(idx_self+1, other[(i+idx_other) % len(other)])

        self.nodes.insert(idx_self+1, other[idx_other])

    def rotate(self, angle, origin=(0, 0), use_degrees=True):
        r""" Rotate points around given origin

        :params:
            * *angle* (``float``)
                rotation angle
            * *origin* (``Vector2D``)
                origin point for the rotation. default: (0, 0)
            * *use_degrees* (``boolean``)
                rotation angle is given in degrees. default:True
        """

        for p in self.nodes:
            p.rotate(angle=angle, origin=origin, use_degrees=use_degrees)
        return self

    def translate(self, distance_vector):
        r""" Translate points

        :params:
            * *distance_vector* (``Vector2D``)
                2D vector defining by how much and in what direction to translate.
        """

        for p in self.nodes:
            p += distance_vector
        return self

    def __copy__(self):
        return PolygonPoints(nodes=self.nodes)

    def __iter__(self):
        for n in self.nodes:
            yield n

    def __getitem__(self, idx):
        return self.nodes[idx]

    def __len__(self):
        return len(self.nodes)


================================================
FILE: KicadModTree/Vector.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016-2018 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from __future__ import division
from builtins import round

import warnings

from KicadModTree.util.kicad_util import formatFloat
from math import sqrt, sin, cos, hypot, atan2, degrees, radians


class Vector2D(object):
    r"""Representation of a 2D Vector in space

    :Example:

    >>> from KicadModTree import *
    >>> Vector2D(0, 0)
    >>> Vector2D([0, 0])
    >>> Vector2D((0, 0))
    >>> Vector2D({'x': 0, 'y':0})
    >>> Vector2D(Vector2D(0, 0))
    """
    def __init__(self, coordinates=None, y=None):
        # parse constructor
        if coordinates is None:
            coordinates = {}
        elif type(coordinates) in [int, float]:
            if y is not None:
                coordinates = [coordinates, y]
            else:
                raise TypeError('you have to give x and y coordinate')
        elif isinstance(coordinates, Vector2D):
            # convert Vector2D as well as Vector3D to dict
            coordinates = coordinates.to_dict()

        # parse vectors with format: Vector2D({'x':0, 'y':0})
        if type(coordinates) is dict:
            self.x = float(coordinates.get('x', 0.))
            self.y = float(coordinates.get('y', 0.))
            return

        # parse vectors with format: Vector2D([0, 0]) or Vector2D((0, 0))
        if type(coordinates) in [list, tuple]:
            if len(coordinates) == 2:
                self.x = float(coordinates[0])
                self.y = float(coordinates[1])
                return
            else:
                raise TypeError('invalid list size (2 elements expected)')

        raise TypeError('invalid parameters given')

    def round_to(self, base):
        r"""Round to a specific base (like it's required for a grid)

        :param base: base we want to round to
        :return: rounded point

        >>> from KicadModTree import *
        >>> Vector2D(0.1234, 0.5678).round_to(0.01)
        """
        if base == 0 or base is None:
            return self.__copy__()

        return Vector2D([round(v / base) * base for v in self])

    def distance_to(self, value):
        r"""Distance between this and another point

        :param value: the other point
        :return: distance between self and other point
        """
        other = Vector2D.__arithmetic_parse(value)
        d = other - self
        return hypot(d.x, d.y)

    @staticmethod
    def __arithmetic_parse(value):
        if isinstance(value, Vector2D):
            return value
        elif type(value) in [int, float]:
            return Vector2D([value, value])
        else:
            return Vector2D(value)

    def __eq__(self, other):
        if not isinstance(self, other.__class__):
            return False
        return self.x == other.x and self.y == other.y

    def __ne__(self, other):
        return not self.__eq__(other)

    def __add__(self, value):
        other = Vector2D.__arithmetic_parse(value)

        return Vector2D({'x': self.x + other.x,
                         'y': self.y + other.y})

    def __iadd__(self, value):
        other = Vector2D.__arithmetic_parse(value)
        self.x += other.x
        self.y += other.y

        return self

    def __neg__(self):
        return Vector2D({'x': -self.x, 'y': -self.y})

    def __sub__(self, value):
        other = Vector2D.__arithmetic_parse(value)

        return Vector2D({'x': self.x - other.x,
                         'y': self.y - other.y})

    def __isub__(self, value):
        other = Vector2D.__arithmetic_parse(value)
        self.x -= other.x
        self.y -= other.y

        return self

    def __mul__(self, value):
        other = Vector2D.__arithmetic_parse(value)

        return Vector2D({'x': self.x * other.x,
                         'y': self.y * other.y})

    def __div__(self, value):
        other = Vector2D.__arithmetic_parse(value)

        return Vector2D({'x': self.x / other.x,
                         'y': self.y / other.y})

    def __truediv__(self, obj):
        return self.__div__(obj)

    def to_dict(self):
        return {'x': self.x, 'y': self.y}

    def render(self, formatcode):
        warnings.warn(
            "render is deprecated, read values directly instead",
            DeprecationWarning
        )
        return formatcode.format(x=formatFloat(self.x),
                                 y=formatFloat(self.y))

    def __repr__(self):
        return "Vector2D (x={x}, y={y})".format(**self.to_dict())

    def __str__(self):
        return "(x={x}, y={y})".format(**self.to_dict())

    def __getitem__(self, key):
        if key == 0 or key == 'x':
            return self.x
        if key == 1 or key == 'y':
            return self.y

        raise IndexError('Index {} is out of range'.format(key))

    def __setitem__(self, key, item):
        if key == 0 or key == 'x':
            self.x = item
        elif key == 1 or key == 'y':
            self.y = item
        else:
            raise IndexError('Index {} is out of range'.format(key))

    def __len__(self):
        return 2

    def __iter__(self):
        yield self.x
        yield self.y

    def __copy__(self):
        return Vector2D(self.x, self.y)

    def rotate(self, angle, origin=(0, 0), use_degrees=True):
        r""" Rotate vector around given origin

        :params:
            * *angle* (``float``)
                rotation angle
            * *origin* (``Vector2D``)
                origin point for the rotation. default: (0, 0)
            * *use_degrees* (``boolean``)
                rotation angle is given in degrees. default:True
        """

        op = Vector2D(origin)

        if use_degrees:
            angle = radians(angle)

        temp = op.x + cos(angle) * (self.x - op.x) - sin(angle) * (self.y - op.y)
        self.y = op.y + sin(angle) * (self.x - op.x) + cos(angle) * (self.y - op.y)
        self.x = temp

        return self

    def to_polar(self, origin=(0, 0), use_degrees=True):
        r""" Get polar representation of the vector

        :params:
            * *origin* (``Vector2D``)
                origin point for polar conversion. default: (0, 0)
            * *use_degrees* (``boolean``)
                angle in degrees. default:True
        """

        op = Vector2D(origin)

        diff = self - op
        radius = hypot(diff.x, diff.y)

        angle = atan2(diff.y, diff.x)
        if use_degrees:
            angle = degrees(angle)

        return (radius, angle)

    @staticmethod
    def from_polar(radius, angle, origin=(0, 0), use_degrees=True):
        r""" Generate a vector from its polar representation

        :params:
            * *radius* (``float``)
                lenght of the vector
            * *angle* (``float``)
                angle of the vector
            * *origin* (``Vector2D``)
                origin point for polar conversion. default: (0, 0)
            * *use_degrees* (``boolean``)
                angle in degrees. default:True
        """

        if use_degrees:
            angle = radians(angle)

        x = radius * cos(angle)
        y = radius * sin(angle)

        return Vector2D({'x': x, 'y': y})+Vector2D(origin)

    def to_homogeneous(self):
        r""" Get homogeneous representation
        """

        return Vector3D(self.x, self.y, 1)

    @staticmethod
    def from_homogeneous(source):
        r""" Recover 2d vector from its homogeneous representation

        :params:
            * *source* (``Vector3D``)
                3d homogeneous representation
        """

        return Vector2D(source.x/source.z, source.y/source.z)


class Vector3D(Vector2D):
    r"""Representation of a 3D Vector in space

    :Example:

    >>> from KicadModTree import *
    >>> Vector3D(0, 0, 0)
    >>> Vector3D([0, 0, 0])
    >>> Vector3D((0, 0, 0))
    >>> Vector3D({'x': 0, 'y':0, 'z':0})
    >>> Vector3D(Vector2D(0, 0))
    >>> Vector3D(Vector3D(0, 0, 0))
    """

    def __init__(self, coordinates=None, y=None, z=None):
        # we don't need a super constructor here

        # parse constructor
        if coordinates is None:
            coordinates = {}
        elif type(coordinates) in [int, float]:
            if y is not None:
                if z is not None:
                    coordinates = [coordinates, y, z]
                else:
                    coordinates = [coordinates, y]
            else:
                raise TypeError('you have to give at least x and y coordinate')
        elif isinstance(coordinates, Vector2D):
            # convert Vector2D as well as Vector3D to dict
            coordinates = coordinates.to_dict()

        # parse vectors with format: Vector2D({'x':0, 'y':0})
        if type(coordinates) is dict:
            self.x = float(coordinates.get('x', 0.))
            self.y = float(coordinates.get('y', 0.))
            self.z = float(coordinates.get('z', 0.))
            return

        # parse vectors with format: Vector3D([0, 0]), Vector3D([0, 0, 0]) or Vector3D((0, 0)), Vector3D((0, 0, 0))
        if type(coordinates) in [list, tuple]:
            if len(coordinates) >= 2:
                self.x = float(coordinates[0])
                self.y = float(coordinates[1])
            else:
                raise TypeError('invalid list size (to small)')

            if len(coordinates) == 3:
                self.z = float(coordinates[2])
            else:
                self.z = 0.

            if len(coordinates) > 3:
                raise TypeError('invalid list size (to big)')

        else:
            raise TypeError('dict or list type required')

    def round_to(self, base):
        r"""Round to a specific base (like it's required for a grid)

        :param base: base we want to round to
        :return: rounded point

        >>> from KicadModTree import *
        >>> Vector3D(0.123, 0.456, 0.789).round_to(0.01)
        """
        if base == 0 or base is None:
            return self.__copy__()

        return Vector3D([round(v / base) * base for v in self])

    def cross_product(self, other):
        other = Vector3D.__arithmetic_parse(other)

        return Vector3D({
                    'x': self.y*other.z - self.z*other.y,
                    'y': self.z*other.x - self.x*other.z,
                    'z': self.x*other.y - self.y*other.x})

    def dot_product(self, other):
        other = Vector3D.__arithmetic_parse(other)

        return self.x*other.x + self.y*other.y + self.z*other.z

    @staticmethod
    def __arithmetic_parse(value):
        if isinstance(value, Vector3D):
            return value
        elif type(value) in [int, float]:
            return Vector3D([value, value, value])
        else:
            return Vector3D(value)

    def __eq__(self, other):
        if not isinstance(self, other.__class__):
            return False
        return self.x == other.x and self.y == other.y and self.z == other.z

    def __ne__(self, other):
        return not self.__eq__(other)

    def __add__(self, value):
        other = Vector3D.__arithmetic_parse(value)

        return Vector3D({'x': self.x + other.x,
                         'y': self.y + other.y,
                         'z': self.z + other.z})

    def __iadd__(self, value):
        other = Vector2D.__arithmetic_parse(value)
        self.x += other.x
        self.y += other.y
        self.z += other.z

        return self

    def __neg__(self):
        return Vector2D({'x': -self.x,
                         'y': -self.y,
                         'z': -self.z})

    def __sub__(self, value):
        other = Vector3D.__arithmetic_parse(value)

        return Vector3D({'x': self.x - other.x,
                         'y': self.y - other.y,
                         'z': self.z - other.z})

    def __isub__(self, value):
        other = Vector2D.__arithmetic_parse(value)
        self.x -= other.x
        self.y -= other.y
        self.z -= other.z

        return self

    def __mul__(self, value):
        other = Vector3D.__arithmetic_parse(value)

        return Vector3D({'x': self.x * other.x,
                         'y': self.y * other.y,
                         'z': self.z * other.z})

    def __div__(self, value):
        other = Vector3D.__arithmetic_parse(value)

        return Vector3D({'x': self.x / other.x,
                         'y': self.y / other.y,
                         'z': self.z / other.z})

    def __truediv__(self, obj):
        return self.__div__(obj)

    def to_dict(self):
        return {'x': self.x, 'y': self.y, 'z': self.z}

    def render(self, formatcode):
        warnings.warn(
            "render is deprecated, read values directly instead",
            DeprecationWarning
        )
        return formatcode.format(x=formatFloat(self.x),
                                 y=formatFloat(self.y),
                                 z=formatFloat(self.z))

    def __repr__(self):
        return "Vector3D (x={x}, y={y}, z={z})".format(**self.to_dict())

    def __str__(self):
        return "(x={x}, y={y}, z={z})".format(**self.to_dict())

    def __getitem__(self, key):
        if key == 0 or key == 'x':
            return self.x
        if key == 1 or key == 'y':
            return self.y
        if key == 2 or key == 'z':
            return self.z

        raise IndexError('Index {} is out of range'.format(key))

    def __setitem__(self, key, item):
        if key == 0 or key == 'x':
            self.x = item
        elif key == 1 or key == 'y':
            self.y = item
        elif key == 2 or key == 'z':
            self.z = item
        else:
            raise IndexError('Index {} is out of range'.format(key))

    def __len__(self):
        return 3

    def __iter__(self):
        yield self.x
        yield self.y
        yield self.z

    def __copy__(self):
        return Vector3D(self.x, self.y, self.z)


================================================
FILE: KicadModTree/__init__.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.Point import *  # backwards compatibility

# all different types of nodes
from KicadModTree.nodes import *

# File Handlers
from KicadModTree.KicadFileHandler import KicadFileHandler

# Argparser
from KicadModTree.ModArgparser import ModArgparser


================================================
FILE: KicadModTree/examples/__init__.py
================================================
'''
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/ >.
'''


================================================
FILE: KicadModTree/examples/argparse_example.py
================================================
#!/usr/bin/env python

# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

import sys
import os

sys.path.append(os.path.join(sys.path[0], "../.."))  # enable package import from parent directory

from KicadModTree import *  # NOQA


def example_footprint(args):
    print("now we can create a footprint using the following parameters:")
    print(args)


if __name__ == '__main__':
    parser = ModArgparser(example_footprint)
    parser.add_parameter("name", type=str, required=True)  # the root node of .yml files is parsed as name
    parser.add_parameter("datasheet", type=str, required=False)
    parser.add_parameter("courtyard", type=float, required=False, default=0.25)
    parser.add_parameter("diameter", type=float, required=True)
    parser.add_parameter("pad_length", type=float, required=True)
    parser.add_parameter("pad_width", type=float, required=True)

    parser.run()  # now run our script which handles the whole part of parsing the files


================================================
FILE: KicadModTree/examples/padArrayWithOutline.py
================================================
#!/usr/bin/env python

# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2017 by @SchrodingersGat
# (C) 2017 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

import sys
sys.path.append('../..')  # enable package import from parent directory

from KicadModTree import *  # NOQA

if __name__ == '__main__':
    footprint_name = "pad_array_footprint"

    # Init kicad footprint
    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("An example footprint")
    kicad_mod.setTags("example")

    # Set general values
    kicad_mod.append(Text(type='reference', text='REF**', at=[0, -3], layer='F.SilkS'))
    kicad_mod.append(Text(type='value', text=footprint_name, at=[1.5, 3], layer='F.Fab'))

    # Add model
    kicad_mod.append(Model(filename="example.3dshapes/example_footprint.wrl",
                           at=[0, 0, 0],
                           scale=[1, 1, 1],
                           rotate=[0, 0, 0]))

    # Create a pad array with a large horizontal spacing, and a smaller vertical spacing
    # centered at the origin
    pa = PadArray(pincount=10,
                  spacing=[2.54, -0.2],
                  center=[0, 0],
                  initial=5,
                  increment=2,
                  type=Pad.TYPE_SMT,
                  shape=Pad.SHAPE_RECT,
                  size=[1, 2],
                  layers=Pad.LAYERS_SMT)

    kicad_mod.append(pa)

    # Calculate the border of the pad array
    border = pa.calculateOutline()

    # Create a courtyard around the pad array
    kicad_mod.append(RectLine(start=border['min'], end=border['max'], layer='F.Fab', width=0.05, offset=0.5))

    # Write file
    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile('example_footprint.kicad_mod')


================================================
FILE: KicadModTree/examples/params.csv
================================================
name,        diameter,    pad_length,      pad_width
10x2x5,10,2,5
15x2x5,15,2,5
18x2x5,18,2,5
"Jsjdlfmlakefjsl , asldl",13,5,2.5


================================================
FILE: KicadModTree/examples/params.yml
================================================
asdf:
  diameter: 10
  pad_length: 3
  pad_width: 7

================================================
FILE: KicadModTree/examples/polygon.py
================================================
#!/usr/bin/env python

# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

import sys
import os

sys.path.append(os.path.join(sys.path[0], "../.."))  # enable package import from parent directory

from KicadModTree import *  # NOQA


if __name__ == '__main__':
    footprint_name = "example_footprint"

    # init kicad footprint
    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("A example footprint")
    kicad_mod.setTags("example")

    # set general values
    kicad_mod.append(Text(type='reference', text='REF**', at=[0, -3], layer='F.SilkS'))
    kicad_mod.append(Text(type='value', text=footprint_name, at=[1.5, 3], layer='F.Fab'))

    # create polygon
    kicad_mod.append(Polygon(nodes=[[-2, 0], [0, -2], [4, 0], [0, 2], [-2, 0], [0, -2], [4, 0], [0, 2]],
                             layer='F.SilkS'))

    # print render tree
    print(kicad_mod.getCompleteRenderTree())

    # write file
    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile('example_footprint.kicad_mod')


================================================
FILE: KicadModTree/examples/simpleFootprint.py
================================================
#!/usr/bin/env python

# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

import sys
import os

sys.path.append(os.path.join(sys.path[0], "../.."))  # enable package import from parent directory

from KicadModTree import *  # NOQA


if __name__ == '__main__':
    footprint_name = "example_footprint"

    # init kicad footprint
    kicad_mod = Footprint(footprint_name)
    kicad_mod.setDescription("A example footprint")
    kicad_mod.setTags("example")

    # set general values
    kicad_mod.append(Text(type='reference', text='REF**', at=[0, -3], layer='F.SilkS'))
    kicad_mod.append(Text(type='value', text=footprint_name, at=[1.5, 3], layer='F.Fab'))

    # create silkscreen
    kicad_mod.append(RectLine(start=[-2, -2], end=[5, 2], layer='F.SilkS'))

    # create courtyard
    kicad_mod.append(RectLine(start=[-2.25, -2.25], end=[5.25, 2.25], layer='F.CrtYd'))

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

    # add model
    kicad_mod.append(Model(filename="example.3dshapes/example_footprint.wrl",
                           at=[0, 0, 0], scale=[1, 1, 1], rotate=[0, 0, 0]))

    # print render tree
    # print(kicad_mod.getRenderTree())
    print(kicad_mod.getCompleteRenderTree())

    # write file
    file_handler = KicadFileHandler(kicad_mod)
    file_handler.writeFile('example_footprint.kicad_mod')


================================================
FILE: KicadModTree/nodes/Footprint.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>


from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node


'''
This is my new approach, using a render tree for footprint generation.

ADVANTAGES:

* simple point transformations
* automatic calculation of courtjard,...
* simple duplication of rendering structures

'''

# define in which order the general "lisp" operators are arranged
render_order = ['descr', 'tags', 'attr', 'solder_mask_margin',
                'solder_paste_margin', 'solder_paste_ratio', 'fp_text',
                'fp_circle', 'fp_line', 'pad', 'model']
# TODO: sort Text by type


class Footprint(Node):
    '''
    Root Node to generate KicadMod
    '''
    def __init__(self, name):
        Node.__init__(self)

        self.name = name
        self.description = None
        self.tags = None
        self.attribute = None
        self.maskMargin = None
        self.pasteMargin = None
        self.pasteMarginRatio = None

    def setName(self, name):
        self.name = name

    def setDescription(self, description):
        self.description = description

    def setTags(self, tags):
        self.tags = tags

    def setAttribute(self, value):
        self.attribute = value

    def setMaskMargin(self, value):
        self.maskMargin = value

    def setPasteMargin(self, value):
        self.pasteMargin = value

    def setPasteMarginRatio(self, value):
        # paste_margin_ratio is unitless between 0 and 1 while GUI uses percentage
        assert abs(value) <= 1, "Solder paste margin must be between -1 and 1. {} is too large.".format(value)

        self.pasteMarginRatio = value


================================================
FILE: KicadModTree/nodes/Node.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from copy import copy, deepcopy

from KicadModTree.Vector import *


class MultipleParentsError(RuntimeError):
    def __init__(self, message):

        # Call the base class constructor with the parameters it needs
        super(MultipleParentsError, self).__init__(message)


class RecursionDetectedError(RuntimeError):
    def __init__(self, message):

        # Call the base class constructor with the parameters it needs
        super(RecursionDetectedError, self).__init__(message)


class Node(object):
    def __init__(self):
        self._parent = None
        self._childs = []

    def append(self, node):
        '''
        add node to child
        '''
        if not isinstance(node, Node):
            raise TypeError('invalid object, has to be based on Node')

        if node._parent:
            raise MultipleParentsError('muliple parents are not allowed!')

        self._childs.append(node)

        node._parent = self

    def extend(self, nodes):
        '''
        add list of nodes to child
        '''
        new_nodes = []
        for node in nodes:
            if not isinstance(node, Node):
                raise TypeError('invalid object, has to be based on Node')

            if node._parent or node in new_nodes:
                raise MultipleParentsError('muliple parents are not allowed!')

            new_nodes.append(node)

        # when all went smooth by now, we can set the parent nodes to ourself
        for node in new_nodes:
            node._parent = self

        self._childs.extend(new_nodes)

    def remove(self, node):
        '''
        remove child from node
        '''
        if not isinstance(node, Node):
            raise TypeError('invalid object, has to be based on Node')

        while node in self._childs:
            self._childs.remove(node)

        node._parent = None

    def insert(self, node):
        '''
        moving all childs into the node, and using the node as new parent of those childs
        '''
        if not isinstance(node, Node):
            raise TypeError('invalid object, has to be based on Node')

        for child in copy(self._childs):
            self.remove(child)
            node.append(child)

        self.append(node)

    def copy(self):
        copy = deepcopy(self)
        copy._parent = None
        return copy

    def serialize(self):
        nodes = [self]
        for child in self.getAllChilds():
            nodes += child.serialize()
        return nodes

    def getNormalChilds(self):
        '''
        Get all normal childs of this node
        '''
        return self._childs

    def getVirtualChilds(self):
        '''
        Get virtual childs of this node
        '''
        return []

    def getAllChilds(self):
        '''
        Get virtual and normal childs of this node
        '''
        return self.getNormalChilds() + self.getVirtualChilds()

    def getParent(self):
        '''
        get Parent Node of this Node
        '''
        return self._parent

    def getRootNode(self):
        '''
        get Root Node of this Node
        '''

        # TODO: recursion detection
        if not self.getParent():
            return self

        return self.getParent().getRootNode()

    def getRealPosition(self, coordinate, rotation=None):
        '''
        return position of point after applying all transformation and rotation operations
        '''
        if not self._parent:
            if rotation is None:
                # TODO: most of the points are 2D Nodes
                return Vector3D(coordinate)
            else:
                return Vector3D(coordinate), rotation

        return self._parent.getRealPosition(coordinate, rotation)

    def calculateBoundingBox(self, outline=None):
        min_x, min_y = 0, 0
        max_x, max_y = 0, 0

        if outline:
            min_x = outline['min']['x']
            min_y = outline['min']['y']
            max_x = outline['max']['x']
            max_y = outline['max']['y']

        for child in self.getAllChilds():
            child_outline = child.calculateBoundingBox()

            min_x = min([min_x, child_outline['min']['x']])
            min_y = min([min_y, child_outline['min']['y']])
            max_x = max([max_x, child_outline['max']['x']])
            max_y = max([max_y, child_outline['max']['y']])

        return {'min': Vector2D(min_x, min_y), 'max': Vector2D(max_x, max_y)}

    def _getRenderTreeText(self):
        '''
        Text which is displayed when generating a render tree
        '''
        return type(self).__name__

    def _getRenderTreeSymbol(self):
        '''
        Symbol which is displayed when generating a render tree
        '''
        if self._parent is None:
            return "+"

        return "*"

    def getRenderTree(self, rendered_nodes=None):
        '''
        print render tree
        '''
        if rendered_nodes is None:
            rendered_nodes = set()

        if self in rendered_nodes:
            raise RecursionDetectedError('recursive definition of render tree!')

        rendered_nodes.add(self)

        tree_str = "{0} {1}".format(self._getRenderTreeSymbol(), self._getRenderTreeText())
        for child in self.getNormalChilds():
            tree_str += '\n  '
            tree_str += '  '.join(child.getRenderTree(rendered_nodes).splitlines(True))

        return tree_str

    def getCompleteRenderTree(self, rendered_nodes=None):
        '''
        print virtual render tree
        '''
        if rendered_nodes is None:
            rendered_nodes = set()

        if self in rendered_nodes:
            raise RecursionDetectedError('recursive definition of render tree!')

        rendered_nodes.add(self)

        tree_str = "{0} {1}".format(self._getRenderTreeSymbol(), self._getRenderTreeText())
        for child in self.getAllChilds():
            tree_str += '\n  '
            tree_str += '  '.join(child.getCompleteRenderTree(rendered_nodes).splitlines(True))

        return tree_str


================================================
FILE: KicadModTree/nodes/__init__.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

# generic node
from .Node import Node, MultipleParentsError, RecursionDetectedError

# root node
from .Footprint import Footprint

from .base import *
from .specialized import *


================================================
FILE: KicadModTree/nodes/base/Arc.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node
import math
from KicadModTree.util.geometric_util import geometricArc, BaseNodeIntersection


class Arc(Node, geometricArc):
    r"""Add an Arc to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *geometry* (``geometricArc``)
          alternative to using geometric parameters
        * *center* (``Vector2D``) --
          center of arc
        * *start* (``Vector2D``) --
          start point of arc
        * *midpoint* (``Vector2D``) --
          alternative to start point
          point is on arc and defines point of equal distance to both arc ends
          arcs of this form are given as midpoint, center plus angle
        * *end* (``Vector2D``) --
          alternative to angle
          arcs of this form are given as start, end and center
        * *angle* (``float``) --
          angle of arc
        * *layer* (``str``) --
          layer on which the arc is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the arc line (default: None, which means auto detection)

    :Example:

    >>> from KicadModTree import *
    >>> Arc(center=[0, 0], start=[-1, 0], angle=180, layer='F.SilkS')
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        geometricArc.__init__(self, **kwargs)

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def copyReplaceGeometry(self, geometry):
        return Arc(geometry=geometry, layer=self.layer, width=self.width)

    def copy(self):
        return Arc(
            center=self.center_pos, start=self.start_pos, angle=self.angle,
            layer=self.layer, width=self.width
            )

    def cut(self, *other):
        r""" cut line with given other element

        :params:
            * *other* (``Line``, ``Circle``, ``Arc``)
                cut the element on any intersection with the given geometric element
        """
        result = []
        garcs = geometricArc.cut(self, *other)
        for g in garcs:
            result.append(self.copyReplaceGeometry(g))

        return result

    def calculateBoundingBox(self):
        # TODO: finish implementation
        min_x = min(self.start_pos.x, self._calulateEndPos().x)
        min_y = min(self.start_pos.x, self._calulateEndPos().y)
        max_x = max(self.start_pos.x, self._calulateEndPos().x)
        max_y = max(self.start_pos.x, self._calulateEndPos().y)

        '''
        for angle in range(4):
            float_angle = angle * math.pi/2.

            start_angle = _calculateStartAngle(self)
            end_angle = start_angle + math.radians(self.angle)

            # TODO: +- pi border
            if float_angle < start_angle:
                continue
            if float_angle > end_angle:
                continue

            print("TODO: add angle side: {1}".format(float_angle))
        '''

        return Node.calculateBoundingBox({'min': Vector2D((min_x, min_y)), 'max': Vector2D((max_x, max_y))})

    def _getRenderTreeText(self):
        render_strings = ['fp_arc']
        render_strings.append(self.center_pos.render('(center {x} {y})'))
        render_strings.append(self.start_pos.render('(start {x} {y})'))
        render_strings.append('(angle {angle})'.format(angle=self.angle))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text


================================================
FILE: KicadModTree/nodes/base/Circle.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node
from KicadModTree.util.geometric_util import geometricCircle, BaseNodeIntersection


class Circle(Node, geometricCircle):
    r"""Add a Circle to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *center* (``Vector2D``) --
          center of the circle
        * *radius* (``float``) --
          radius of the circle
        * *layer* (``str``) --
          layer on which the circle is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the circle line (default: None, which means auto detection)

    :Example:

    >>> from KicadModTree import *
    >>> Circle(center=[0, 0], radius=1.5, layer='F.SilkS')
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        geometricCircle.__init__(self, Vector2D(kwargs['center']), float(kwargs['radius']))

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def rotate(self, angle, origin=(0, 0), use_degrees=True):
        r""" Rotate circle around given origin

        :params:
            * *angle* (``float``)
                rotation angle
            * *origin* (``Vector2D``)
                origin point for the rotation. default: (0, 0)
            * *use_degrees* (``boolean``)
                rotation angle is given in degrees. default:True
        """

        self.center_pos.rotate(angle=angle, origin=origin, use_degrees=use_degrees)
        return self

    def translate(self, distance_vector):
        r""" Translate circle

        :params:
            * *distance_vector* (``Vector2D``)
                2D vector defining by how much and in what direction to translate.
        """

        self.center_pos += distance_vector
        return self

    def cut(self, *other):
        raise NotImplemented("cut for circles not yet implemented")

    def getRadius(self):
        return self.radius

    def calculateBoundingBox(self):
        min_x = self.center_pos.x-self.radius
        min_y = self.center_pos.y-self.radius
        max_x = self.center_pos.x+self.radius
        max_y = self.center_pos.y+self.radius

        return Node.calculateBoundingBox({'min': ParseXY(min_x, min_y), 'max': ParseXY(max_x, max_y)})

    def _getRenderTreeText(self):
        render_strings = ['fp_circle']
        render_strings.append(self.center_pos.render('(center {x} {y})'))
        render_strings.append(self.end_pos.render('(end {x} {y})'))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text


================================================
FILE: KicadModTree/nodes/base/Line.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node
from KicadModTree.util.geometric_util import geometricLine, BaseNodeIntersection


class Line(Node, geometricLine):
    r"""Add a Line to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *start* (``Vector2D``) --
          start point of the line
        * *end* (``Vector2D``) --
          end point of the line
        * *layer* (``str``) --
          layer on which the line is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the line (default: None, which means auto detection)

    :Example:

    >>> from KicadModTree import *
    >>> Line(start=[1, 0], end=[-1, 0], layer='F.SilkS')
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        if 'geometry' in kwargs:
            geometry = kwargs['geometry']
            geometricLine.__init__(self, geometry.start_pos, geometry.end_pos)
        else:
            geometricLine.__init__(
                self,
                start=Vector2D(kwargs['start']),
                end=Vector2D(kwargs['end'])
                )

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def copyReplaceGeometry(self, geometry):
        return Line(
            start=geometry.start_pos, end=geometry.end_pos,
            layer=self.layer, width=self.width
            )

    def copy(self):
        return Line(
            start=self.start_pos, end=self.end_pos,
            layer=self.layer, width=self.width
            )

    def cut(self, *other):
        r""" cut line with given other element

        :params:
            * *other* (``Line``, ``Circle``, ``Arc``)
                cut the element on any intersection with the given geometric element
        """
        result = []
        glines = geometricLine.cut(self, *other)
        for g in glines:
            result.append(self.copyReplaceGeometry(g))

        return result

    def _getRenderTreeText(self):
        render_strings = ['fp_line']
        render_strings.append(self.start_pos.render('(start {x} {y})'))
        render_strings.append(self.end_pos.render('(end {x} {y})'))
        render_strings.append('(layer {layer})'.format(layer=self.layer))
        render_strings.append('(width {width})'.format(width=self.width))

        render_text = Node._getRenderTreeText(self)
        render_text += ' ({})'.format(' '.join(render_strings))

        return render_text

    def calculateBoundingBox(self):
        render_start_pos = self.getRealPosition(self.start_pos)
        render_end_pos = self.getRealPosition(self.end_pos)

        min_x = min([render_start_pos.x, render_end_pos.x])
        min_y = min([render_start_pos.y, render_end_pos.y])
        max_x = max([render_start_pos.x, render_end_pos.x])
        max_y = max([render_start_pos.y, render_end_pos.y])

        return Node.calculateBoundingBox({'min': Vector2D(min_x, min_y), 'max': Vector2D(max_x, max_y)})


================================================
FILE: KicadModTree/nodes/base/Model.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node


class Model(Node):
    r"""Add a 3D-Model to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *filename* (``str``) --
          name of the 3d-model file
        * *at* (``Vector3D``) --
          position of the model (default: [0, 0, 0])
        * *scale* (``Vector3D``) --
          scale of the model (default: [1, 1, 1])
        * *rotate* (``Vector3D``) --
          rotation of the model (default: [0, 0, 0])

    :Example:

    >>> from KicadModTree import *
    >>> Model(filename="example.3dshapes/example_footprint.wrl",
    ...       at=[0, 0, 0], scale=[1, 1, 1], rotate=[0, 0, 0])
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.filename = kwargs['filename']
        self.at = Vector3D(kwargs.get('at', [0, 0, 0]))
        self.scale = Vector3D(kwargs.get('scale', [1, 1, 1]))
        self.rotate = Vector3D(kwargs.get('rotate', [0, 0, 0]))

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)

        render_string = ['filename: {filename}'.format(filename=self.filename),
                         'at: {at}'.format(at=self.at.render('(xyz {x} {y} {z})')),
                         'scale: {scale}'.format(scale=self.scale.render('(xyz {x} {y} {z})')),
                         'rotate: {rotate}'.format(rotate=self.rotate.render('(xyz {x} {y} {z})'))]

        render_text += " [{}]".format(", ".join(render_string))

        return render_text


================================================
FILE: KicadModTree/nodes/base/Pad.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
# (C) 2018 by Rene Poeschl, github @poeschlr

from KicadModTree.util.paramUtil import *
from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node
from KicadModTree.util.kicad_util import lispString
from KicadModTree.nodes.base.Arc import Arc
from KicadModTree.nodes.base.Circle import Circle
from KicadModTree.nodes.base.Line import Line
from KicadModTree.nodes.base.Polygon import Polygon


class RoundRadiusHandler(object):
    r"""Handles round radius setting of a pad

    :param \**kwargs:
        See below

    :Keyword Arguments:
    * *radius_ratio* (``float [0 <= r <= 0.5]``) --
      The radius ratio of the rounded rectangle. (default set by default_radius_ratio)
    * *maximum_radius* (``float``) --
      The maximum radius for the rounded rectangle.
      If the radius produced by the radius_ratio parameter for the pad would
      exceed the maximum radius, the ratio is reduced to limit the radius.
      (This is useful for IPC-7351C compliance as it suggests 25% ratio with limit 0.25mm)
    * *round_radius_exact* (``float``) --
      Set an exact round radius for a pad.
    * *default_radius_ratio* (``float [0 <= r <= 0.5]``) --
      This parameter allows to set the default radius ratio
      (backwards compatibility option for chamfered pads)
    """
    def __init__(self, **kwargs):
        default_radius_ratio = getOptionalNumberTypeParam(
                            kwargs, 'default_radius_ratio', default_value=0.25,
                            low_limit=0, high_limit=0.5)
        self.radius_ratio = getOptionalNumberTypeParam(
                            kwargs, 'radius_ratio', default_value=default_radius_ratio,
                            low_limit=0, high_limit=0.5)

        self.maximum_radius = getOptionalNumberTypeParam(kwargs, 'maximum_radius')
        self.round_radius_exact = getOptionalNumberTypeParam(kwargs, 'round_radius_exact')

        self.kicad4_compatible = kwargs.get('kicad4_compatible', False)

    def getRadiusRatio(self, shortest_sidelength):
        r"""get the resulting round radius ratio

        :param shortest_sidelength: shortest sidelength of a pad
        :return: the resulting round radius ratio to be used for the pad
        """
        if self.kicad4_compatible:
            return 0

        if self.round_radius_exact is not None:
            if self.round_radius_exact > shortest_sidelength/2:
                raise ValueError(
                    "requested round radius of {} is too large for pad size of {}"
                    .format(self.round_radius_exact, pad_size)
                    )
            if self.maximum_radius is not None:
                return min(self.round_radius_exact, self.maximum_radius)/shortest_sidelength
            else:
                return self.round_radius_exact/shortest_sidelength
        if self.maximum_radius is not None:
            if self.radius_ratio*shortest_sidelength > self.maximum_radius:
                return self.maximum_radius/shortest_sidelength

        return self.radius_ratio

    def getRoundRadius(self, shortest_sidelength):
        r"""get the resulting round radius

        :param shortest_sidelength: shortest sidelength of a pad
        :return: the resulting round radius to be used for the pad
        """
        return self.getRadiusRatio(shortest_sidelength)*shortest_sidelength

    def roundingRequested(self):
        r"""Check if the pad has a rounded corner

        :return: True if rounded corners are required
        """
        if self.kicad4_compatible:
            return False

        if self.maximum_radius == 0:
            return False

        if self.round_radius_exact == 0:
            return False

        if self.radius_ratio == 0:
            return False

        return True

    def limitMaxRadius(self, limit):
        r"""Set a new maximum limit

        :param limit: the new limit.
        """

        if not self.roundingRequested():
            return
        if self.maximum_radius is not None:
            self.maximum_radius = min(self.maximum_radius, limit)
        else:
            self.maximum_radius = limit

    def __str__(self):
        return "ratio {}, max {}, exact {}, v4 compatible {}".format(
                    self.radius_ratio, self.maximum_radius,
                    self.round_radius_exact, self.kicad4_compatible
                    )


class Pad(Node):
    r"""Add a Pad to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *number* (``int``, ``str``) --
          number/name of the pad (default: \"\")
        * *type* (``Pad.TYPE_THT``, ``Pad.TYPE_SMT``, ``Pad.TYPE_CONNECT``, ``Pad.TYPE_NPTH``) --
          type of the pad
        * *shape* (``Pad.SHAPE_CIRCLE``, ``Pad.SHAPE_OVAL``, ``Pad.SHAPE_RECT``, ``SHAPE_ROUNDRECT``,
        ``Pad.SHAPE_TRAPEZE``, ``SHAPE_CUSTOM``) --
          shape of the pad
        * *layers* (``Pad.LAYERS_SMT``, ``Pad.LAYERS_THT``, ``Pad.LAYERS_NPTH``) --
          layers on which are used for the pad

        * *at* (``Vector2D``) --
          center position of the pad
        * *rotation* (``float``) --
          rotation of the pad
        * *size* (``float``, ``Vector2D``) --
          size of the pad
        * *offset* (``Vector2D``) --
          offset of the pad
        * *drill* (``float``, ``Vector2D``) --
          drill-size of the pad

        * *radius_ratio* (``float``) --
          The radius ratio of the rounded rectangle.
          Ignored for every shape except round rect.
        * *maximum_radius* (``float``) --
          The maximum radius for the rounded rectangle.
          If the radius produced by the radius_ratio parameter for the pad would
          exceed the maximum radius, the ratio is reduced to limit the radius.
          (This is useful for IPC-7351C compliance as it suggests 25% ratio with limit 0.25mm)
          Ignored for every shape except round rect.
        * *round_radius_exact* (``float``) --
          Set an exact round radius for a pad.
          Ignored for every shape except round rect
        * *round_radius_handler* (``RoundRadiusHandler``) --
          An instance of the RoundRadiusHandler class
          If this is given then all other round radius specifiers are ignored
          Ignored for every shape except round rect

        * *solder_paste_margin_ratio* (``float``) --
          solder paste margin ratio of the pad (default: 0)
        * *solder_paste_margin* (``float``) --
          solder paste margin of the pad (default: 0)
        * *solder_mask_margin* (``float``) --
          solder mask margin of the pad (default: 0)

        * *x_mirror* (``[int, float](mirror offset)``) --
          mirror x direction around offset "point"
        * *y_mirror* (``[int, float](mirror offset)``) --
          mirror y direction around offset "point"

    :Example:

    >>> from KicadModTree import *
    >>> Pad(number=1, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT,
    ...     at=[0, 0], size=[2, 2], drill=1.2, layers=Pad.LAYERS_THT)
    """

    TYPE_THT = 'thru_hole'
    TYPE_SMT = 'smd'
    TYPE_CONNECT = 'connect'
    TYPE_NPTH = 'np_thru_hole'
    _TYPES = [TYPE_THT, TYPE_SMT, TYPE_CONNECT, TYPE_NPTH]

    SHAPE_CIRCLE = 'circle'
    SHAPE_OVAL = 'oval'
    SHAPE_RECT = 'rect'
    SHAPE_ROUNDRECT = 'roundrect'
    SHAPE_TRAPEZE = 'trapezoid'
    SHAPE_CUSTOM = 'custom'
    _SHAPES = [SHAPE_CIRCLE, SHAPE_OVAL, SHAPE_RECT, SHAPE_ROUNDRECT, SHAPE_TRAPEZE, SHAPE_CUSTOM]

    LAYERS_SMT = ['F.Cu', 'F.Mask', 'F.Paste']
    LAYERS_THT = ['*.Cu', '*.Mask']
    LAYERS_NPTH = ['*.Cu', '*.Mask']

    ANCHOR_CIRCLE = 'circle'
    ANCHOR_RECT = 'rect'
    _ANCHOR_SHAPE = [ANCHOR_CIRCLE, ANCHOR_RECT]

    SHAPE_IN_ZONE_CONVEX = 'convexhull'
    SHAPE_IN_ZONE_OUTLINE = 'outline'
    _SHAPE_IN_ZONE = [SHAPE_IN_ZONE_CONVEX, SHAPE_IN_ZONE_OUTLINE]

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.radius_ratio = 0

        self._initNumber(**kwargs)
        self._initType(**kwargs)
        self._initShape(**kwargs)
        self._initPosition(**kwargs)
        self._initSize(**kwargs)
        self._initOffset(**kwargs)
        self._initDrill(**kwargs)  # requires pad type and offset
        self._initSolderPasteMargin(**kwargs)
        self._initSolderPasteMarginRatio(**kwargs)
        self._initSolderMaskMargin(**kwargs)
        self._initLayers(**kwargs)
        self._initMirror(**kwargs)

        if self.shape == self.SHAPE_OVAL and self.size[0] == self.size[1]:
            self.shape = self.SHAPE_CIRCLE

        if self.shape == Pad.SHAPE_OVAL or self.shape == Pad.SHAPE_CIRCLE:
            self.radius_ratio = 0.5
        if self.shape == Pad.SHAPE_ROUNDRECT:
            self._initRadiusRatio(**kwargs)

        if self.shape == Pad.SHAPE_CUSTOM:
            self._initAnchorShape(**kwargs)
            self._initShapeInZone(**kwargs)

            self.primitives = []
            if 'primitives' not in kwargs:
                raise KeyError('primitives must be declared for custom pads')

            for p in kwargs['primitives']:
                self.addPrimitive(p)

    def _initMirror(self, **kwargs):
        self.mirror = [None, None]
        if 'x_mirror' in kwargs and type(kwargs['x_mirror']) in [float, int]:
            self.mirror[0] = kwargs['x_mirror']
        if 'y_mirror' in kwargs and type(kwargs['y_mirror']) in [float, int]:
            self.mirror[1] = kwargs['y_mirror']

        if self.mirror[0] is not None:
            self.at.x = 2 * self.mirror[0] - self.at.x
            self.offset.x *= -1
        if self.mirror[1] is not None:
            self.at.y = 2 * self.mirror[1] - self.at.y
            self.offset.y *= -1

    def _initNumber(self, **kwargs):
        self.number = kwargs.get('number', "")  # default to an un-numbered pad

    def _initType(self, **kwargs):
        if not kwargs.get('type'):
            raise KeyError('type not declared (like "type=Pad.TYPE_THT")')
        self.type = kwargs.get('type')
        if self.type not in Pad._TYPES:
            raise ValueError('{type} is an invalid type for pads'.format(type=self.type))

    def _initShape(self, **kwargs):
        if not kwargs.get('shape'):
            raise KeyError('shape not declared (like "shape=Pad.SHAPE_CIRCLE")')
        self.shape = kwargs.get('shape')
        if self.shape not in Pad._SHAPES:
            raise ValueError('{shape} is an invalid shape for pads'.format(shape=self.shape))

    def _initPosition(self, **kwargs):
        if not kwargs.get('at'):
            raise KeyError('center position not declared (like "at=[0,0]")')
        self.at = Vector2D(kwargs.get('at'))

        self.rotation = kwargs.get('rotation', 0)

    def _initSize(self, **kwargs):
        if not kwargs.get('size'):
            raise KeyError('pad size not declared (like "size=[1,1]")')
        self.size = toVectorUseCopyIfNumber(kwargs.get('size'), low_limit=0)

    def _initOffset(self, **kwargs):
        self.offset = Vector2D(kwargs.get('offset', [0, 0]))

    def _initDrill(self, **kwargs):
        if self.type in [Pad.TYPE_THT, Pad.TYPE_NPTH]:
            if not kwargs.get('drill'):
                raise KeyError('drill size required (like "drill=1")')
            self.drill = toVectorUseCopyIfNumber(kwargs.get('drill'), low_limit=0)
        else:
            self.drill = None
            if kwargs.get('drill'):
                pass  # TODO: throw warning because drill is not supported

    def _initSolderPasteMarginRatio(self, **kwargs):
        self.solder_paste_margin_ratio = kwargs.get('solder_paste_margin_ratio', 0)

    def _initSolderPasteMargin(self, **kwargs):
        self.solder_paste_margin = kwargs.get('solder_paste_margin', 0)

    def _initSolderMaskMargin(self, **kwargs):
        self.solder_mask_margin = kwargs.get('solder_mask_margin', 0)

    def _initLayers(self, **kwargs):
        if not kwargs.get('layers'):
            raise KeyError('layers not declared (like "layers=[\'*.Cu\', \'*.Mask\', \'F.SilkS\']")')
        self.layers = kwargs.get('layers')

    def _initRadiusRatio(self, **kwargs):
        if('round_radius_handler' in kwargs):
            self.round_radius_handler = kwargs['round_radius_handler']
        else:
            self.round_radius_handler = RoundRadiusHandler(**kwargs)

        self.radius_ratio = self.round_radius_handler.getRadiusRatio(min(self.size))

        if self.radius_ratio == 0:
            self.shape = Pad.SHAPE_RECT

    def _initAnchorShape(self, **kwargs):
        self.anchor_shape = kwargs.get('anchor_shape', Pad.ANCHOR_CIRCLE)
        if self.anchor_shape not in Pad._ANCHOR_SHAPE:
            raise ValueError('{shape} is an illegal anchor shape'.format(shape=self.anchor_shape))

    def _initShapeInZone(self, **kwargs):
        self.shape_in_zone = kwargs.get('shape_in_zone', Pad.SHAPE_IN_ZONE_OUTLINE)
        if self.shape_in_zone not in Pad._SHAPE_IN_ZONE:
            raise ValueError('{shape} is an illegal specifier for the shape in zone option'
                             .format(shape=self.shape_in_zone))

    def rotate(self, angle, origin=(0, 0), use_degrees=True):
        r""" Rotate pad around given origin

        :params:
            * *angle* (``float``)
                rotation angle
            * *origin* (``Vector2D``)
                origin point for the rotation. default: (0, 0)
            * *use_degrees* (``boolean``)
                rotation angle is given in degrees. default:True
        """

        self.at.rotate(angle=angle, origin=origin, use_degrees=use_degrees)
        a = angle if use_degrees else math.degrees(angle)

        # subtraction because kicad text field rotation is the wrong way round
        self.rotation -= a
        return self

    def translate(self, distance_vector):
        r""" Translate pad

        :params:
            * *distance_vector* (``Vector2D``)
                2D vector defining by how much and in what direction to translate.
        """

        self.at += distance_vector
        return self

    # calculate the outline of a pad
    def calculateBoundingBox(self):
        return Node.calculateBoundingBox(self)

    def _getRenderTreeText(self):
        render_strings = ['pad']
        render_strings.append(lispString(self.number))
        render_strings.append(lispString(self.type))
        render_strings.append(lispString(self.shape))
        render_strings.append(self.at.render('(at {x} {y})'))
        render_strings.append(self.size.render('(size {x} {y})'))
        render_strings.append('(drill {})'.format(self.drill))
        render_strings.append('(layers {})'.format(' '.join(self.layers)))

        render_text = Node._getRenderTreeText(self)
        render_text += '({})'.format(' '.join(render_strings))

        return render_text

    def addPrimitive(self, p):
        r""" add a primitve to a custom pad

        :param p: the primitive to add
        """
        self.primitives.append(p)

    def getRoundRadius(self):
        if self.shape == Pad.SHAPE_CUSTOM:
            r_max = 0
            for p in self.primitives:
                r = p.width/2
                if r > r_max:
                    r_max = r
            return r_max
        return self.round_radius_handler.getRoundRadius(min(self.size))


================================================
FILE: KicadModTree/nodes/base/Polygon.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2018 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.PolygonPoints import *
from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node


class Polygon(Node):
    r"""Add a Polygon to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *polygon* (``list(Point)``) --
          outer nodes of the polygon
        * *layer* (``str``) --
          layer on which the line is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the line (default: None, which means auto detection)
        * *x_mirror* (``[int, float](mirror offset)``) --
          mirror x direction around offset "point"
        * *y_mirror* (``[int, float](mirror offset)``) --
          mirror y direction around offset "point"

    :Example:

    >>> from KicadModTree import *
    >>> Polygon(nodes=[[-2, 0], [0, -2], [4, 0], [0, 2]], layer='F.SilkS')
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.nodes = PolygonPoints(**kwargs)

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

    def rotate(self, angle, origin=(0, 0), use_degrees=True):
        r""" Rotate polygon around given origin

        :params:
            * *angle* (``float``)
                rotation angle
            * *origin* (``Vector2D``)
                origin point for the rotation. default: (0, 0)
            * *use_degrees* (``boolean``)
                rotation angle is given in degrees. default:True
        """

        self.nodes.rotate(angle=angle, origin=origin, use_degrees=use_degrees)
        return self

    def translate(self, distance_vector):
        r""" Translate polygon

        :params:
            * *distance_vector* (``Vector2D``)
                2D vector defining by how much and in what direction to translate.
        """

        self.nodes.translate(distance_vector)
        return self

    def calculateBoundingBox(self):
        return nodes.calculateBoundingBox()

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)
        render_text += " [nodes: ["

        node_strings = []
        for n in self.nodes:
            node_strings.append("[x: {x}, y: {y}]".format(x=n.x, y=n.y))

        if len(node_strings) <= 6:
            render_text += ", ".join(node_strings)
        else:
            # display only a few nodes of the beginning and the end of the polygone line
            render_text += ", ".join(node_strings[:3])
            render_text += ",... , "
            render_text += ", ".join(node_strings[-3:])

        render_text += "]"

        return render_text

    def cut(self, other):
        r""" Cut other polygon from this polygon

        More details see PolygonPoints.cut docstring.

        :param other: the other polygon
        """
        self.nodes.cut(other.nodes)


================================================
FILE: KicadModTree/nodes/base/Text.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node


class Text(Node):
    r"""Add a Line to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *type* (``str``) --
          type of text
        * *text* (``str``) --
          text which is been visualized
        * *at* (``Vector2D``) --
          position of text
        * *rotation* (``float``) --
          rotation of text (default: 0)
        * *mirror* (``bool``) --
          mirror text (default: False)
        * *layer* (``str``) --
          layer on which the text is drawn (default: 'F.SilkS')
        * *size* (``Vector2D``) --
          size of the text (default: [1, 1])
        * *thickness* (``float``) --
          thickness of the text (default: 0.15)
        * *hide* (``bool``) --
          hide text (default: False)

    :Example:

    >>> from KicadModTree import *
    >>> Text(type='reference', text='REF**', at=[0, -3], layer='F.SilkS')
    >>> Text(type='value', text="footprint name", at=[0, 3], layer='F.Fab')
    >>> Text(type='user', text='test', at=[0, 0], layer='Cmts.User')
    """

    TYPE_REFERENCE = 'reference'
    TYPE_VALUE = 'value'
    TYPE_USER = 'user'
    _TYPES = [TYPE_REFERENCE, TYPE_VALUE, TYPE_USER]

    def __init__(self, **kwargs):
        Node.__init__(self)
        self._initType(**kwargs)

        self.text = kwargs['text']
        self.at = Vector2D(kwargs['at'])
        self.rotation = kwargs.get('rotation', 0)
        self.mirror = kwargs.get('mirror', False)

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.size = Vector2D(kwargs.get('size', [1, 1]))
        self.thickness = kwargs.get('thickness', 0.15)

        self.hide = kwargs.get('hide', False)

    def _initType(self, **kwargs):
        self.type = kwargs['type']
        if self.type not in Text._TYPES:
            raise ValueError('Illegal type selected for text field.')

    def rotate(self, angle, origin=(0, 0), use_degrees=True):
        r""" Rotate text around given origin

        :params:
            * *angle* (``float``)
                rotation angle
            * *origin* (``Vector2D``)
                origin point for the rotation. default: (0, 0)
            * *use_degrees* (``boolean``)
                rotation angle is given in degrees. default:True
        """

        self.at.rotate(angle=angle, origin=origin, use_degrees=use_degrees)
        a = angle if use_degrees else math.degrees(angle)

        # subtraction because kicad text field rotation is the wrong way round
        self.rotation -= a
        return self

    def translate(self, distance_vector):
        r""" Translate text

        :params:
            * *distance_vector* (``Vector2D``)
                2D vector defining by how much and in what direction to translate.
        """

        self.at += distance_vector
        return self

    def calculateBoundingBox(self):
        width = len(self.text)*self.size['x']
        height = self.size['y']

        min_x = self.at['x']-width/2.
        min_y = self.at['y']-height/2.
        max_x = self.at['x']+width/2.
        max_y = self.at['y']+height/2.

        return Node.calculateBoundingBox({'min': Vector2D(min_x, min_y), 'max': Vector2D(max_x, max_y)})

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)

        render_string = ['type: "{}"'.format(self.type),
                         'text: "{}"'.format(self.text),
                         'at: {}'.format(self.at.render('(at {x} {y})')),
                         'layer: {}'.format(self.layer),
                         'size: {}'.format(self.size.render('(size {x} {y})')),
                         'thickness: {}'.format(self.thickness)]

        render_text += " [{}]".format(", ".join(render_string))

        return render_text


================================================
FILE: KicadModTree/nodes/base/__init__.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016-2018 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from .Arc import Arc

from .Circle import Circle

from .Line import Line

from .Model import Model

from .Pad import Pad

from .Polygon import Polygon

from .Text import Text


================================================
FILE: KicadModTree/nodes/specialized/ChamferedPad.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
# (C) 2018 by Rene Poeschl, github @poeschlr
from __future__ import division

from copy import copy
from KicadModTree.util.paramUtil import *
from KicadModTree.Vector import *
from KicadModTree.nodes.base.Polygon import *
from KicadModTree.nodes.base.Pad import Pad, RoundRadiusHandler
from math import sqrt


class CornerSelection():
    r"""Class for handling chamfer selection
        :param chamfer_select:
            * A list of bools do directly set the corners
              (top left, top right, bottom right, bottom left)
            * A dict with keys (constands see below)
            * The integer 1 means all corners
            * The integer 0 means no corners

        :constants:
            * CornerSelection.TOP_LEFT
            * CornerSelection.TOP_RIGHT
            * CornerSelection.BOTTOM_RIGHT
            * CornerSelection.BOTTOM_LEFT
    """

    TOP_LEFT = 'tl'
    TOP_RIGHT = 'tr'
    BOTTOM_RIGHT = 'br'
    BOTTOM_LEFT = 'bl'

    def __init__(self, chamfer_select):
        self.top_left = False
        self.top_right = False
        self.bottom_right = False
        self.bottom_left = False

        if chamfer_select == 1:
            self.selectAll()
            return

        if chamfer_select == 0:
            return

        if type(chamfer_select) is dict:
            for key in chamfer_select:
                self[key] = bool(chamfer_select[key])
        else:
            for i, value in enumerate(chamfer_select):
                self[i] = bool(value)

    def selectAll(self):
        for i in range(len(self)):
            self[i] = True

    def clearAll(self):
        for i in range(len(self)):
            self[i] = False

    def setLeft(self, value=1):
        self.top_left = bool(value)
        self.bottom_left = bool(value)

    def setTop(self, value=1):
        self.top_left = bool(value)
        self.top_right = bool(value)

    def setRight(self, value=1):
        self.top_right = bool(value)
        self.bottom_right = bool(value)

    def setBottom(self, value=1):
        self.bottom_left = bool(value)
        self.bottom_right = bool(value)

    def isAnySelected(self):
        for v in self:
            if v:
                return True
        return False

    def rotateCW(self):
        top_left_old = self.top_left

        self.top_left = self.bottom_left
        self.bottom_left = self.bottom_right
        self.bottom_right = self.top_right
        self.top_right = top_left_old
        return self

    def rotateCCW(self):
        top_left_old = self.top_left

        self.top_left = self.top_right
        self.top_right = self.bottom_right
        self.bottom_right = self.bottom_left
        self.bottom_left = top_left_old
        return self

    def __or__(self, other):
        return CornerSelection([s or o for s, o in zip(self, other)])

    def __ior__(self, other):
        for i in range(len(self)):
            self[i] |= other[i]
        return self

    def __and__(self, other):
        return CornerSelection([s and o for s, o in zip(self, other)])

    def __iand__(self, other):
        for i in range(len(self)):
            self[i] &= other[i]
        return self

    def __len__(self):
        return 4

    def __iter__(self):
        yield self.top_left
        yield self.top_right
        yield self.bottom_right
        yield self.bottom_left

    def __getitem__(self, item):
        if item in [0, CornerSelection.TOP_LEFT]:
            return self.top_left
        if item in [1, CornerSelection.TOP_RIGHT]:
            return self.top_right
        if item in [2, CornerSelection.BOTTOM_RIGHT]:
            return self.bottom_right
        if item in [3, CornerSelection.BOTTOM_LEFT]:
            return self.bottom_left

        raise IndexError('Index {} is out of range'.format(item))

    def __setitem__(self, item, value):
        if item in [0, CornerSelection.TOP_LEFT]:
            self.top_left = bool(value)
        elif item in [1, CornerSelection.TOP_RIGHT]:
            self.top_right = bool(value)
        elif item in [2, CornerSelection.BOTTOM_RIGHT]:
            self.bottom_right = bool(value)
        elif item in [3, CornerSelection.BOTTOM_LEFT]:
            self.bottom_left = bool(value)
        else:
            raise IndexError('Index {} is out of range'.format(item))

    def to_dict(self):
        return {
            CornerSelection.TOP_LEFT: self.top_left,
            CornerSelection.TOP_RIGHT: self.top_right,
            CornerSelection.BOTTOM_RIGHT: self.bottom_right,
            CornerSelection.BOTTOM_LEFT: self.bottom_left
            }

    def __str__(self):
        return str(self.to_dict())


class ChamferedPad(Node):
    r"""Add a ChamferedPad to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *number* (``int``, ``str``) --
          number/name of the pad (default: \"\")
        * *type* (``Pad.TYPE_THT``, ``Pad.TYPE_SMT``, ``Pad.TYPE_CONNECT``, ``Pad.TYPE_NPTH``) --
          type of the pad
        * *at* (``Vector2D``) --
          center position of the pad
        * *rotation* (``float``) --
          rotation of the pad
        * *size* (``float``, ``Vector2D``) --
          size of the pad
        * *offset* (``Vector2D``) --
          offset of the pad
        * *drill* (``float``, ``Vector2D``) --
          drill-size of the pad
        * *solder_paste_margin_ratio* (``float``) --
          solder paste margin ratio of the pad (default: 0)
        * *solder_paste_margin* (``float``) --
          solder paste margin of the pad (default: 0)
        * *solder_mask_margin* (``float``) --
          solder mask margin of the pad (default: 0)
        * *layers* (``Pad.LAYERS_SMT``, ``Pad.LAYERS_THT``, ``Pad.LAYERS_NPTH``) --
          layers on which are used for the pad
        * *corner_selection* (``CornerSelection``) --
          Select which corner(s) to chamfer. (top left, top right, bottom right, bottom left)
        * *chamfer_size* (``float``, ``Vector2D``) --
          Size of the chamfer.
        * *x_mirror* (``[int, float](mirror offset)``) --
          mirror x direction around offset "point"
        * *y_mirror* (``[int, float](mirror offset)``) --
          mirror y direction around offset "point"

        * *radius_ratio* (``float``) --
          The radius ratio of the rounded rectangle.
          (default 0 for backwards compatibility)
        * *maximum_radius* (``float``) --
          The maximum radius for the rounded rectangle.
          If the radius produced by the radius_ratio parameter for the pad would
          exceed the maximum radius, the ratio is reduced to limit the radius.
          (This is useful for IPC-7351C compliance as it suggests 25% ratio with limit 0.25mm)
        * *round_radius_exact* (``float``) --
          Set an exact round radius for a pad.
        * *round_radius_handler* (``RoundRadiusHandler``) --
          An instance of the RoundRadiusHandler class
          If this is given then all other round radius specifiers are ignored
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        self._initPosition(**kwargs)
        self._initSize(**kwargs)
        self._initMirror(**kwargs)
        self._initPadSettings(**kwargs)

        self.pad = self._generatePad()

    def _initSize(self, **kwargs):
        if not kwargs.get('size'):
            raise KeyError('pad size not declared (like "size=[1,1]")')
        self.size = toVectorUseCopyIfNumber(kwargs.get('size'), low_limit=0)

    def _initPosition(self, **kwargs):
        if 'at' not in kwargs:
            raise KeyError('center position not declared (like "at=[0,0]")')
        self.at = Vector2D(kwargs.get('at'))

    def _initMirror(self, **kwargs):
        self.mirror = {}
        if 'x_mirror' in kwargs and type(kwargs['x_mirror']) in [float, int]:
            self.mirror['x_mirror'] = kwargs['x_mirror']
        if 'y_mirror' in kwargs and type(kwargs['y_mirror']) in [float, int]:
            self.mirror['y_mirror'] = kwargs['y_mirror']

    def _initPadSettings(self, **kwargs):
        if 'corner_selection' not in kwargs:
            raise KeyError('corner selection is required for chamfered pads (like "corner_selection=[1,0,0,0]")')

        self.corner_selection = CornerSelection(kwargs.get('corner_selection'))

        if 'chamfer_size' not in kwargs:
            self.chamfer_size = Vector2D(0, 0)
        else:
            self.chamfer_size = toVectorUseCopyIfNumber(
                kwargs.get('chamfer_size'), low_limit=0, must_be_larger=False)

        if('round_radius_handler' in kwargs):
            self.round_radius_handler = kwargs['round_radius_handler']
        else:
            # default radius ration 0 for backwards compatibility
            self.round_radius_handler = RoundRadiusHandler(default_radius_ratio=0, **kwargs)

        self.padargs = copy(kwargs)
        self.padargs.pop('size', None)
        self.padargs.pop('shape', None)
        self.padargs.pop('at', None)
        self.padargs.pop('round_radius_handler', None)

    def _generatePad(self):
        if self.chamfer_size[0] >= self.size[0] or self.chamfer_size[1] >= self.size[1]:
            raise ValueError('Chamfer size ({}) too large for given pad size ({})'.format(self.chamfer_size, self.size))

        is_chamfered = False
        if self.corner_selection.isAnySelected() and self.chamfer_size[0] > 0 and self.chamfer_size[1] > 0:
            is_chamfered = True

        radius = self.round_radius_handler.getRoundRadius(min(self.size))

        if is_chamfered:
            outside = Vector2D(self.size.x/2, self.size.y/2)

            inside = [Vector2D(outside.x, outside.y-self.chamfer_size.y),
                      Vector2D(outside.x-self.chamfer_size.x, outside.y)
                      ]

            polygon_width = 0
            if self.round_radius_handler.roundingRequested():
                if self.chamfer_size[0] != self.chamfer_size[1]:
                    raise NotImplementedError(
                            'Rounded chamfered pads are only supported for 45 degree chamfers.'
                            ' Chamfer {}'.format(self.chamfer_size)
                            )
                # We prefer the use of rounded rectangle over chamfered pads.
                r_chamfer = self.chamfer_size[0] + sqrt(2)*self.chamfer_size[0]/2
                if radius >= r_chamfer:
                    is_chamfered = False
                elif radius > 0:
                    shortest_sidlength = min(min(self.size-self.chamfer_size), self.chamfer_size[0]*sqrt(2))
                    if radius > shortest_sidlength/2:
                        radius = shortest_sidlength/2
                    polygon_width = radius*2
                    outside -= radius
                    inside[0].y -= radius*(2/sqrt(2)-1)
                    inside[0].x -= radius
                    inside[1].x -= radius*(2/sqrt(2)-1)
                    inside[1].y -= radius

        if is_chamfered:
            points = []
            corner_vectors = [
                Vector2D(-1, -1), Vector2D(1, -1), Vector2D(1, 1), Vector2D(-1, 1)
                ]
            for i in range(4):
                if self.corner_selection[i]:
                    points.append(corner_vectors[i]*inside[i % 2])
                    points.append(corner_vectors[i]*inside[(i+1) % 2])
                else:
                    points.append(corner_vectors[i]*outside)

            primitives = [Polygon(nodes=points, width=polygon_width, **self.mirror)]
            # TODO make size calculation more resilient
            size = min(self.size.x, self.size.y)-max(self.chamfer_size[0], self.chamfer_size[1])/sqrt(2)
            if size <= 0:
                raise ValueError('Anchor pad size calculation failed.'
                                 'Chamfer size ({}) to large for given pad size ({})'
                                 .format(self.size, self.chamfer_size))
            return Pad(primitives=primitives, at=self.at,
                       shape=Pad.SHAPE_CUSTOM, size=size, **self.padargs)
        else:
            return Pad(
                    at=self.at, shape=Pad.SHAPE_ROUNDRECT, size=self.size,
                    round_radius_handler=self.round_radius_handler, **self.padargs
                )

    def chamferAvoidCircle(self, center, diameter, clearance=0):
        r""" set the chamfer such that the pad avoids a cricle located at near corner.

        :param center: (``Vector2D``) --
           The center of the circle ot avoid
        :param diameter: (``float``, ``Vector2D``) --
           The diameter of the circle. If Vector2D given only x direction is used.
        :param clearance: (``float``) --
           Additional clearance around circle. default:0
        """

        relative_center = Vector2D(center) - self.at
        # pad and circle are symetric so we do not care which corner the
        # reference circle is located at.
        #  -> move it to bottom right to get only positive relative coordinates.
        relative_center = Vector2D([abs(v) for v in relative_center])
        d = diameter if type(diameter) in [float, int] else diameter.x

        # Where should the chamfer be if the center of the reference circle
        # would be in line with the pad edges
        # (meaning exactly at the bottome right corner)
        reference_point = relative_center - sqrt(2)*(clearance+d/2)
        self.chamfer_size = self.size/2 - reference_point

        # compensate for reference circles not placed exactly at the corner
        edge_to_center = relative_center - self.size/2
        self.chamfer_size -= [edge_to_center.y, edge_to_center.x]
        self.chamfer_size = Vector2D([x if x > 0 else 0 for x in self.chamfer_size])

        self.pad = self._generatePad()
        return self.chamfer_size

    def getVirtualChilds(self):
        return [self.pad]

    def getRoundRadius(self):
        return self.pad.getRoundRadius()


================================================
FILE: KicadModTree/nodes/specialized/ChamferedPadGrid.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
# (C) 2018 by Rene Poeschl, github @poeschlr

from __future__ import division

from KicadModTree.util.paramUtil import *
from KicadModTree.Vector import *
from KicadModTree.nodes.base.Polygon import *
from KicadModTree.nodes.specialized.ChamferedPad import *


class ChamferSelPadGrid(CornerSelection):
    r"""Class for handling chamfer selection
        :param chamfer_select:
            * A list of bools do directly set the corners
              (top left, top right, bottom right, bottom left)
            * A dict with keys (Constands see below)
            * The integer 1 means all corners and edges
            * The integer 0 means no corners, no edges

        :constants:
            * ChamferSelPadGrid.TOP_EDGE
            * ChamferSelPadGrid.RIGHT_EDGE
            * ChamferSelPadGrid.BOTTOM_EDGE
            * ChamferSelPadGrid.LEFT_EDGE
            * Plus all constands inherited from CornerSelection

    """

    TOP_EDGE = "t"
    RIGHT_EDGE = "r"
    BOTTOM_EDGE = "b"
    LEFT_EDGE = "l"

    def __init__(self, chamfer_select):
        self.top_edge = False
        self.right_edge = False
        self.bottom_edge = False
        self.left_edge = False

        if chamfer_select == 1:
            self.selectAll()
            CornerSelection.__init__(self, 1)
            return

        if chamfer_select == 0:
            CornerSelection.__init__(self, 0)
            return

        if type(chamfer_select) is dict:
            CornerSelection.__init__(self, chamfer_select)
            for key in chamfer_select:
                self[key] = bool(chamfer_select[key])
        else:
            for i, value in enumerate(chamfer_select):
                self[i] = bool(value)

    def setLeft(self, value=1):
        CornerSelection.setLeft(self, value)
        self.left_edge = bool(value)

    def setTop(self, value=1):
        CornerSelection.setTop(self, value)
        self.top_edge = bool(value)

    def setRight(self, value=1):
        CornerSelection.setRight(self, value)
        self.right_edge = bool(value)

    def setBottom(self, value=1):
        CornerSelection.setBottom(self, value)
        self.bottom_edge = bool(value)

    def setCorners(self, value=1):
        self.top_left = bool(value)
        self.top_right = bool(value)
        self.bottom_right = bool(value)
        self.bottom_left = bool(value)

    def setEdges(self, value=1):
        self.top_edge = bool(value)
        self.right_edge = bool(value)
        self.bottom_edge = bool(value)
        self.left_edge = bool(value)

    def __len__(self):
        return 8

    def __iter__(self):
        for v in CornerSelection.__iter__(self):
            yield v
        yield self.top_edge
        yield self.right_edge
        yield self.bottom_edge
        yield self.left_edge

    def __getitem__(self, item):
        if item in [4, ChamferSelPadGrid.TOP_EDGE]:
            return self.top_edge
        if item in [5, ChamferSelPadGrid.RIGHT_EDGE]:
            return self.right_edge
        if item in [6, ChamferSelPadGrid.BOTTOM_EDGE]:
            return self.bottom_edge
        if item in [7, ChamferSelPadGrid.LEFT_EDGE]:
            return self.left_edge
        return CornerSelection.__getitem__(self, item)

    def __setitem__(self, item, value):
        if item in [4, ChamferSelPadGrid.TOP_EDGE]:
            self.top_edge = bool(value)
        elif item in [5, ChamferSelPadGrid.RIGHT_EDGE]:
            self.right_edge = bool(value)
        elif item in [6, ChamferSelPadGrid.BOTTOM_EDGE]:
            self.bottom_edge = bool(value)
        elif item in [7, ChamferSelPadGrid.LEFT_EDGE]:
            self.left_edge = bool(value)
        else:
            CornerSelection.__setitem__(self, item, value)

    def to_dict(self):
        result = CornerSelection.to_dict(self)
        result.update({
            ChamferSelPadGrid.TOP_EDGE: self.top_edge,
            ChamferSelPadGrid.RIGHT_EDGE: self.right_edge,
            ChamferSelPadGrid.BOTTOM_EDGE: self.bottom_edge,
            ChamferSelPadGrid.LEFT_EDGE: self.left_edge
            })
        return result


class ChamferedPadGrid(Node):
    r"""Add a ChamferedPad to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *number* (``int``, ``str``) --
          number/name of the pad (default: \"\")
        * *center* (``Vector2D``) --
          center position of the pad grid
        * *size* (``float``, ``Vector2D``) --
          size of the pads
        * *pincount* (``int``, ``[int, int]``)
          Pad count in x and y direction.
          If only one integer is given, it will be used for both directions.
        * *grid* (``float``, ``Vector2D``)
          Pad grid in x and y direction.
          If only one float is given, it will be used for both directions.

        * *solder_paste_margin_ratio* (``float``) --
          solder paste margin ratio of the pad (default: 0)
        * *solder_paste_margin* (``float``) --
          solder paste margin of the pad (default: 0)
        * *solder_mask_margin* (``float``) --
          solder mask margin of the pad (default: 0)

        * *layers* (``Pad.LAYERS_SMT``, ``Pad.LAYERS_THT``, ``Pad.LAYERS_NPTH``) --
          layers on which are used for the pad
        * *chamfer_selection* (``ChamferSelPadGrid``) --
          Select which corner and edge pads to chamfer.
        * *chamfer_size* (``float``, ``Vector2D``) --
          Size of the chamfer.
        * *x_mirror* (``[int, float](mirror offset)``) --
          mirror x direction around offset "point"
        * *y_mirror* (``[int, float](mirror offset)``) --
          mirror y direction around offset "point"

        * *radius_ratio* (``float``) --
          The radius ratio of the rounded rectangle.
          (default 0 for backwards compatibility)
        * *maximum_radius* (``float``) --
          The maximum radius for the rounded rectangle.
          If the radius produced by the radius_ratio parameter for the pad would
          exceed the maximum radius, the ratio is reduced to limit the radius.
          (This is useful for IPC-7351C compliance as it suggests 25% ratio with limit 0.25mm)
        * *round_radius_exact* (``float``) --
          Set an exact round radius for a pad.
        * *round_radius_handler* (``RoundRadiusHandler``) --
          An instance of the RoundRadiusHandler class
          If this is given then all other round radius specifiers are ignored
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        if len(kwargs) == 0:
            return

        self.number = kwargs.get('number', "")
        self.center = Vector2D(kwargs.get('center', [0, 0]))

        self._initSize(**kwargs)
        self._initCount(**kwargs)
        self._initGrid(**kwargs)
        self._initPadSettings(**kwargs)

    def _initCount(self, **kwargs):
        if 'pincount' not in kwargs:
            raise KeyError('pincount not declared (like "pincount=10")')

        self.pincount = toIntArray(kwargs['pincount'])

    def _initSize(self, **kwargs):
        if 'size' not in kwargs:
            raise KeyError('size not declared (like "size=[1, 2]")')

        self.size = toVectorUseCopyIfNumber(kwargs['size'], low_limit=0)

    def _initGrid(self, **kwargs):
        if 'grid' not in kwargs:
            raise KeyError('grid not declared (like "grid=[1, 2]")')

        self.grid = toVectorUseCopyIfNumber(kwargs['grid'], low_limit=self.size)

    def _initPadSettings(self, **kwargs):
        if 'chamfer_selection' not in kwargs:
            raise KeyError('chamfer selection is required for chamfered pads (like "chamfer_selection=[1,0,0,0]")')

        self.chamfer_selection = ChamferSelPadGrid(kwargs.get('chamfer_selection'))

        if 'chamfer_size' not in kwargs:
            self.chamfer_size = Vector2D(0, 0)
        else:
            self.chamfer_size = toVectorUseCopyIfNumber(
                kwargs.get('chamfer_size'), low_limit=0, must_be_larger=False)

        if('round_radius_handler' in kwargs):
            self.round_radius_handler = kwargs['round_radius_handler']
        else:
            # default radius ration 0 for backwards compatibility
            self.round_radius_handler = RoundRadiusHandler(default_radius_ratio=0, **kwargs)

        self.padargs = copy(kwargs)
        self.padargs.pop('size', None)
        self.padargs.pop('number', None)
        self.padargs.pop('at', None)
        self.padargs.pop('chamfer_size', None)
        self.padargs.pop('round_radius_handler', None)

    def chamferAvoidCircle(self, center, diameter, clearance=0):
        r""" set the chamfer such that the pad avoids a cricle located at near corner.

        :param center: (``Vector2D``) --
           The center of the circle ot avoid
        :param diameter: (``float``, ``Vector2D``) --
           The diameter of the circle. If Vector2D given only x direction is used.
        :param clearance: (``float``) --
           Additional clearance around circle. default:0
        """
        relative_center = Vector2D(center) - self.center

        left = -self.grid['x']*(self.pincount[0]-1)/2
        top = -self.grid['y']*(self.pincount[1]-1)/2

        nearest_x = left
        nearest_y = top

        min_dist_x = abs(relative_center['x']-nearest_x)
        min_dist_y = abs(relative_center['y']-nearest_y)

        for i in range(self.pincount[0]):
            x = left+i*self.grid['x']
            dx = abs(x-relative_center['x'])
            if dx < min_dist_x:
                min_dist_x = dx
                nearest_x = x

        for i in range(self.pincount[1]):
            y = top+i*self.grid['y']
            dy = abs(y-relative_center['y'])
            if dy < min_dist_y:
                min_dist_y = dy
                nearest_y = y

        temp_pad = ChamferedPad(
            at=[nearest_x, nearest_y], size=self.size,
            type=Pad.TYPE_SMT, layers=['F.Cu'], corner_selection=1
        )
        self.chamfer_size = temp_pad.chamferAvoidCircle(
            center=relative_center, diameter=diameter, clearance=clearance)
        return self.chamfer_size

    def __padCornerSelection(self, idx_x, idx_y):
        corner = CornerSelection(0)
        if idx_x == 0:
            if idx_y == 0:
                if self.chamfer_selection[ChamferSelPadGrid.TOP_LEFT]:
                    corner[CornerSelection.TOP_LEFT] = True
                if self.chamfer_selection[ChamferSelPadGrid.LEFT_EDGE]:
                    corner[CornerSelection.BOTTOM_LEFT] = True
            if idx_y == self.pincount[1]-1:
                if self.chamfer_selection[ChamferSelPadGrid.BOTTOM_LEFT]:
                    corner[CornerSelection.BOTTOM_LEFT] = True
                if self.chamfer_selection[ChamferSelPadGrid.LEFT_EDGE]:
                    corner[CornerSelection.TOP_LEFT] = True
            if idx_y != 0 and idx_y != self.pincount[1]-1:
                if self.chamfer_selection[ChamferSelPadGrid.LEFT_EDGE]:
                    corner.setLeft()
        if idx_x == self.pincount[0]-1:
            if idx_y == 0:
                if self.chamfer_selection[ChamferSelPadGrid.TOP_RIGHT]:
                    corner[CornerSelection.TOP_RIGHT] = True
                if self.chamfer_selection[ChamferSelPadGrid.RIGHT_EDGE]:
                    corner[CornerSelection.BOTTOM_RIGHT] = True
            if idx_y == self.pincount[1]-1:
                if self.chamfer_selection[ChamferSelPadGrid.BOTTOM_RIGHT]:
                    corner[CornerSelection.BOTTOM_RIGHT] = True
                if self.chamfer_selection[ChamferSelPadGrid.RIGHT_EDGE]:
                    corner[CornerSelection.TOP_RIGHT] = True
            if idx_y != 0 and idx_y != self.pincount[1]-1:
                if self.chamfer_selection[ChamferSelPadGrid.RIGHT_EDGE]:
                    corner.setRight()
        if idx_x != 0 and idx_x != self.pincount[0]-1:
            if idx_y == 0:
                if self.chamfer_selection[ChamferSelPadGrid.TOP_EDGE]:
                    corner.setTop()
            if idx_y == self.pincount[1]-1:
                if self.chamfer_selection[ChamferSelPadGrid.BOTTOM_EDGE]:
                    corner.setBottom()
        return corner

    def _generatePads(self):
        left = -self.grid['x']*(self.pincount[0]-1)/2+self.center['x']
        top = -self.grid['y']*(self.pincount[1]-1)/2+self.center['y']

        pads = []
        for idx_x in range(self.pincount[0]):
            x = left+idx_x*self.grid['x']
            for idx_y in range(self.pincount[1]):
                y = top+idx_y*self.grid['y']
                corner = self.__padCornerSelection(idx_x, idx_y)
                pads.append(ChamferedPad(
                    at=[x, y], number=self.number, size=self.size,
                    chamfer_size=self.chamfer_size,
                    corner_selection=corner,
                    round_radius_handler=self.round_radius_handler,
                    **self.padargs
                    ))
        return pads

    def getVirtualChilds(self):
        return self._generatePads()

    def __copy__(self):
        newone = type(self)()
        newone.__dict__.update(self.__dict__)
        return newone


================================================
FILE: KicadModTree/nodes/specialized/ExposedPad.py
================================================
#!/usr/bin/env python

# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2017 by @SchrodingersGat
# (C) 2017 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
# (C) 2018 by Rene Poeschl, github @poeschlr

from __future__ import division

from KicadModTree.util.paramUtil import *
from KicadModTree.nodes.base.Pad import *
from KicadModTree.nodes.specialized.ChamferedPadGrid import *
from KicadModTree.nodes.specialized.PadArray import *
from KicadModTree.nodes.Node import Node
from math import sqrt, floor
from copy import copy
import traceback


class ExposedPad(Node):
    r"""Add an exposed pad

    Complete with correct paste, mask and via handling

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *number* (``int``, ``str``) --
          number/name of the pad
        * *at* (``Vector2D``) --
          center the exposed pad around this point (default: 0,0)
        * *size* (``float``, ``Vector2D``) --
          size of the pad
        * *solder_mask_margin* (``float``) --
          solder mask margin of the pad (default: 0)
          Only used if mask_size is not specified.
        * *mask_size* (``float``, ``Vector2D``) --
          size of the mask cutout (If not given, mask will be part of the main pad)

        * *paste_layout* (``int``, ``[int, int]``) --
          paste layout specification.
          How many pads in x and y direction.
          If only a single integer given, x and y direction use the same count.
        * *paste_between_vias* (``int``, ``[int, int]``)
          Alternative for paste_layout with more controll.
          This defines how many pads will be between 4 vias in x and y direction.
          If only a single integer given, x and y direction use the same count.
        * *paste_rings_outside* (``int``, ``[int, int]``)
          Alternative for paste_layout with more controll.
          Defines the number of rings outside of the vias in x and y direction.
          If only a single integer given, x and y direction use the same count.
        * *paste_coverage* (``float``) --
          how much of the mask free area is covered with paste. (default: 0.65)

        * *via_layout* (``int``, ``[int, int]``) --
          thermal via layout specification.
          How many vias in x and y direction.
          If only a single integer given, x and y direction use the same count.
          default: no vias added
        * *via_grid* (``int``, ``Vector2D``) --
          thermal via grid specification.
          Grid used for thermal vias in x and y direction.
          If only a single integer given, x and y direction use the same count.
          If none is given then the via grid will be automatically calculated
          to have them distributed across the main pad.
        * *via_drill* (``float``) --
          via drill diameter (default: 0.3)
        * *via_tented* (VIA_TENTED, VIA_TENTED_TOP_ONLY, VIA_TENTED_BOTTOM_ONLY, VIA_NOT_TENTED) --
          Determines which side of the thermal vias is covered in soldermask.
          On the top only vias outside the defined mask area can be covered in soldermask.
          default: VIA_TENTED
        * *min_annular_ring* (``float``) --
          Anullar ring for thermal vias. (default: 0.15)
        * *bottom_pad_Layers* (``[layer string]``) --
          Select layers for the bottom pad (default: [B.Cu]) --
          Ignored if no thermal vias are added.
          If None or empty no pad is added.
        * *bottom_pad_min_size* (``float``, ``Vector2D``) --
          Minimum size for bottom pad. default: (0,0)
          Ignored if no bottom pad given.
        * *paste_avoid_via* (``bool``) --
          Paste automatically generated to avoid vias (default: false)
        * *via_paste_clarance* (``float``)
          Clearance between paste and via drills (default: 0.05)
          Only used if paste_avoid_via is set.

        * *grid_round_base* (``float``) --
          Base used for rounding calculated grids (default: 0.01)
          0 means no rounding
        * *size_round_base* (``float``) --
          Base used for rounding calculated sizes (default: 0.01)
          0 means no rounding

        * *radius_ratio* (``float``) --
          The radius ratio of the main pads.
        * *maximum_radius* (``float``) --
          The maximum radius for the main pads.
          If the radius produced by the radius_ratio parameter for the pad would
          exceed the maximum radius, the ratio is reduced to limit the radius.
        * *round_radius_exact* (``float``) --
          Set an exact round radius for the main pads.

        * *paste_radius_ratio* (``float``) --
          The radius ratio of the paste pads.
        * *paste_maximum_radius* (``float``) --
          The maximum radius for the paste pads.
          If the radius produced by the paste_radius_ratio parameter for the paste pad would
          exceed the maximum radius, the ratio is reduced to limit the radius.
        * *paste_round_radius_exact* (``float``) --
          Set an exact round radius for the paste pads.

        * *kicad4_compatible* (``bool``) --
          Makes sure the resulting pad is compatible with kicad 4. default False
    """

    VIA_TENTED = 'all'
    VIA_TENTED_TOP_ONLY = 'top'
    VIA_TENTED_BOTTOM_ONLY = 'bottom'
    VIA_NOT_TENTED = 'none'

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.at = Vector2D(kwargs.get('at', [0, 0]))
        self.size_round_base = kwargs.get('size_round_base', 0.01)
        self.grid_round_base = kwargs.get('grid_round_base', 0.01)

        self.round_radius_handler = RoundRadiusHandler(default_radius_ratio=0, **kwargs)

        self.kicad4_compatible = kwargs.get('kicad4_compatible', False)
        self.paste_round_radius_handler = RoundRadiusHandler(
                radius_ratio=kwargs.get('paste_radius_ratio', 0),
                maximum_radius=kwargs.get('paste_maximum_radius', None),
                round_radius_exact=kwargs.get('paste_round_radius_exact', None),
                kicad4_compatible=self.kicad4_compatible
            )

        self._initNumber(**kwargs)
        self._initSize(**kwargs)
        self._initThermalVias(**kwargs)
        self._initPaste(**kwargs)

    def _initNumber(self, **kwargs):
        if not kwargs.get('number'):
            raise KeyError('pad number for exposed pad not declared (like "number=9")')
        self.number = kwargs.get('number')

    def _initSize(self, **kwargs):
        if not kwargs.get('size'):
            raise KeyError('pad size not declared (like "size=[1,1]")')
        self.size = toVectorUseCopyIfNumber(kwargs.get('size'))

        if not kwargs.get('mask_size'):
            self.mask_size = self.size
        else:
            self.mask_size = toVectorUseCopyIfNumber(kwargs.get('mask_size'))

    def setViaLayout(self, layout):
        self.has_vias = True
        self.via_layout = toIntArray(layout, min_value=0)
        if self.via_layout[0] == 0 or self.via_layout[1] == 0:
            self.has_vias = False
        return self.has_vias

    def __initViaGrid(self, **kwargs):
        nx = self.via_layout[0]-1
        ny = self.via_layout[1]-1

        self.via_grid = kwargs.get('via_grid')
        if self.via_grid is not None:
            self.via_grid = toVectorUseCopyIfNumber(self.via_grid, low_limit=self.via_size)
        else:
            self.via_grid = Vector2D([
                    (self.size.x-self.via_size)/(nx if nx > 0 else 1),
                    (self.size.y-self.via_size)/(ny if ny > 0 else 1)
                ])

        self.via_grid = self.via_grid.round_to(kwargs.get('grid_round_base', 0))

    def _initThermalVias(self, **kwargs):
        if not self.setViaLayout(kwargs.get('via_layout', [0, 0])):
            return

        self.via_drill = kwargs.get('via_drill', 0.3)
        self.via_size = self.via_drill + 2*kwargs.get('min_annular_ring', 0.15)
        self.__initViaGrid(**kwargs)
        self.via_tented = kwargs.get('via_tented', ExposedPad.VIA_TENTED)

        self.bottom_pad_Layers = kwargs.get('bottom_pad_Layers', ['B.Cu'])

        self.add_bottom_pad = True
        if self.bottom_pad_Layers is None or len(self.bottom_pad_Layers) == 0:
            self.add_bottom_pad = False
        else:
            bottom_pad_min_size = toVectorUseCopyIfNumber(kwargs.get('bottom_pad_min_size', [0, 0]))
            self.bottom_size = Vector2D([
                    max((self.via_layout[0]-1)*self.via_grid[0]+self.via_size, bottom_pad_min_size[0]),
                    max((self.via_layout[1]-1)*self.via_grid[1]+self.via_size, bottom_pad_min_size[1])
                ])

    def __viasInMaskCount(self, idx):
        r""" Determine the number of vias within the soldermask area

        :param idx: (``int``) --
           determines if the x or y direction is used.
        """
        if (self.via_layout[idx]-1)*self.via_grid[idx] <= self.paste_area_size[idx]:
            return self.via_layout[idx]
        else:
            return int(self.paste_area_size[idx]//(self.via_grid[idx]))

    def _initPasteForAvoidingVias(self, **kwargs):
        self.via_clarance = kwargs.get('via_paste_clarance', 0.05)

        # check get against none to allow the caller to use None as the sign to ignore these.
        if kwargs.get('paste_between_vias') is not None\
                or kwargs.get('paste_rings_outside')is not None:
            self.paste_between_vias = toIntArray(kwargs.get('paste_between_vias', [0, 0]), min_value=0)
            self.paste_rings_outside = toIntArray(kwargs.get('paste_rings_outside', [0, 0]), min_value=0)
        else:
            default = [l-1 for l in self.via_layout]
            layout = kwargs.get('paste_layout')
            if layout is None:
                # alows initializing with 'paste_layout=None' to force default value
                layout = default
            self.paste_layout = toIntArray(layout)

            # int(floor(paste_count/(vias_in_mask-1)))
            self.paste_between_vias = [p//(v-1) if v > 1 else p//v
                                       for p, v in zip(self.paste_layout, self.vias_in_mask)]
            inner_count = [(v-1)*p for v, p in zip(self.vias_in_mask, self.paste_between_vias)]
            self.paste_rings_outside = [(p-i)//2 for p, i in zip(self.paste_layout, inner_count)]

    def _initPaste(self, **kwargs):
        self.paste_avoid_via = kwargs.get('paste_avoid_via', False)
        self.paste_reduction = sqrt(kwargs.get('paste_coverage', 0.65))

        self.paste_area_size = Vector2D([min(m, c) for m, c in zip(self.mask_size, self.size)])
        if self.has_vias:
            self.vias_in_mask = [self.__viasInMaskCount(i) for i in range(2)]

        if not self.has_vias or not all(self.vias_in_mask):
            self.paste_avoid_via = False

        if self.has_vias and self.paste_avoid_via:
            self._initPasteForAvoidingVias(**kwargs)
        else:
            self.paste_layout = toIntArray(kwargs.get('paste_layout', [1, 1]))

    def __createPasteIgnoreVia(self):
        nx = self.paste_layout[0]
        ny = self.paste_layout[1]

        sx = self.paste_area_size.x
        sy = self.paste_area_size.y

        paste_size = Vector2D([sx*self.paste_reduction/nx, sy*self.paste_reduction/ny])\
            .round_to(self.size_round_base)

        dx = (sx - paste_size[0]*nx)/(nx)
        dy = (sy - paste_size[1]*ny)/(ny)

        paste_grid = Vector2D(
                    [paste_size[0]+dx, paste_size[1]+dy]
                ).round_to(self.grid_round_base)

        return [ChamferedPadGrid(
                    number="", type=Pad.TYPE_SMT,
                    center=self.at, size=paste_size, layers=['F.Paste'],
                    chamfer_size=0, chamfer_selection=0,
                    pincount=self.paste_layout, grid=paste_grid,
                    round_radius_handler=self.paste_round_radius_handler
                    )]

    @staticmethod
    def __createPasteGrids(original, grid, count, center):
        r""" Helper function for creating grids of ChamferedPadGrid sections

        :param original: (``ChamferedPadGrid``) --
           This instance will be shallow copied to create a grid.
        :param grid: (``float``, ``Vector2D``) --
           The spacing between instances
        :param count: (``int``, ``[int, int]``) --
           Determines how many copies will be created in x and y direction.
           If only one number is given, both directions use the same count.
        :parma center: (``float``, ``Vector2D``) --
           Center of the resulting grid of grids.
        """
        pads = []
        top_left = Vector2D(center)-Vector2D(grid)*(Vector2D(count)-1)/2
        for idx_x in range(count[0]):
            x = top_left[0]+idx_x*grid[0]
            for idx_y in range(count[1]):
                y = top_left[1]+idx_y*grid[1]
                pads.append(copy(original))
                pads[-1].center = Vector2D(x, y)
        return pads

    def __createPasteAvoidViasInside(self):
        top_left_area = self.top_left_via+self.via_grid/2
        self.inner_grid = self.via_grid/Vector2D(self.paste_between_vias)

        if any(self.paste_rings_outside):
            self.inner_size = self.via_grid/Vector2D(self.paste_between_vias)*self.paste_reduction
        else:
            # inner_grid = mask_size/(inner_count)
            self.inner_size = self.paste_area_size/(self.inner_count)*self.paste_reduction

        corner = ChamferSelPadGrid(0)
        corner.setCorners()
        pad = ChamferedPadGrid(
                number="", type=Pad.TYPE_SMT,
                center=[0, 0], size=self.inner_size, layers=['F.Paste'],
                chamfer_size=0, chamfer_selection=corner,
                pincount=self.paste_between_vias, grid=self.inner_grid,
                round_radius_handler=self.paste_round_radius_handler
                )

        if not self.kicad4_compatible:
            pad.chamferAvoidCircle(
                        center=self.via_grid/2, diameter=self.via_drill,
                        clearance=self.via_clarance)

        count = [self.vias_in_mask[0]-1, self.vias_in_mask[1]-1]
        return ExposedPad.__createPasteGrids(
                    original=pad, grid=self.via_grid, count=count, center=self.at
                    )

    def __createPasteOutsideX(self):
        pads = []
        corner = ChamferSelPadGrid(
                    {ChamferSelPadGrid.TOP_RIGHT: 1,
                     ChamferSelPadGrid.BOTTOM_RIGHT: 1
                     })
        x = self.top_left_via[0]-self.ring_size[0]/2
        y = self.at[1]-(self.via_layout[1]-2)/2*self.via_grid[1]

        pad_side = ChamferedPadGrid(
            number="", type=Pad.TYPE_SMT,
            center=[x, y],
            size=[self.outer_size[0], self.inner_size[1]],
            layers=['F.Paste'],
            chamfer_size=0, chamfer_selection=corner,
            pincount=[self.paste_rings_outside[0], self.paste_between_vias[1]],
            grid=[self.outer_paste_grid[0], self.inner_grid[1]],
            round_radius_handler=self.paste_round_radius_handler
            )

        if not self.kicad4_compatible:
            pad_side.chamferAvoidCircle(
                    center=self.top_left_via, diameter=self.via_drill,
                    clearance=self.via_clarance)

        pads.extend(ExposedPad.__createPasteGrids(
                    original=pad_side, grid=self.via_grid,
                    count=[1, self.via_layout[1]-1],
                    center=[x, self.at['y']]
                    ))

        corner = ChamferSelPadGrid(
                    {ChamferSelPadGrid.TOP_LEFT: 1,
                     ChamferSelPadGrid.BOTTOM_LEFT: 1
                     })
        pad_side.chamfer_selection = corner

        x = 2*self.at[0]-x
        pads.extend(ExposedPad.__createPasteGrids(
                    original=pad_side, grid=self.via_grid,
                    count=[1, self.via_layout[1]-1],
                    center=[x, self.at['y']]
                    ))
        return pads

    def __createPasteOutsideY(self):
        pads = []
        corner = ChamferSelPadGrid(
                    {ChamferSelPadGrid.BOTTOM_LEFT: 1,
                     ChamferSelPadGrid.BOTTOM_RIGHT: 1
                     })

        x = self.at[0]-(self.via_layout[0]-2)/2*self.via_grid[0]
        y = self.top_left_via[1]-self.ring_size[1]/2

        pad_side = ChamferedPadGrid(
            number="", type=Pad.TYPE_SMT,
            center=[x, y],
            size=[self.inner_size[0], self.outer_size[1]],
            layers=['F.Paste'],
            chamfer_size=0, chamfer_selection=corner,
            pincount=[self.paste_between_vias[0], self.paste_rings_outside[1]],
            grid=[self.inner_grid[0], self.outer_paste_grid[1]],
            round_radius_handler=self.paste_round_radius_handler
            )

        if not self.kicad4_compatible:
            pad_side.chamferAvoidCircle(
                    center=self.top_left_via, diameter=self.via_drill,
                    clearance=self.via_clarance)

        pads.extend(ExposedPad.__createPasteGrids(
                    original=pad_side, grid=self.via_grid,
                    count=[self.via_layout[0]-1, 1],
                    center=[self.at['x'], y]
                    ))

        corner = ChamferSelPadGrid(
                    {ChamferSelPadGrid.TOP_LEFT: 1,
                     ChamferSelPadGrid.TOP_RIGHT: 1
                     })
        pad_side.chamfer_selection = corner

        y = 2*self.at[1]-y
        pads.extend(ExposedPad.__createPasteGrids(
                    original=pad_side, grid=self.via_grid,
                    count=[self.via_layout[0]-1, 1],
                    center=[self.at['x'], y]
                    ))
        return pads

    def __createPasteOutsideCorners(self):
        pads = []
        left = self.top_left_via[0]-self.ring_size[0]/2
        top = self.top_left_via[1]-self.ring_size[1]/2
        corner = [
            [
                {ChamferSelPadGrid.BOTTOM_RIGHT: 1},
                {ChamferSelPadGrid.TOP_RIGHT: 1}
                ],
            [
                {ChamferSelPadGrid.BOTTOM_LEFT: 1},
                {ChamferSelPadGrid.TOP_LEFT: 1}
                ]
            ]
        pad_side = ChamferedPadGrid(
            number="", type=Pad.TYPE_SMT,
            center=[left, top], size=self.outer_size, layers=['F.Paste'],
            chamfer_size=0, chamfer_selection=0,
            pincount=self.paste_rings_outside,
            grid=self.outer_paste_grid,
            round_radius_handler=self.paste_round_radius_handler
            )

        if not self.kicad4_compatible:
            pad_side.chamferAvoidCircle(
                    center=self.top_left_via, diameter=self.via_drill,
                    clearance=self.via_clarance)

        for idx_x in range(2):
            for idx_y in range(2):
                x = left if idx_x == 0 else 2*self.at[0]-left
                y = top if idx_y == 0 else 2*self.at[1]-top
                pad_side.center = Vector2D(x, y)
                pad_side.chamfer_selection = ChamferSelPadGrid(corner[idx_x][idx_y])
                pads.append(copy(pad_side))

        return pads

    def __createPasteAvoidViasOutside(self):
        self.ring_size = (self.paste_area_size-(Vector2D(self.vias_in_mask)-1)*self.via_grid)/2
        self.outer_paste_grid = Vector2D([s/p if p != 0 else s
                                          for s, p in zip(self.ring_size, self.paste_rings_outside)])
        self.outer_size = self.outer_paste_grid*self.paste_reduction

        pads = []
        if self.paste_rings_outside[0] and self.inner_count[1] > 0:
            pads.extend(self.__createPasteOutsideX())

        if self.paste_rings_outside[1] and self.inner_count[0]:
            pads.extend(self.__createPasteOutsideY())

        if all(self.paste_rings_outside):
            pads.extend(self.__createPasteOutsideCorners())

        return pads

    def __createPaste(self):
        pads = []
        if self.has_vias:
            self.top_left_via = -(Vector2D(self.vias_in_mask)-1)*self.via_grid/2+self.at

        if self.has_vias and self.paste_avoid_via:
            self.inner_count = (Vector2D(self.vias_in_mask)-1)*Vector2D(self.paste_between_vias)

            if all(self.vias_in_mask) and all(self.paste_between_vias):
                pads += self.__createPasteAvoidViasInside()
            if any(self.paste_rings_outside):
                pads += self.__createPasteAvoidViasOutside()
        else:
            pads += self.__createPasteIgnoreVia()

        return pads

    def __createMainPad(self):
        pads = []
        if self.size == self.mask_size:
            layers_main = ['F.Cu', 'F.Mask']
        else:
            layers_main = ['F.Cu']
            pads.append(Pad(
                number="", at=self.at, size=self.mask_size,
                shape=Pad.SHAPE_ROUNDRECT, type=Pad.TYPE_SMT, layers=['F.Mask'],
                round_radius_handler=self.round_radius_handler
            ))

        pads.append(Pad(
            number=self.number, at=self.at, size=self.size,
            shape=Pad.SHAPE_ROUNDRECT, type=Pad.TYPE_SMT, layers=layers_main,
            round_radius_handler=self.round_radius_handler
        ))

        return pads

    def __createVias(self):
        via_layers = ['*.Cu']
        if self.via_tented == ExposedPad.VIA_NOT_TENTED or self.via_tented == ExposedPad.VIA_TENTED_BOTTOM_ONLY:
            via_layers.append('F.Mask')
        if self.via_tented == ExposedPad.VIA_NOT_TENTED or self.via_tented == ExposedPad.VIA_TENTED_TOP_ONLY:
            via_layers.append('B.Mask')

        pads = []
        cy = -((self.via_layout[1]-1)*self.via_grid[1])/2 + self.at.y
        for i in range(self.via_layout[1]):
            pads.append(
                PadArray(center=[self.at.x, cy], initial=self.number,
                         increment=0, pincount=self.via_layout[0],
                         x_spacing=self.via_grid[0], size=self.via_size,
                         type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE,
                         drill=self.via_drill, layers=via_layers
                         ))
            cy += self.via_grid[1]

        if self.add_bottom_pad:
            pads.append(Pad(
                number=self.number, at=self.at, size=self.bottom_size,
                shape=Pad.SHAPE_ROUNDRECT, type=Pad.TYPE_SMT,
                layers=self.bottom_pad_Layers,
                round_radius_handler=self.round_radius_handler
            ))

        return pads

    def getVirtualChilds(self):
        # traceback.print_stack()
        if self.has_vias:
            self.round_radius_handler.limitMaxRadius(self.via_size/2)

        pads = []
        pads += self.__createMainPad()
        if self.has_vias:
            pads += self.__createVias()
        pads += self.__createPaste()
        return pads

    def getRoundRadius(self):
        return self.round_radius_handler.getRoundRadius(min(self.size))


================================================
FILE: KicadModTree/nodes/specialized/FilledRect.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node
from KicadModTree.nodes.specialized import RectLine
from KicadModTree.nodes.specialized import RectFill


class FilledRect(Node):
    r"""Add a Filled Rect to the render tree

    Combines ``RectLine`` and ``RectFill`` into one class for simpler handling

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *start* (``Vector2D``) --
          start edge of the rect
        * *end* (``Vector2D``) --
          end edge of the rect
        * *layer* (``str``) --
          layer on which the rect is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the outer line (default: 0.15)

    :Example:

    >>> from KicadModTree import *
    >>> FilledRect(start=[-3, -2], end=[3, 2], layer='F.SilkS')
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.start_pos = Vector2D(kwargs['start'])
        self.end_pos = Vector2D(kwargs['end'])

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width', 0.12)  # TODO: better variation to get line width

        rect_line = RectLine(**kwargs)
        rect_line._parent = self

        rect_fill = RectFill(**kwargs)
        rect_fill._parent = self

        self.virtual_childs = [rect_line, rect_fill]

    def getVirtualChilds(self):
        return self.virtual_childs

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)

        render_string = ['start: [x: {sx}, y: {sy}]'.format(sx=self.start_pos.x, sy=self.start_pos.y),
                         'end: [x: {ex}, y: {ey}]'.format(ex=self.end_pos.x, ey=self.end_pos.y)]

        render_text += " [{}]".format(", ".join(render_string))

        return render_text


================================================
FILE: KicadModTree/nodes/specialized/PadArray.py
================================================
#!/usr/bin/env python

# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2017 by @SchrodingersGat
# (C) 2017 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from types import GeneratorType
from KicadModTree.nodes.base.Pad import *
from KicadModTree.nodes.specialized.ChamferedPad import *
from KicadModTree.nodes.Node import Node

from KicadModTree.util.paramUtil import *


class PadArray(Node):
    r"""Add a row of Pads

    Simplifies the handling of pads which are rendered in a specific form

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *start* (``Vector2D``) --
          start edge of the pad array
        * *center* (``Vector2D``) --
          center pad array around specific point
        * *pincount* (``int``) --
          number of pads to render
        * *spacing* (``Vector2D``, ``float``) --
          offset between rendered pads
        * *x_spacing* (``float``) --
          x offset between rendered pads
        * *y_spacing* (``float``) --
          y offset between rendered pads
        * *initial* (``int``) --
          name of the first pad
        * *increment* (``int, function(previous_number)``) --
          declare how the name of the follow up is calculated
        * *type* (``Pad.TYPE_THT``, ``Pad.TYPE_SMT``, ``Pad.TYPE_CONNECT``, ``Pad.TYPE_NPTH``) --
          type of the pad
        * *shape* (``Pad.SHAPE_CIRCLE``, ``Pad.SHAPE_OVAL``, ``Pad.SHAPE_RECT``, ``Pad.SHAPE_TRAPEZE``, ...) --
          shape of the pad
        * *rotation* (``float``) --
          rotation of the pad
        * *size* (``float``, ``Vector2D``) --
          size of the pad
        * *offset* (``Vector2D``) --
          offset of the pad
        * *drill* (``float``, ``Vector2D``) --
          drill-size of the pad
        * *solder_paste_margin_ratio* (``float``) --
          solder paste margin ratio of the pad
        * *layers* (``Pad.LAYERS_SMT``, ``Pad.LAYERS_THT``, ``Pad.LAYERS_NPTH``) --
          layers on which are used for the pad
        * *chamfer_corner_selection_first* (``[bool, bool, bool, bool]``)
          Select which corner should be chamfered for the first pad. (default: None)
        * *chamfer_corner_selection_last* (``[bool, bool, bool, bool]``)
          Select which corner should be chamfered for the last pad. (default: None)
        * *chamfer_size* (``float``, ``Vector2D``) --
          size for the chamfer used for the end pads. (default: None)

        * *end_pads_size_reduction* (``dict with keys x-,x+,y-,y+``) --
          size is reduced on the given side. (size reduced plus center moved.)
        * *tht_pad1_shape* (``Pad.SHAPE_RECT``, ``Pad.SHAPE_ROUNDRECT``, ...) --
          shape for marking pad 1 for through hole components. (deafult: ``Pad.SHAPE_ROUNDRECT``)
        * *tht_pad1_id* (``int, string``) --
          pad number used for "pin 1" (default: 1)
        * *hidden_pins* (``int, Vector1D``) --
          pin number(s) to be skipped; a footprint with hidden pins has missing pads and matching pin numbers
        * *deleted_pins* (``int, Vector1D``) --
          pin locations(s) to be skipped; a footprint with deleted pins has pads missing but no missing pin numbers"


    :Example:

    >>> from KicadModTree import *
    >>> PadArray(pincount=10, spacing=[1,-1], center=[0,0], initial=5, increment=2,
    ...          type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, size=[1,2], layers=Pad.LAYERS_SMT)
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        self._initPincount(**kwargs)
        self._initIncrement(**kwargs)
        self._initInitialNumber(**kwargs)
        self._initSpacing(**kwargs)
        self._initStartingPosition(**kwargs)
        self.virtual_childs = self._createPads(**kwargs)

    # How many pads in the array
    def _initPincount(self, **kwargs):
        if not kwargs.get('pincount'):
            raise KeyError('pincount not declared (like "pincount=10")')
        self.pincount = kwargs.get('pincount')
        if type(self.pincount) is not int or self.pincount <= 0:
            raise ValueError('{pc} is an invalid value for pincount'.format(pc=self.pincount))

        if kwargs.get('hidden_pins') and kwargs.get('deleted_pins'):
            raise KeyError('hidden pins and deleted pins cannot be used together')

        self.exclude_pin_list = []
        if kwargs.get('hidden_pins'):
            # exclude_pin_list is for pads being removed based on pad number
            # deleted pins are filtered out later by pad location (not number)
            self.exclude_pin_list = kwargs.get('hidden_pins')

            if type(self.exclude_pin_list) not in [list, tuple]:
                raise TypeError('exclude pin list must be specified like "exclude_pin_list=[0,1]"')
            elif any([type(i) not in [int] for i in self.exclude_pin_list]):
                raise ValueError('exclude pin list must be integer value')

    # Where to start the aray
    def _initStartingPosition(self, **kwargs):
        """
        can use the 'start' argument to start a pad array at a given position
        OR
        can use the 'center' argument to center the array around the given position
        """
        self.startingPosition = [0, 0]

        # Start takes priority
        if kwargs.get('start'):
            self.startingPosition = kwargs.get('start')
            if type(self.startingPosition) not in [list, tuple] or not len(self.startingPosition) == 2:
                raise ValueError('array starting position "start" must be given as an list of length two')
            if any([type(i) not in [int, float] for i in self.startingPosition]):
                raise ValueError('array starting coordinates must be numerical')
        elif kwargs.get('center'):
            center = kwargs.get('center')

            if type(center) not in [list, tuple] or not len(center) == 2:
                raise ValueError('array center position "center" must be given as a list of length two')
            if any([type(i) not in [int, float] for i in center]):
                raise ValueError('array center coordinates must be numerical')

            # Now calculate the desired starting position of the array
            self.startingPosition[0] = center[0] - (self.pincount - 1) * self.spacing[0] / 2.
            self.startingPosition[1] = center[1] - (self.pincount - 1) * self.spacing[1] / 2.

    # What number to start with?
    def _initInitialNumber(self, **kwargs):
        self.initialPin = kwargs.get('initial', 1)
        if self.initialPin == "":
            self.increment = 0
        elif type(self.initialPin) is not int or self.initialPin < 1:
            if not callable(self.increment):
                raise ValueError('{pn} is not a valid starting pin number if increment is not a function'
                                 .format(pn=self.initialPin))

    # Pin incrementing
    def _initIncrement(self, **kwargs):
        self.increment = kwargs.get('increment', 1)

    # Pad spacing
    def _initSpacing(self, **kwargs):
        """
        spacing can be given as:
        spacing = [1,2] # high priority
        x_spacing = 1
        y_spacing = 2
        """

        self.spacing = [0, 0]  # [x, y]

        if kwargs.get('spacing'):
            self.spacing = kwargs.get('spacing')
            if type(self.spacing) not in [list, tuple]:
                raise TypeError('spacing must be specified like "spacing=[0,1]"')
            elif len(self.spacing) is not 2:
                raise ValueError('spacing must be supplied as x,y pair')
            elif any([type(i) not in [int, float] for i in self.spacing]):
                raise ValueError('spacing must be numerical value')
            # if 'spacing' is specified, ignore x_spacing and y_spacing
            return

        if kwargs.get('x_spacing'):
            self.spacing[0] = kwargs.get('x_spacing')
            if type(self.spacing[0]) not in [int, float]:
                raise ValueError('x_spacing must be supplied as numerical value')

        if kwargs.get('y_spacing'):
            self.spacing[1] = kwargs.get('y_spacing')
            if type(self.spacing[1]) not in [int, float]:
                raise ValueError('y_spacing must be supplied as numerical value')

        if all([i == 0 for i in self.spacing]):
            raise ValueError('pad spacing ({sp}) must be non-zero'.format(sp=self.spacing))

    def _createPads(self, **kwargs):

        pads = []

        x_start, y_start = self.startingPosition
        x_spacing, y_spacing = self.spacing

        padShape = kwargs.get('shape')

        # Special case, increment = 0
        # this can be used for creating an array with all the same pad number
        if self.increment == 0:
            pad_numbers = [self.initialPin] * self.pincount
        elif type(self.increment) == int:
            pad_numbers = range(self.initialPin, self.initialPin + (self.pincount * self.increment), self.increment)
        elif callable(self.increment):
            pad_numbers = [self.initialPin]
            for idx in range(1, self.pincount):
                pad_numbers.append(self.increment(pad_numbers[-1]))
        elif type(self.increment) == GeneratorType:
            pad_numbers = [next(self.increment) for i in range(self.pincount)]
        else:
            raise TypeError("Wrong type for increment. It must be either a int, callable or generator.")

        end_pad_params = copy(kwargs)
        if kwargs.get('end_pads_size_reduction'):
            size_reduction = kwargs['end_pads_size_reduction']
            end_pad_params['size'] = toVectorUseCopyIfNumber(kwargs.get('size'), low_limit=0)

            delta_size = Vector2D(
                size_reduction.get('x+', 0) + size_reduction.get('x-', 0),
                size_reduction.get('y+', 0) + size_reduction.get('y-', 0)
                )

            end_pad_params['size'] -= delta_size

            delta_pos = Vector2D(
                -size_reduction.get('x+', 0) + size_reduction.get('x-', 0),
                -size_reduction.get('y+', 0) + size_reduction.get('y-', 0)
                )/2
        else:
            delta_pos = Vector2D(0, 0)

        for i, number in enumerate(pad_numbers):
            includePad = True

            # deleted pins are filtered by pad/pin position (they are 'None' in pad_numbers list)
            if type(number) not in [int, str]:
                includePad = False

            # hidden pins are filtered out by pad number (index of pad_numbers list)
            if not kwargs.get('deleted_pins'):
                if type(self.initialPin) == 'int':
                    includePad = (self.initialPin + i) not in self.exclude_pin_list
                else:
                    includePad = number not in self.exclude_pin_list

            if includePad:
                current_pad_pos = Vector2D(
                    x_start + i * x_spacing,
                    y_start + i * y_spacing
                    )
                current_pad_params = copy(kwargs)
                if i == 0 or i == len(pad_numbers)-1:
                    current_pad_pos += delta_pos
                    current_pad_params = end_pad_params
                if kwargs.get('type') == Pad.TYPE_THT and number == kwargs.get('tht_pad1_id', 1):
                    current_pad_params['shape'] = kwargs.get('tht_pad1_shape', Pad.SHAPE_ROUNDRECT)
                    if 'radius_ratio' not in current_pad_params:
                        current_pad_params['radius_ratio'] = 0.25
                    if 'maximum_radius' not in current_pad_params:
                        current_pad_params['maximum_radius'] = 0.25
                else:
                    current_pad_params['shape'] = padShape
                if kwargs.get('chamfer_size'):
                    if i == 0 and 'chamfer_corner_selection_first' in kwargs:
                        pads.append(
                            ChamferedPad(
                                number=number, at=current_pad_pos,
                                corner_selection=kwargs.get('chamfer_corner_selection_first'),
                                **current_pad_params
                                ))
                        continue
                    if i == len(pad_numbers)-1 and 'chamfer_corner_selection_last' in kwargs:
                        pads.append(
                            ChamferedPad(
                                number=number, at=current_pad_pos,
                                corner_selection=kwargs.get('chamfer_corner_selection_last'),
                                **current_pad_params
                                ))
                        continue
                pads.append(Pad(number=number, at=current_pad_pos, **current_pad_params))

        return pads

    def getVirtualChilds(self):
        return self.virtual_childs


================================================
FILE: KicadModTree/nodes/specialized/PolygoneLine.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.PolygonPoints import *
from KicadModTree.nodes.Node import Node
from KicadModTree.nodes.base.Line import Line


class PolygoneLine(Node):
    r"""Add a Polygone Line to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *polygone* (``list(Point)``) --
          edges of the polygone
        * *layer* (``str``) --
          layer on which the polygone is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the line (default: None, which means auto detection)

    :Example:

    >>> from KicadModTree import *
    >>> PolygoneLine(polygone=[[0, 0], [0, 1], [1, 1], [0, 0]], layer='F.SilkS')
    """

    def __init__(self, **kwargs):
        Node.__init__(self)

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width')

        self._initPolyPoint(**kwargs)

        self.virtual_childs = self._createChildNodes(self.nodes)

    def _initPolyPoint(self, **kwargs):
        self.nodes = PolygonPoints(**kwargs)

    def _createChildNodes(self, polygone_line):
        nodes = []

        for line_start, line_end in zip(polygone_line, polygone_line[1:]):
            new_node = Line(start=line_start, end=line_end, layer=self.layer, width=self.width)
            new_node._parent = self
            nodes.append(new_node)

        return nodes

    def getVirtualChilds(self):
        return self.virtual_childs

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)
        render_text += " ["

        node_strings = []
        for node in self.nodes:
            node_position = Vector2D(node)
            node_strings.append("[x: {x}, y: {y}]".format(x=node_position.x,
                                                          y=node_position.y))

        if len(node_strings) <= 6:
            render_text += " ,".join(node_strings)
        else:
            # display only a few nodes of the beginning and the end of the polygone line
            render_text += " ,".join(node_strings[:3])
            render_text += " ,... ,"
            render_text += " ,".join(node_strings[-3:])

        render_text += "]"

        return render_text


================================================
FILE: KicadModTree/nodes/specialized/RectFill.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node
from KicadModTree.nodes.base import Line


class RectFill(Node):
    r"""Add the filling of a Rect to the render tree

    Normally, this class isn't needed, because ``FilledRect`` combines ``RectLine`` with ``RectFill``

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *start* (``Vector2D``) --
          start edge of the rect fill
        * *end* (``Vector2D``) --
          end edge of the rect fill
        * *layer* (``str``) --
          layer on which the rect fill is drawn (default: 'F.SilkS')
        * *width* (``float``) --
          width of the filling lines (default: 0.12)

    :Example:

    >>> from KicadModTree import *
    >>> RectFill(start=[-3, -2], end=[3, 2], layer='F.SilkS')
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.start_pos = Vector2D(kwargs['start'])
        self.end_pos = Vector2D(kwargs['end'])

        self.layer = kwargs.get('layer', 'F.SilkS')
        self.width = kwargs.get('width', 0.12)  # TODO: auto detection

        self.virtual_childs = self._createChildNodes(self.start_pos, self.end_pos, self.layer, self.width)

    def _createChildNodes(self, start_pos, end_pos, layer, width):
        nodes = []

        cur_y_pos = min([start_pos.y, end_pos.y])
        max_y_pos = max([start_pos.y, end_pos.y])

        while (cur_y_pos + width) < max_y_pos:
            cur_y_pos += width
            new_node = Line(start=Vector2D(start_pos.x, cur_y_pos),
                            end=Vector2D(end_pos.x, cur_y_pos),
                            layer=layer,
                            width=width)
            new_node._parent = self
            nodes.append(new_node)

        return nodes

    def getVirtualChilds(self):
        return self.virtual_childs

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)

        render_string = ['start: [x: {sx}, y: {sy}]'.format(sx=self.start_pos.x, sy=self.start_pos.y),
                         'end: [x: {ex}, y: {ey}]'.format(ex=self.end_pos.x, ey=self.end_pos.y)]

        render_text += " [{}]".format(", ".join(render_string))

        return render_text


================================================
FILE: KicadModTree/nodes/specialized/RectLine.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>

from KicadModTree.Vector import *
from KicadModTree.nodes.Node import Node
from .PolygoneLine import PolygoneLine


class RectLine(PolygoneLine):
    r"""Add a Rect to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *start* (``Vector2D``) --
          start edge of the rect
        * *end* (``Vector2D``) --
          end edge of the rect
        * *layer* (``str``) --
          layer on which the rect is drawn
        * *width* (``float``) --
          width of the outer line (default: None, which means auto detection)
        * *offset* (``Vector2D``, ``float``) --
          offset of the rect line to the specified one

    :Example:

    >>> from KicadModTree import *
    >>> RectLine(start=[-3, -2], end=[3, 2], layer='F.SilkS')
    """

    def __init__(self, **kwargs):
        self.start_pos = Vector2D(kwargs['start'])
        self.end_pos = Vector2D(kwargs['end'])

        # If specifed, an 'offset' can be applied to the RectLine.
        # For example, creating a border around a given Rect of a specified size
        if kwargs.get('offset'):
            # offset for the rect line
            # e.g. for creating a rectLine 0.5mm LARGER than the given rect, or similar
            offset = [0, 0]

            # Has an offset / inset been specified?
            if type(kwargs['offset']) in [int, float]:
                offset[0] = offset[1] = kwargs['offset']
            elif type(kwargs['offset']) in [list, tuple] and len(kwargs['offset']) == 2:
                # Ensure that all offset params are numerical
                if all([type(i) in [int, float] for i in kwargs['offset']]):
                    offset = kwargs['offset']

            # For the offset to work properly, start-pos must be top-left, and end-pos must be bottom-right
            x1 = min(self.start_pos.x, self.end_pos.x)
            x2 = max(self.start_pos.x, self.end_pos.x)

            y1 = min(self.start_pos.y, self.end_pos.y)
            y2 = max(self.start_pos.y, self.end_pos.y)

            # Put the offset back in
            self.start_pos.x = x1 - offset[0]
            self.start_pos.y = y1 - offset[1]

            self.end_pos.x = x2 + offset[0]
            self.end_pos.y = y2 + offset[1]

        polygone_line = [{'x': self.start_pos.x, 'y': self.start_pos.y},
                         {'x': self.start_pos.x, 'y': self.end_pos.y},
                         {'x': self.end_pos.x, 'y': self.end_pos.y},
                         {'x': self.end_pos.x, 'y': self.start_pos.y},
                         {'x': self.start_pos.x, 'y': self.start_pos.y}]

        PolygoneLine.__init__(self, polygone=polygone_line, layer=kwargs['layer'], width=kwargs.get('width'))

    def _getRenderTreeText(self):
        render_text = Node._getRenderTreeText(self)
        render_text += " [start: [x: {sx}, y: {sy}] end: [x: {ex}, y: {ey}]]".format(sx=self.start_pos.x,
                                                                                     sy=self.start_pos.y,
                                                                                     ex=self.end_pos.x,
                                                                                     ey=self.end_pos.y)

        return render_text


================================================
FILE: KicadModTree/nodes/specialized/RingPad.py
================================================
# KicadModTree 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.
#
# KicadModTree 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/ >.
#
# (C) 2016 by Thomas Pointhuber, <thomas.pointhuber@gmx.at>
# (C) 2018 by Rene Poeschl, github @poeschlr
from __future__ import division

from copy import copy
from KicadModTree.nodes.Node import Node
from KicadModTree.util.paramUtil import *
from KicadModTree.util.geometric_util import geometricArc, geometricLine, BaseNodeIntersection
from KicadModTree.Vector import *
from KicadModTree.nodes.base.Pad import Pad
from KicadModTree.nodes.base.Circle import Circle
from KicadModTree.nodes.base.Arc import Arc
from KicadModTree.nodes.base.Line import Line
from math import sqrt, sin, cos, pi, ceil


class RingPadPrimitive(Node):
    r"""Add a RingPad to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
      * *radius*: (``float``) --
        middle radius of the ring
      * *width*: (``float``) --
        width of the ring (outer radius - inner radius)
      * *at*: (``Vector2D``) --
        position of the center
      * *layers*: (``Pad.Layers``) --
        layers used for creating the pad
      * *number* (``int``, ``str``) --
        number/name of the pad (default: \"\")
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.at = Vector2D(kwargs.get('at', (0, 0)))
        self.radius = float(kwargs['radius'])
        self.width = float(kwargs['width'])
        self.layers = kwargs['layers']
        self.number = kwargs.get('number', "")

    def copy(self):
        return RingPadPrimitive(
                    at=self.at, radius=self.radius,
                    width=self.width, layers=self.layers,
                    number=self.number
                    )

    def getVirtualChilds(self):
        return [Pad(number=self.number,
                    type=Pad.TYPE_SMT, shape=Pad.SHAPE_CUSTOM,
                    at=(self.at+Vector2D(self.radius, 0)),
                    size=self.width, layers=self.layers,
                    primitives=[Circle(
                        center=(-self.radius, 0),
                        radius=self.radius,
                        width=self.width
                        )]
                    )]


class ArcPadPrimitive(Node):
    r"""Add a RingPad to the render tree

    :param \**kwargs:
        See below

    :Keyword Arguments:
        * *number* (``int``, ``str``) --
          number/name of the pad (default: \"\")
        * *width* (``float``) --
          width of the pad
        * *layers* (``Pad.Layers``) --
          layers on which are used for the pad
        * *round_radius_ratio* (``float``) --
          round radius.
          default: 25\% of ring width
        * *max_round_radius* (``float``) --
          maximum round radius, default: 0.25
          Use none to ignore
        * *reference_arc* (``geometricArc``) --
          the reference arc used for this pad
        * *start_line* (``geometricLine``) --
          line confining the side near the reference points start point
        * *end_line* (``geometricLine``) --
          line confining the side near the reference points end point
        * *minimum_overlap* (``float``)
          minimum overlap. default 0.1
    """

    def __init__(self, **kwargs):
        Node.__init__(self)
        self.reference_arc = geometricArc(geometry=kwargs['reference_arc'])
        self.width = float(kwargs['width'])

        self.number = kwargs.get('number', "")
        self.layers = kwargs['layers']
        self.minimum_overlap = kwargs.get('minimum_overlap', 0.1)

        self.setRoundRadius(**kwargs)
        self.setLimitingLines(**kwargs)

    def setRoundRadius(self, **kwargs):
        if 'round_radius' in kwargs:
            self.round_radius = kwargs['round_radius']
            return

        round_radius_ratio = kwargs.get('round_radius_ratio', 0.25)
        max_round_radius = kwargs.get('max_round_radius', 0.25)
        r = self.width*round_radius_ratio
        if max_round_radius is not None and max_round_radius > 0:
            self.round_radius = min(r, max_round_radius)

    def setLimitingLines(self, **kwargs):
        if kwargs.get('start_line') is not None:
            self.start_line = geometricLine(geometry=kwargs.get('start_line'))
        else:
            self.start_line = None
        if kwargs.get('end_line') is not None:
            self.end_line = geometricLine(geometry=kwargs.get('end_line'))
        else:
            self.end_line = None

    def copy(self):
        return ArcPadPrimitive(
                    reference_arc=self.reference_arc,
                    width=self.width,
                    round_radius=self.round_radius,
                    number=self.number,
                    layers=self.layers,
                    start_line=self.start_line,
                    end_line=self.end_line,
                    minimum_overlap=self.minimum_overlap
                    )

    def rotate(self, angle, origin=(0, 0), use_degrees=True):
        r""" Rotate around given origin

        :params:
            * *angle* (``float``)
                rotation angle
            * *origin* (``Vector2D``)
                origin point for the rotation. default: (0, 0)
            * *use_degrees* (``boolean``)
                rotation angle is given in degrees. default:True
        """

        self.reference_arc.rotate(angle=angle, origin=origin, use_degrees=use_degrees)
        if self.start_line is not None:
            self.start_line.rotat
Download .txt
gitextract_dm0b98jf/

├── .codeclimate.yml
├── .gitignore
├── .travis.yml
├── AUTHORS.md
├── KicadModTree/
│   ├── FileHandler.py
│   ├── KicadFileHandler.py
│   ├── ModArgparser.py
│   ├── Point.py
│   ├── PolygonPoints.py
│   ├── Vector.py
│   ├── __init__.py
│   ├── examples/
│   │   ├── __init__.py
│   │   ├── argparse_example.py
│   │   ├── padArrayWithOutline.py
│   │   ├── params.csv
│   │   ├── params.yml
│   │   ├── polygon.py
│   │   └── simpleFootprint.py
│   ├── nodes/
│   │   ├── Footprint.py
│   │   ├── Node.py
│   │   ├── __init__.py
│   │   ├── base/
│   │   │   ├── Arc.py
│   │   │   ├── Circle.py
│   │   │   ├── Line.py
│   │   │   ├── Model.py
│   │   │   ├── Pad.py
│   │   │   ├── Polygon.py
│   │   │   ├── Text.py
│   │   │   └── __init__.py
│   │   └── specialized/
│   │       ├── ChamferedPad.py
│   │       ├── ChamferedPadGrid.py
│   │       ├── ExposedPad.py
│   │       ├── FilledRect.py
│   │       ├── PadArray.py
│   │       ├── PolygoneLine.py
│   │       ├── RectFill.py
│   │       ├── RectLine.py
│   │       ├── RingPad.py
│   │       ├── Rotation.py
│   │       ├── Translation.py
│   │       └── __init__.py
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── datatypes/
│   │   │   ├── __init__.py
│   │   │   ├── test_Vector2D.py
│   │   │   └── test_Vector3D.py
│   │   ├── moduletests/
│   │   │   ├── __init__.py
│   │   │   ├── test_arc.py
│   │   │   ├── test_exposed_pad.py
│   │   │   ├── test_kicad5_padshapes.py
│   │   │   ├── test_rotation.py
│   │   │   └── test_simple_footprints.py
│   │   ├── nodes/
│   │   │   ├── __init__.py
│   │   │   └── test_Node.py
│   │   └── test.py
│   └── util/
│       ├── __init__.py
│       ├── geometric_util.py
│       ├── kicad_util.py
│       └── paramUtil.py
├── LICENSE
├── README.md
├── docs/
│   ├── KicadModTree.nodes.base.rst
│   ├── KicadModTree.nodes.rst
│   ├── KicadModTree.nodes.specialized.rst
│   ├── KicadModTree.rst
│   ├── KicadModTree.util.rst
│   ├── Makefile
│   ├── conf.py
│   └── index.rst
├── manage.sh
├── requirements-dev.txt
├── requirements.txt
├── scripts/
│   ├── Battery/
│   │   ├── BatteryHolder.py
│   │   ├── BatteryHolder.yml
│   │   └── README.txt
│   ├── Buttons_Switches/
│   │   ├── make_DIPSwitches.py
│   │   ├── rotary_coded_switch.py
│   │   └── rotary_coded_switch.yml
│   ├── Buzzers_Beepers/
│   │   ├── buzzer_round_tht.py
│   │   └── buzzer_round_tht_star_mictronics.csv
│   ├── Capacitors_SMD/
│   │   ├── CP_Elec_round.py
│   │   ├── CP_Elec_round.yaml
│   │   ├── C_Elec_round.py
│   │   ├── C_Elec_round.yaml
│   │   ├── C_Trimmer_config.yaml
│   │   ├── C_Trimmer_factory.py
│   │   ├── C_Trimmer_make.py
│   │   ├── bump.py
│   │   ├── chamfers.py
│   │   ├── corners.py
│   │   ├── ipc7351B_capae_crystal.yaml
│   │   └── tantal and normal smd generator found under SMD_chip_package_rlc-etc
│   ├── Capacitors_THT/
│   │   └── make_Capacitors_THT.py
│   ├── Chokes_THT/
│   │   └── make_Chokes_THT.py
│   ├── Connector/
│   │   ├── Connector_Audio/
│   │   │   └── Jack_3.5mm_Switronic_ST-005-G_horizontal.py
│   │   ├── Connector_Harwin/
│   │   │   ├── conn_harwin_m20-781xx45_smd_top_dual_row.py
│   │   │   └── m20-89xx.py
│   │   ├── Connector_Hirose/
│   │   │   ├── 00-SMD footprint generators can be found in Connector_SMD_single_row_plus_mounting_pad.md
│   │   │   ├── conn_ffc_hirose_fh12_smd_side.py
│   │   │   ├── conn_hirose_df11_tht_top.py
│   │   │   ├── conn_hirose_df12c_ds_smd_top.py
│   │   │   ├── conn_hirose_df12e_dp_smd_top.py
│   │   │   ├── conn_hirose_df13_tht_side.py
│   │   │   ├── conn_hirose_df13_tht_top.py
│   │   │   ├── conn_hirose_df13c_smd_top.py
│   │   │   ├── conn_hirose_df63_tht_top.py
│   │   │   ├── helpers.py
│   │   │   └── not_in_official_lib/
│   │   │       ├── df33_straight_pth.py
│   │   │       └── df63_angled.py
│   │   ├── Connector_IEC_DIN/
│   │   │   └── generate_din41612.py
│   │   ├── Connector_JAE/
│   │   │   ├── conn_ffc_jae_ff08.py
│   │   │   ├── conn_jae_LY20_tht_side.py
│   │   │   ├── conn_jae_LY20_tht_top.py
│   │   │   └── helpers.py
│   │   ├── Connector_JST/
│   │   │   ├── 00-SMD footprint generators can be found in Connector_SMD_single_row_plus_mounting_pad.md
│   │   │   ├── JST-PH-SMT-SIDE_ENTRY.fcstd
│   │   │   ├── JST-PH-SMT-TOP_ENTRY.fcstd
│   │   │   ├── JST_ZE_top_entry_pad_size.fcstd
│   │   │   ├── conn_jst_J2100_tht_side.py
│   │   │   ├── conn_jst_J2100_tht_top.py
│   │   │   ├── conn_jst_JWPF_tht_top.py
│   │   │   ├── conn_jst_NV_tht_top.py
│   │   │   ├── conn_jst_PHD_horizontal.py
│   │   │   ├── conn_jst_PHD_vertical.py
│   │   │   ├── conn_jst_PUD_tht_side.py
│   │   │   ├── conn_jst_PUD_tht_top.py
│   │   │   ├── conn_jst_VH_tht_side-stabilizer.py
│   │   │   ├── conn_jst_VH_tht_side.py
│   │   │   ├── conn_jst_VH_tht_top-shrouded.py
│   │   │   ├── conn_jst_eh_tht_side.py
│   │   │   ├── conn_jst_eh_tht_top.py
│   │   │   ├── conn_jst_ph_tht_side.py
│   │   │   ├── conn_jst_ph_tht_top.py
│   │   │   ├── conn_jst_vh_tht_top.py
│   │   │   ├── conn_jst_xh_tht_side.py
│   │   │   ├── conn_jst_xh_tht_top.py
│   │   │   ├── conn_jst_ze_tht_side.py
│   │   │   ├── conn_jst_ze_tht_top.py
│   │   │   └── helpers.py
│   │   ├── Connector_Molex/
│   │   │   ├── 00-SMD footprint generators can be found in Connector_SMD_single_row_plus_mounting_pad.md
│   │   │   ├── conn_ffc_molex_200528.py
│   │   │   ├── conn_ffc_molex_502250.py
│   │   │   ├── conn_molex_SPOX_tht_side.py
│   │   │   ├── conn_molex_SPOX_tht_top.py
│   │   │   ├── conn_molex_kk_254_tht_top.py
│   │   │   ├── conn_molex_kk_396_tht_top.py
│   │   │   ├── conn_molex_mega-fit_tht_side_dual-row.py
│   │   │   ├── conn_molex_mega-fit_tht_top_dual_row.py
│   │   │   ├── conn_molex_micro-clasp_tht_side.py
│   │   │   ├── conn_molex_micro-clasp_tht_top.py
│   │   │   ├── conn_molex_micro-fit-3.0_smd_side_dual_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_smd_top_dual_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_tht_side_dual_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_tht_side_single_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_tht_top_dual_row.py
│   │   │   ├── conn_molex_micro-fit-3.0_tht_top_single_row.py
│   │   │   ├── conn_molex_micro-latch_tht_side.py
│   │   │   ├── conn_molex_micro-latch_tht_top.py
│   │   │   ├── conn_molex_mini-fit-sr_tht_side.py
│   │   │   ├── conn_molex_mini-fit-sr_tht_top.py
│   │   │   ├── conn_molex_mini-fit-sr_tht_top_dual.py
│   │   │   ├── conn_molex_mini-fit_Jr_tht_side_dual-row.py
│   │   │   ├── conn_molex_mini-fit_Jr_tht_top_dual-row.py
│   │   │   ├── conn_molex_nano-fit_tht_side.py
│   │   │   ├── conn_molex_nano-fit_tht_top.py
│   │   │   ├── conn_molex_picoblade_tht_side.py
│   │   │   ├── conn_molex_picoblade_tht_top.py
│   │   │   ├── conn_molex_picoflex_smd_top.py
│   │   │   ├── conn_molex_picoflex_tht_top.py
│   │   │   ├── conn_molex_sabre_tht_side.py
│   │   │   ├── conn_molex_sabre_tht_top.py
│   │   │   ├── conn_molex_slimstack-501920.py
│   │   │   ├── conn_molex_slimstack-502426.py
│   │   │   ├── conn_molex_slimstack-502430.py
│   │   │   ├── conn_molex_slimstack-52991.py
│   │   │   ├── conn_molex_slimstack-53748.py
│   │   │   ├── conn_molex_slimstack-54722.py
│   │   │   ├── conn_molex_slimstack-55560.py
│   │   │   ├── conn_molex_stackable-linear_tht_top.py
│   │   │   └── helpers.py
│   │   ├── Connector_PCBEdge/
│   │   │   └── molex_EDGELOCK.py
│   │   ├── Connector_PhoenixContact/
│   │   │   ├── config_phoenix_KLCv1.0.yaml
│   │   │   ├── config_phoenix_KLCv1.1.yaml
│   │   │   ├── config_phoenix_KLCv2.0.yaml
│   │   │   ├── config_phoenix_KLCv3.0.yaml
│   │   │   ├── config_phoenix_TERA.yaml
│   │   │   ├── helpers.py
│   │   │   ├── mc.py
│   │   │   ├── mc_params.py
│   │   │   ├── mstb.py
│   │   │   └── mstb_params.py
│   │   ├── Connector_SMD_single_row_plus_mounting_pad/
│   │   │   ├── conn_hirose.yaml
│   │   │   ├── conn_jst.yaml
│   │   │   ├── conn_molex.yaml
│   │   │   ├── helpers.py
│   │   │   └── smd_single_row_plus_mounting_pad.py
│   │   ├── Connector_Samtec/
│   │   │   ├── conn_samtec_LSHM_smd_top.py
│   │   │   ├── conn_samtec_hle.py
│   │   │   ├── helpers.py
│   │   │   ├── mecf_connector.py
│   │   │   └── mecf_socket.py
│   │   ├── Connector_Stocko/
│   │   │   └── conn_Stocko_MKS_16xx.py
│   │   ├── Connector_TE-Connectivity/
│   │   │   ├── conn_ffc_te_84952-84953.py
│   │   │   ├── conn_fpc_te_1734839.py
│   │   │   ├── conn_te_826576.py
│   │   │   ├── conn_te_mate-n-lock_tht_side.py
│   │   │   ├── conn_te_mate-n-lock_tht_top.py
│   │   │   └── helpers.py
│   │   ├── Connector_Wago/
│   │   │   ├── conn_wago_734_horizontal.py
│   │   │   ├── conn_wago_734_vertical.py
│   │   │   └── helpers.py
│   │   ├── Connector_Wire/
│   │   │   ├── Research/
│   │   │   │   └── sources.md
│   │   │   ├── solder_wire_tht.py
│   │   │   └── wire_MC_Flexivolt.yaml
│   │   ├── Connector_Wuerth/
│   │   │   └── wuerth_6480xx11622.py
│   │   ├── conn_config_KLCv2.yaml
│   │   └── conn_config_KLCv3.yaml
│   ├── Connector_PinSocket/
│   │   ├── canvas.py
│   │   ├── cq_base_parameters.py
│   │   ├── main_generator.py
│   │   ├── parameters.py
│   │   ├── parameters.yaml
│   │   └── socket_strips.py
│   ├── Connectors_DSub/
│   │   └── make_dsubs.py
│   ├── Converter_DCDC/
│   │   ├── Converter_DCDC.py
│   │   ├── Converter_DCDC.yml
│   │   ├── XP_Power_SF_THT.py
│   │   └── conv_config_KLCv3.yaml
│   ├── Crystals_Resonators_SMD/
│   │   └── make_crystal_smd.py
│   ├── Crystals_Resonators_THT/
│   │   └── make_crystal.py
│   ├── Diodes_SMD/
│   │   └── generator found under SMD_chip_package_rlc-etc
│   ├── Diodes_THT/
│   │   └── make_Diodes_THT.py
│   ├── Fuse/
│   │   ├── ptc-fuse-tht.py
│   │   └── ptc-fuse-tht.yaml
│   ├── Inductor_SMD/
│   │   ├── Inductor_SMD.py
│   │   └── Inductor_SMD.yml
│   ├── Inductors/
│   │   ├── Choke_Schaffner_RNXXX.py
│   │   ├── Murata_DEM35xxC.py
│   │   ├── bourns-srn.py
│   │   ├── generator for normal packages found under SMD_chip_package_rlc-etc
│   │   ├── vishay_IHSM.py
│   │   ├── we-hci.py
│   │   ├── we-hcm.py
│   │   └── we-mapi.py
│   ├── LEDs_SMD/
│   │   ├── generator for normal packages  found under SMD_chip_package_rlc-etc
│   │   ├── plcc4.py
│   │   ├── plcc4.yml
│   │   └── smlvn6.py
│   ├── LEDs_THT/
│   │   └── make_LEDs_THT.py
│   ├── Mounting_Hardware/
│   │   ├── mounting_hole.py
│   │   ├── wuerth_smt_spacer.py
│   │   └── wuerth_smt_spacer.yaml
│   ├── Mounting_Holes/
│   │   └── mounting_hole_long.yaml
│   ├── Multicomp/
│   │   ├── connectors_multicomp_mc9a12.py
│   │   ├── connectors_multicomp_mc9a22.py
│   │   └── create_connectors_multicomp.sh
│   ├── Oscillators_SMD/
│   │   └── make_oscillators.py
│   ├── Packages/
│   │   ├── Package_BGA/
│   │   │   ├── bga.yaml
│   │   │   ├── bga_xilinx.yaml
│   │   │   ├── csp.yaml
│   │   │   ├── ipc_7351b_bga_land_patterns.yaml
│   │   │   ├── ipc_bga_generator.py
│   │   │   └── test_ipc.yaml
│   │   ├── Package_DIP/
│   │   │   └── make_DIP_footprints.py
│   │   ├── Package_Gullwing__QFP_SOIC_SO/
│   │   │   ├── Readme.md
│   │   │   ├── ipc_gullwing_generator.py
│   │   │   └── size_definitions/
│   │   │       ├── eqfp.yaml
│   │   │       ├── hsoic.yaml
│   │   │       ├── hsop.yaml
│   │   │       ├── htsop.yaml
│   │   │       ├── htssop.yaml
│   │   │       ├── hvssop.yaml
│   │   │       ├── infineon.yaml
│   │   │       ├── lqfp.yaml
│   │   │       ├── mqfp.yaml
│   │   │       ├── msop.yaml
│   │   │       ├── pqfp.yaml
│   │   │       ├── sc-74.yaml
│   │   │       ├── so.yaml
│   │   │       ├── soic.yaml
│   │   │       ├── soj.yaml
│   │   │       ├── sop.yaml
│   │   │       ├── sot.yaml
│   │   │       ├── sso.yaml
│   │   │       ├── ssop.yaml
│   │   │       ├── test_hidden_deleted_pins.yaml
│   │   │       ├── test_so.yaml
│   │   │       ├── tqfp.yaml
│   │   │       ├── tsop-i.yaml
│   │   │       ├── tsop-ii.yaml
│   │   │       ├── tsot.yaml
│   │   │       ├── tssop.yaml
│   │   │       ├── vqfp.yaml
│   │   │       └── vssop.yaml
│   │   ├── Package_NoLead__DFN_QFN_LGA_SON/
│   │   │   ├── Readme.md
│   │   │   ├── ipc_noLead_generator.py
│   │   │   ├── qfn.py
│   │   │   ├── qfn.yml
│   │   │   └── size_definitions/
│   │   │       ├── MicroSiP.yaml
│   │   │       ├── csp.yaml
│   │   │       ├── dfn.yaml
│   │   │       ├── hvson8.yaml
│   │   │       ├── lfcsp.yaml
│   │   │       ├── lga.yaml
│   │   │       ├── oscillator.yaml
│   │   │       ├── qfn/
│   │   │       │   ├── hvqfn.yaml
│   │   │       │   ├── qfn-1x.yaml
│   │   │       │   ├── qfn-20.yaml
│   │   │       │   ├── qfn-24.yaml
│   │   │       │   ├── qfn-28.yaml
│   │   │       │   ├── qfn-3x.yaml
│   │   │       │   ├── qfn-4x.yaml
│   │   │       │   ├── qfn-5x.yaml
│   │   │       │   ├── qfn-64_9x9.yaml
│   │   │       │   ├── qfn-6x.yaml
│   │   │       │   ├── qfn-7x.yaml
│   │   │       │   ├── qfn-mini-circuits.yaml
│   │   │       │   ├── qfn-onsemi-vct.yml
│   │   │       │   ├── qfn-other-pincounts.yaml
│   │   │       │   ├── qfn_texas.yaml
│   │   │       │   ├── special_qfn.yaml
│   │   │       │   ├── tqfn.yaml
│   │   │       │   ├── ufqfpn.yaml
│   │   │       │   ├── uqfn.yaml
│   │   │       │   ├── vqfn.yaml
│   │   │       │   └── wqfn.yaml
│   │   │       ├── vson.yaml
│   │   │       ├── wdfn-8.yml
│   │   │       └── wson.yaml
│   │   ├── Package_PLCC/
│   │   │   ├── ipc_plcc_jLead_generator.py
│   │   │   └── plcc_jLead_definitions.yaml
│   │   ├── TO_SOT_Packages_SMD/
│   │   │   ├── DPAK.py
│   │   │   ├── DPAK_README.md
│   │   │   ├── DPAK_config.yaml
│   │   │   └── make_DPAK.py
│   │   ├── TO_SOT_THT/
│   │   │   ├── TO_SOT_THT_generate.py
│   │   │   ├── TO_THT_packages.py
│   │   │   └── tools.py
│   │   ├── ipc_definitions.yaml
│   │   ├── package_config_KLCv3.yaml
│   │   └── utils/
│   │       └── ep_handling_utils.py
│   ├── PadGenerator/
│   │   └── RingPad.py
│   ├── Potentiometers/
│   │   ├── make_Potentiometer_SMD.py
│   │   ├── make_Potentiometer_THT.py
│   │   ├── slide_Potentiometer.py
│   │   └── slide_Potentiometer.yaml
│   ├── Recom_DCDC/
│   │   └── Recom_SIP.py
│   ├── ResistorArrays_SIP_THT/
│   │   └── make_Resistor_array_SIP.py
│   ├── Resistor_THT/
│   │   └── make_Resistors_THT.py
│   ├── Resistors_SMD/
│   │   ├── README.md
│   │   ├── generator found under SMD_chip_package_rlc-etc
│   │   └── smd_chip_resistors_smd.csv
│   ├── SMD_chip_package_rlc-etc/
│   │   ├── SMD_chip_devices.yaml
│   │   ├── SMD_chip_package_rlc-etc.py
│   │   ├── config_KLCv3.0.yaml
│   │   ├── ipc7351B_smd_two_terminal_chip.yaml
│   │   ├── ipc_smd_two_terminal_chip.yaml
│   │   └── size_definitions/
│   │       ├── size_capacitor_chip_devices.yaml
│   │       ├── size_default_chip_devices.yaml
│   │       ├── size_default_chip_devices_smaller_0402.yaml
│   │       ├── size_default_chip_devices_smaller_0603.yaml
│   │       ├── size_diode.yaml
│   │       ├── size_fuse.yaml
│   │       ├── size_inductor.yaml
│   │       ├── size_resistor.yaml
│   │       ├── size_tantal.yaml
│   │       └── size_wide_body_chip_resistor.yaml
│   ├── Shielding/
│   │   ├── laird_technologies_smd_shielding.kicad_mod.yaml
│   │   ├── smd_shielding.py
│   │   ├── wuerth_electronic_smd_shielding.py
│   │   ├── wuerth_electronic_tht_shielding.py
│   │   └── wuerth_smd_shielding.kicad_mod.yaml
│   ├── Socket/
│   │   ├── 3M_Textool.py
│   │   └── 3M_Textool.yaml
│   ├── TerminalBlock_4Ucon/
│   │   └── make_TerminalBlock_4Ucon.py
│   ├── TerminalBlock_Altech/
│   │   ├── Altech.py
│   │   └── Altech.yml
│   ├── TerminalBlock_MetzConnect/
│   │   ├── make_SingleTerminalBlock_MetzConnect.py
│   │   └── make_TerminalBlock_MetzConnect.py
│   ├── TerminalBlock_Philmore/
│   │   └── make_TerminalBlock_Philmore.py
│   ├── TerminalBlock_Phoenix/
│   │   └── make_TerminalBlock_Phoenix.py
│   ├── TerminalBlock_RND/
│   │   └── make_TerminalBlock_RND.py
│   ├── TerminalBlock_TE-Connectivity/
│   │   └── make_TerminalBlock_TE-Connectivity.py
│   ├── TerminalBlock_WAGO/
│   │   └── make_TerminalBlock_WAGO.py
│   ├── Vigortronix/
│   │   └── vigotronix.py
│   ├── example_kicadmodtree_script.py
│   ├── general/
│   │   ├── StandardBox.py
│   │   ├── new more powerfull generator found under SMD_chip_package_rlc-etc
│   │   └── smd_chip.py
│   ├── pin-headers_socket-strips/
│   │   ├── make_idc_headers.py
│   │   ├── make_pin_headers.py
│   │   └── make_socket_strips.py
│   └── tools/
│       ├── dict_tools.py
│       ├── drawing_tools.py
│       ├── footprint_global_properties.py
│       ├── footprint_keepout_area.py
│       ├── footprint_scripts_DIP.py
│       ├── footprint_scripts_LEDs.py
│       ├── footprint_scripts_crystals.py
│       ├── footprint_scripts_dsub.py
│       ├── footprint_scripts_pin_headers.py
│       ├── footprint_scripts_potentiometers.py
│       ├── footprint_scripts_resistorlike.py
│       ├── footprint_scripts_sip.py
│       ├── footprint_scripts_terminal_blocks.py
│       ├── footprint_text_fields.py
│       ├── global_config_files/
│       │   ├── config_KLCv1.0.yaml
│       │   ├── config_KLCv2.0.yaml
│       │   ├── config_KLCv3.0.yaml
│       │   └── config_Tera.yaml
│       ├── ipc_pad_size_calculators.py
│       ├── pad_number_generators.py
│       └── quad_dual_pad_border.py
├── setup.py
└── tox.ini
Download .txt
SYMBOL INDEX (1014 symbols across 199 files)

FILE: KicadModTree/FileHandler.py
  class FileHandler (line 20) | class FileHandler(object):
    method __init__ (line 35) | def __init__(self, kicad_mod):
    method writeFile (line 38) | def writeFile(self, filename, **kwargs):
    method serialize (line 64) | def serialize(self, **kwargs):

FILE: KicadModTree/KicadFileHandler.py
  function _get_layer_width (line 37) | def _get_layer_width(layer, width=None):
  class KicadFileHandler (line 44) | class KicadFileHandler(FileHandler):
    method __init__ (line 59) | def __init__(self, kicad_mod):
    method serialize (line 62) | def serialize(self, **kwargs):
    method _serializeTree (line 107) | def _serializeTree(self):
    method _callSerialize (line 154) | def _callSerialize(self, node):
    method _serialize_ArcPoints (line 166) | def _serialize_ArcPoints(self, node):
    method _serialize_Arc (line 177) | def _serialize_Arc(self, node):
    method _serialize_CirclePoints (line 187) | def _serialize_CirclePoints(self, node):
    method _serialize_Circle (line 196) | def _serialize_Circle(self, node):
    method _serialize_LinePoints (line 206) | def _serialize_LinePoints(self, node):
    method _serialize_Line (line 214) | def _serialize_Line(self, node):
    method _serialize_Text (line 227) | def _serialize_Text(self, node):
    method _serialize_Model (line 255) | def _serialize_Model(self, node):
    method _serialize_CustomPadPrimitives (line 268) | def _serialize_CustomPadPrimitives(self, pad):
    method _serialize_Pad (line 310) | def _serialize_Pad(self, node):
    method _serialize_PolygonPoints (line 353) | def _serialize_PolygonPoints(self, node, newline_after_pts=False):
    method _serialize_Polygon (line 369) | def _serialize_Polygon(self, node):

FILE: KicadModTree/ModArgparser.py
  class ParserException (line 27) | class ParserException(Exception):
    method __itruediv__ (line 28) | def __itruediv__(self, *args, **kwargs):
  class ModArgparser (line 32) | class ModArgparser(object):
    method __init__ (line 59) | def __init__(self, footprint_function):
    method add_parameter (line 63) | def add_parameter(self, name, **kwargs):
    method run (line 94) | def run(self):
    method _parse_and_execute_yml (line 140) | def _parse_and_execute_yml(self, filepath):
    method _create_example_data_required (line 167) | def _create_example_data_required(self, **kwargs):
    method _create_example_data_full (line 177) | def _create_example_data_full(self, **kwargs):
    method _create_example_datapoint (line 186) | def _create_example_datapoint(self, type, default):
    method _print_example_yml (line 201) | def _print_example_yml(self):
    method _parse_and_execute_csv (line 210) | def _parse_and_execute_csv(self, filepath):
    method _print_example_csv (line 225) | def _print_example_csv(self):
    method _execute_script (line 232) | def _execute_script(self, **kwargs):

FILE: KicadModTree/Point.py
  class Point2D (line 23) | class Point2D(Vector2D):
    method __init__ (line 24) | def __init__(self, coordinates=None, y=None):
  class Point3D (line 32) | class Point3D(Vector3D):
    method __init__ (line 33) | def __init__(self, coordinates=None, y=None, z=None):
  class Point (line 41) | class Point(Vector3D):
    method __init__ (line 42) | def __init__(self, coordinates=None, y=None, z=None):

FILE: KicadModTree/PolygonPoints.py
  class PolygonPoints (line 23) | class PolygonPoints(object):
    method __init__ (line 42) | def __init__(self, **kwargs):
    method _initNodes (line 46) | def _initNodes(self, **kwargs):
    method _initMirror (line 69) | def _initMirror(self, **kwargs):
    method calculateBoundingBox (line 76) | def calculateBoundingBox(self):
    method findNearestPoints (line 87) | def findNearestPoints(self, other):
    method getPoints (line 111) | def getPoints(self):
    method cut (line 118) | def cut(self, other):
    method rotate (line 146) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method translate (line 162) | def translate(self, distance_vector):
    method __copy__ (line 174) | def __copy__(self):
    method __iter__ (line 177) | def __iter__(self):
    method __getitem__ (line 181) | def __getitem__(self, idx):
    method __len__ (line 184) | def __len__(self):

FILE: KicadModTree/Vector.py
  class Vector2D (line 25) | class Vector2D(object):
    method __init__ (line 37) | def __init__(self, coordinates=None, y=None):
    method round_to (line 67) | def round_to(self, base):
    method distance_to (line 81) | def distance_to(self, value):
    method __arithmetic_parse (line 92) | def __arithmetic_parse(value):
    method __eq__ (line 100) | def __eq__(self, other):
    method __ne__ (line 105) | def __ne__(self, other):
    method __add__ (line 108) | def __add__(self, value):
    method __iadd__ (line 114) | def __iadd__(self, value):
    method __neg__ (line 121) | def __neg__(self):
    method __sub__ (line 124) | def __sub__(self, value):
    method __isub__ (line 130) | def __isub__(self, value):
    method __mul__ (line 137) | def __mul__(self, value):
    method __div__ (line 143) | def __div__(self, value):
    method __truediv__ (line 149) | def __truediv__(self, obj):
    method to_dict (line 152) | def to_dict(self):
    method render (line 155) | def render(self, formatcode):
    method __repr__ (line 163) | def __repr__(self):
    method __str__ (line 166) | def __str__(self):
    method __getitem__ (line 169) | def __getitem__(self, key):
    method __setitem__ (line 177) | def __setitem__(self, key, item):
    method __len__ (line 185) | def __len__(self):
    method __iter__ (line 188) | def __iter__(self):
    method __copy__ (line 192) | def __copy__(self):
    method rotate (line 195) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method to_polar (line 218) | def to_polar(self, origin=(0, 0), use_degrees=True):
    method from_polar (line 240) | def from_polar(radius, angle, origin=(0, 0), use_degrees=True):
    method to_homogeneous (line 262) | def to_homogeneous(self):
    method from_homogeneous (line 269) | def from_homogeneous(source):
  class Vector3D (line 280) | class Vector3D(Vector2D):
    method __init__ (line 294) | def __init__(self, coordinates=None, y=None, z=None):
    method round_to (line 338) | def round_to(self, base):
    method cross_product (line 352) | def cross_product(self, other):
    method dot_product (line 360) | def dot_product(self, other):
    method __arithmetic_parse (line 366) | def __arithmetic_parse(value):
    method __eq__ (line 374) | def __eq__(self, other):
    method __ne__ (line 379) | def __ne__(self, other):
    method __add__ (line 382) | def __add__(self, value):
    method __iadd__ (line 389) | def __iadd__(self, value):
    method __neg__ (line 397) | def __neg__(self):
    method __sub__ (line 402) | def __sub__(self, value):
    method __isub__ (line 409) | def __isub__(self, value):
    method __mul__ (line 417) | def __mul__(self, value):
    method __div__ (line 424) | def __div__(self, value):
    method __truediv__ (line 431) | def __truediv__(self, obj):
    method to_dict (line 434) | def to_dict(self):
    method render (line 437) | def render(self, formatcode):
    method __repr__ (line 446) | def __repr__(self):
    method __str__ (line 449) | def __str__(self):
    method __getitem__ (line 452) | def __getitem__(self, key):
    method __setitem__ (line 462) | def __setitem__(self, key, item):
    method __len__ (line 472) | def __len__(self):
    method __iter__ (line 475) | def __iter__(self):
    method __copy__ (line 480) | def __copy__(self):

FILE: KicadModTree/examples/argparse_example.py
  function example_footprint (line 26) | def example_footprint(args):

FILE: KicadModTree/nodes/Footprint.py
  class Footprint (line 39) | class Footprint(Node):
    method __init__ (line 43) | def __init__(self, name):
    method setName (line 54) | def setName(self, name):
    method setDescription (line 57) | def setDescription(self, description):
    method setTags (line 60) | def setTags(self, tags):
    method setAttribute (line 63) | def setAttribute(self, value):
    method setMaskMargin (line 66) | def setMaskMargin(self, value):
    method setPasteMargin (line 69) | def setPasteMargin(self, value):
    method setPasteMarginRatio (line 72) | def setPasteMarginRatio(self, value):

FILE: KicadModTree/nodes/Node.py
  class MultipleParentsError (line 21) | class MultipleParentsError(RuntimeError):
    method __init__ (line 22) | def __init__(self, message):
  class RecursionDetectedError (line 28) | class RecursionDetectedError(RuntimeError):
    method __init__ (line 29) | def __init__(self, message):
  class Node (line 35) | class Node(object):
    method __init__ (line 36) | def __init__(self):
    method append (line 40) | def append(self, node):
    method extend (line 54) | def extend(self, nodes):
    method remove (line 74) | def remove(self, node):
    method insert (line 86) | def insert(self, node):
    method copy (line 99) | def copy(self):
    method serialize (line 104) | def serialize(self):
    method getNormalChilds (line 110) | def getNormalChilds(self):
    method getVirtualChilds (line 116) | def getVirtualChilds(self):
    method getAllChilds (line 122) | def getAllChilds(self):
    method getParent (line 128) | def getParent(self):
    method getRootNode (line 134) | def getRootNode(self):
    method getRealPosition (line 145) | def getRealPosition(self, coordinate, rotation=None):
    method calculateBoundingBox (line 158) | def calculateBoundingBox(self, outline=None):
    method _getRenderTreeText (line 178) | def _getRenderTreeText(self):
    method _getRenderTreeSymbol (line 184) | def _getRenderTreeSymbol(self):
    method getRenderTree (line 193) | def getRenderTree(self, rendered_nodes=None):
    method getCompleteRenderTree (line 212) | def getCompleteRenderTree(self, rendered_nodes=None):

FILE: KicadModTree/nodes/base/Arc.py
  class Arc (line 22) | class Arc(Node, geometricArc):
    method __init__ (line 55) | def __init__(self, **kwargs):
    method copyReplaceGeometry (line 62) | def copyReplaceGeometry(self, geometry):
    method copy (line 65) | def copy(self):
    method cut (line 71) | def cut(self, *other):
    method calculateBoundingBox (line 85) | def calculateBoundingBox(self):
    method _getRenderTreeText (line 110) | def _getRenderTreeText(self):

FILE: KicadModTree/nodes/base/Circle.py
  class Circle (line 21) | class Circle(Node, geometricCircle):
    method __init__ (line 43) | def __init__(self, **kwargs):
    method rotate (line 50) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method translate (line 65) | def translate(self, distance_vector):
    method cut (line 76) | def cut(self, *other):
    method getRadius (line 79) | def getRadius(self):
    method calculateBoundingBox (line 82) | def calculateBoundingBox(self):
    method _getRenderTreeText (line 90) | def _getRenderTreeText(self):

FILE: KicadModTree/nodes/base/Line.py
  class Line (line 21) | class Line(Node, geometricLine):
    method __init__ (line 43) | def __init__(self, **kwargs):
    method copyReplaceGeometry (line 58) | def copyReplaceGeometry(self, geometry):
    method copy (line 64) | def copy(self):
    method cut (line 70) | def cut(self, *other):
    method _getRenderTreeText (line 84) | def _getRenderTreeText(self):
    method calculateBoundingBox (line 96) | def calculateBoundingBox(self):

FILE: KicadModTree/nodes/base/Model.py
  class Model (line 20) | class Model(Node):
    method __init__ (line 43) | def __init__(self, **kwargs):
    method _getRenderTreeText (line 50) | def _getRenderTreeText(self):

FILE: KicadModTree/nodes/base/Pad.py
  class RoundRadiusHandler (line 27) | class RoundRadiusHandler(object):
    method __init__ (line 47) | def __init__(self, **kwargs):
    method getRadiusRatio (line 60) | def getRadiusRatio(self, shortest_sidelength):
    method getRoundRadius (line 85) | def getRoundRadius(self, shortest_sidelength):
    method roundingRequested (line 93) | def roundingRequested(self):
    method limitMaxRadius (line 112) | def limitMaxRadius(self, limit):
    method __str__ (line 125) | def __str__(self):
  class Pad (line 132) | class Pad(Node):
    method __init__ (line 222) | def __init__(self, **kwargs):
    method _initMirror (line 258) | def _initMirror(self, **kwargs):
    method _initNumber (line 272) | def _initNumber(self, **kwargs):
    method _initType (line 275) | def _initType(self, **kwargs):
    method _initShape (line 282) | def _initShape(self, **kwargs):
    method _initPosition (line 289) | def _initPosition(self, **kwargs):
    method _initSize (line 296) | def _initSize(self, **kwargs):
    method _initOffset (line 301) | def _initOffset(self, **kwargs):
    method _initDrill (line 304) | def _initDrill(self, **kwargs):
    method _initSolderPasteMarginRatio (line 314) | def _initSolderPasteMarginRatio(self, **kwargs):
    method _initSolderPasteMargin (line 317) | def _initSolderPasteMargin(self, **kwargs):
    method _initSolderMaskMargin (line 320) | def _initSolderMaskMargin(self, **kwargs):
    method _initLayers (line 323) | def _initLayers(self, **kwargs):
    method _initRadiusRatio (line 328) | def _initRadiusRatio(self, **kwargs):
    method _initAnchorShape (line 339) | def _initAnchorShape(self, **kwargs):
    method _initShapeInZone (line 344) | def _initShapeInZone(self, **kwargs):
    method rotate (line 350) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method translate (line 369) | def translate(self, distance_vector):
    method calculateBoundingBox (line 381) | def calculateBoundingBox(self):
    method _getRenderTreeText (line 384) | def _getRenderTreeText(self):
    method addPrimitive (line 399) | def addPrimitive(self, p):
    method getRoundRadius (line 406) | def getRoundRadius(self):

FILE: KicadModTree/nodes/base/Polygon.py
  class Polygon (line 21) | class Polygon(Node):
    method __init__ (line 45) | def __init__(self, **kwargs):
    method rotate (line 52) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method translate (line 67) | def translate(self, distance_vector):
    method calculateBoundingBox (line 78) | def calculateBoundingBox(self):
    method _getRenderTreeText (line 81) | def _getRenderTreeText(self):
    method cut (line 101) | def cut(self, other):

FILE: KicadModTree/nodes/base/Text.py
  class Text (line 20) | class Text(Node):
    method __init__ (line 59) | def __init__(self, **kwargs):
    method _initType (line 74) | def _initType(self, **kwargs):
    method rotate (line 79) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method translate (line 98) | def translate(self, distance_vector):
    method calculateBoundingBox (line 109) | def calculateBoundingBox(self):
    method _getRenderTreeText (line 120) | def _getRenderTreeText(self):

FILE: KicadModTree/nodes/specialized/ChamferedPad.py
  class CornerSelection (line 26) | class CornerSelection():
    method __init__ (line 47) | def __init__(self, chamfer_select):
    method selectAll (line 67) | def selectAll(self):
    method clearAll (line 71) | def clearAll(self):
    method setLeft (line 75) | def setLeft(self, value=1):
    method setTop (line 79) | def setTop(self, value=1):
    method setRight (line 83) | def setRight(self, value=1):
    method setBottom (line 87) | def setBottom(self, value=1):
    method isAnySelected (line 91) | def isAnySelected(self):
    method rotateCW (line 97) | def rotateCW(self):
    method rotateCCW (line 106) | def rotateCCW(self):
    method __or__ (line 115) | def __or__(self, other):
    method __ior__ (line 118) | def __ior__(self, other):
    method __and__ (line 123) | def __and__(self, other):
    method __iand__ (line 126) | def __iand__(self, other):
    method __len__ (line 131) | def __len__(self):
    method __iter__ (line 134) | def __iter__(self):
    method __getitem__ (line 140) | def __getitem__(self, item):
    method __setitem__ (line 152) | def __setitem__(self, item, value):
    method to_dict (line 164) | def to_dict(self):
    method __str__ (line 172) | def __str__(self):
  class ChamferedPad (line 176) | class ChamferedPad(Node):
    method __init__ (line 229) | def __init__(self, **kwargs):
    method _initSize (line 238) | def _initSize(self, **kwargs):
    method _initPosition (line 243) | def _initPosition(self, **kwargs):
    method _initMirror (line 248) | def _initMirror(self, **kwargs):
    method _initPadSettings (line 255) | def _initPadSettings(self, **kwargs):
    method _generatePad (line 279) | def _generatePad(self):
    method chamferAvoidCircle (line 345) | def chamferAvoidCircle(self, center, diameter, clearance=0):
    method getVirtualChilds (line 377) | def getVirtualChilds(self):
    method getRoundRadius (line 380) | def getRoundRadius(self):

FILE: KicadModTree/nodes/specialized/ChamferedPadGrid.py
  class ChamferSelPadGrid (line 25) | class ChamferSelPadGrid(CornerSelection):
    method __init__ (line 48) | def __init__(self, chamfer_select):
    method setLeft (line 71) | def setLeft(self, value=1):
    method setTop (line 75) | def setTop(self, value=1):
    method setRight (line 79) | def setRight(self, value=1):
    method setBottom (line 83) | def setBottom(self, value=1):
    method setCorners (line 87) | def setCorners(self, value=1):
    method setEdges (line 93) | def setEdges(self, value=1):
    method __len__ (line 99) | def __len__(self):
    method __iter__ (line 102) | def __iter__(self):
    method __getitem__ (line 110) | def __getitem__(self, item):
    method __setitem__ (line 121) | def __setitem__(self, item, value):
    method to_dict (line 133) | def to_dict(self):
  class ChamferedPadGrid (line 144) | class ChamferedPadGrid(Node):
    method __init__ (line 197) | def __init__(self, **kwargs):
    method _initCount (line 210) | def _initCount(self, **kwargs):
    method _initSize (line 216) | def _initSize(self, **kwargs):
    method _initGrid (line 222) | def _initGrid(self, **kwargs):
    method _initPadSettings (line 228) | def _initPadSettings(self, **kwargs):
    method chamferAvoidCircle (line 253) | def chamferAvoidCircle(self, center, diameter, clearance=0):
    method __padCornerSelection (line 296) | def __padCornerSelection(self, idx_x, idx_y):
    method _generatePads (line 335) | def _generatePads(self):
    method getVirtualChilds (line 354) | def getVirtualChilds(self):
    method __copy__ (line 357) | def __copy__(self):

FILE: KicadModTree/nodes/specialized/ExposedPad.py
  class ExposedPad (line 32) | class ExposedPad(Node):
    method __init__ (line 134) | def __init__(self, **kwargs):
    method _initNumber (line 155) | def _initNumber(self, **kwargs):
    method _initSize (line 160) | def _initSize(self, **kwargs):
    method setViaLayout (line 170) | def setViaLayout(self, layout):
    method __initViaGrid (line 177) | def __initViaGrid(self, **kwargs):
    method _initThermalVias (line 192) | def _initThermalVias(self, **kwargs):
    method __viasInMaskCount (line 213) | def __viasInMaskCount(self, idx):
    method _initPasteForAvoidingVias (line 224) | def _initPasteForAvoidingVias(self, **kwargs):
    method _initPaste (line 246) | def _initPaste(self, **kwargs):
    method __createPasteIgnoreVia (line 262) | def __createPasteIgnoreVia(self):
    method __createPasteGrids (line 288) | def __createPasteGrids(original, grid, count, center):
    method __createPasteAvoidViasInside (line 311) | def __createPasteAvoidViasInside(self):
    method __createPasteOutsideX (line 341) | def __createPasteOutsideX(self):
    method __createPasteOutsideY (line 386) | def __createPasteOutsideY(self):
    method __createPasteOutsideCorners (line 432) | def __createPasteOutsideCorners(self):
    method __createPasteAvoidViasOutside (line 470) | def __createPasteAvoidViasOutside(self):
    method __createPaste (line 488) | def __createPaste(self):
    method __createMainPad (line 505) | def __createMainPad(self):
    method __createVias (line 525) | def __createVias(self):
    method getVirtualChilds (line 554) | def getVirtualChilds(self):
    method getRoundRadius (line 566) | def getRoundRadius(self):

FILE: KicadModTree/nodes/specialized/FilledRect.py
  class FilledRect (line 22) | class FilledRect(Node):
    method __init__ (line 46) | def __init__(self, **kwargs):
    method getVirtualChilds (line 62) | def getVirtualChilds(self):
    method _getRenderTreeText (line 65) | def _getRenderTreeText(self):

FILE: KicadModTree/nodes/specialized/PadArray.py
  class PadArray (line 27) | class PadArray(Node):
    method __init__ (line 94) | def __init__(self, **kwargs):
    method _initPincount (line 104) | def _initPincount(self, **kwargs):
    method _initStartingPosition (line 126) | def _initStartingPosition(self, **kwargs):
    method _initInitialNumber (line 154) | def _initInitialNumber(self, **kwargs):
    method _initIncrement (line 164) | def _initIncrement(self, **kwargs):
    method _initSpacing (line 168) | def _initSpacing(self, **kwargs):
    method _createPads (line 202) | def _createPads(self, **kwargs):
    method getVirtualChilds (line 297) | def getVirtualChilds(self):

FILE: KicadModTree/nodes/specialized/PolygoneLine.py
  class PolygoneLine (line 22) | class PolygoneLine(Node):
    method __init__ (line 42) | def __init__(self, **kwargs):
    method _initPolyPoint (line 52) | def _initPolyPoint(self, **kwargs):
    method _createChildNodes (line 55) | def _createChildNodes(self, polygone_line):
    method getVirtualChilds (line 65) | def getVirtualChilds(self):
    method _getRenderTreeText (line 68) | def _getRenderTreeText(self):

FILE: KicadModTree/nodes/specialized/RectFill.py
  class RectFill (line 21) | class RectFill(Node):
    method __init__ (line 45) | def __init__(self, **kwargs):
    method _createChildNodes (line 55) | def _createChildNodes(self, start_pos, end_pos, layer, width):
    method getVirtualChilds (line 72) | def getVirtualChilds(self):
    method _getRenderTreeText (line 75) | def _getRenderTreeText(self):

FILE: KicadModTree/nodes/specialized/RectLine.py
  class RectLine (line 21) | class RectLine(PolygoneLine):
    method __init__ (line 45) | def __init__(self, **kwargs):
    method _getRenderTreeText (line 86) | def _getRenderTreeText(self):

FILE: KicadModTree/nodes/specialized/RingPad.py
  class RingPadPrimitive (line 30) | class RingPadPrimitive(Node):
    method __init__ (line 49) | def __init__(self, **kwargs):
    method copy (line 57) | def copy(self):
    method getVirtualChilds (line 64) | def getVirtualChilds(self):
  class ArcPadPrimitive (line 77) | class ArcPadPrimitive(Node):
    method __init__ (line 106) | def __init__(self, **kwargs):
    method setRoundRadius (line 118) | def setRoundRadius(self, **kwargs):
    method setLimitingLines (line 129) | def setLimitingLines(self, **kwargs):
    method copy (line 139) | def copy(self):
    method rotate (line 151) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method translate (line 170) | def translate(self, distance_vector):
    method _getStep (line 185) | def _getStep(self):
    method _getArcPrimitives (line 193) | def _getArcPrimitives(self):
    method __cutArcs (line 218) | def __cutArcs(self, arcs, line, index_to_keep):
    method getVirtualChilds (line 230) | def getVirtualChilds(self):
  class RingPad (line 243) | class RingPad(Node):
    method __init__ (line 288) | def __init__(self, **kwargs):
    method _initSize (line 299) | def _initSize(self, **kwargs):
    method _initNumber (line 314) | def _initNumber(self, **kwargs):
    method _initNumAnchor (line 317) | def _initNumAnchor(self, **kwargs):
    method _initPosition (line 322) | def _initPosition(self, **kwargs):
    method _initPasteSettings (line 327) | def _initPasteSettings(self, **kwargs):
    method _generatePads (line 357) | def _generatePads(self):
    method _generatePastePads (line 375) | def _generatePastePads(self):
    method _generateMaskPads (line 406) | def _generateMaskPads(self):
    method _generateCopperPads (line 417) | def _generateCopperPads(self):
    method getVirtualChilds (line 457) | def getVirtualChilds(self):

FILE: KicadModTree/nodes/specialized/Rotation.py
  class Rotation (line 22) | class Rotation(Node):
    method __init__ (line 34) | def __init__(self, r):
    method getRealPosition (line 38) | def getRealPosition(self, coordinate, rotation=None):
    method _getRenderTreeText (line 58) | def _getRenderTreeText(self):

FILE: KicadModTree/nodes/specialized/Translation.py
  class Translation (line 20) | class Translation(Node):
    method __init__ (line 33) | def __init__(self, x, y):
    method getRealPosition (line 40) | def getRealPosition(self, coordinate, rotation=None):
    method _getRenderTreeText (line 55) | def _getRenderTreeText(self):

FILE: KicadModTree/tests/datatypes/test_Vector2D.py
  class Vector2DTests (line 21) | class Vector2DTests(unittest.TestCase):
    method test_init (line 23) | def test_init(self):
    method test_round_to (line 52) | def test_round_to(self):
    method test_add (line 73) | def test_add(self):
    method test_sub (line 96) | def test_sub(self):
    method test_mul (line 119) | def test_mul(self):
    method test_div (line 142) | def test_div(self):
    method test_polar (line 166) | def test_polar(self):

FILE: KicadModTree/tests/datatypes/test_Vector3D.py
  class Vector3DTests (line 21) | class Vector3DTests(unittest.TestCase):
    method test_init (line 23) | def test_init(self):
    method test_round_to (line 78) | def test_round_to(self):
    method test_add (line 104) | def test_add(self):
    method test_sub (line 132) | def test_sub(self):
    method test_mul (line 160) | def test_mul(self):
    method test_div (line 188) | def test_div(self):

FILE: KicadModTree/tests/moduletests/test_arc.py
  class ArcTests (line 76) | class ArcTests(unittest.TestCase):
    method testArcsKx90deg (line 78) | def testArcsKx90deg(self):
    method testArcsKx90degOffsetRotated (line 170) | def testArcsKx90degOffsetRotated(self):

FILE: KicadModTree/tests/moduletests/test_exposed_pad.py
  class ExposedPadTests (line 1244) | class ExposedPadTests(unittest.TestCase):
    method testSimpleExposedPad (line 1246) | def testSimpleExposedPad(self):
    method testSimpleExposedPadNoRounding (line 1265) | def testSimpleExposedPadNoRounding(self):
    method testSimpleExposedMinimal (line 1285) | def testSimpleExposedMinimal(self):
    method testExposedPasteAutogenInner (line 1303) | def testExposedPasteAutogenInner(self):
    method testExposedPasteAutogenInner2 (line 1322) | def testExposedPasteAutogenInner2(self):
    method testExposedPasteAutogenInnerAndOuther (line 1341) | def testExposedPasteAutogenInnerAndOuther(self):
    method testExposedPasteAutogenInnerYonlyAndOuther (line 1362) | def testExposedPasteAutogenInnerYonlyAndOuther(self):
    method testExposedPasteAutogenInnerXonlyAndOuther (line 1381) | def testExposedPasteAutogenInnerXonlyAndOuther(self):
    method testExposedPasteAutogenOnlyOuther (line 1400) | def testExposedPasteAutogenOnlyOuther(self):
    method testExposedPasteBottomPadTests (line 1419) | def testExposedPasteBottomPadTests(self):
    method testExposed4x4paste (line 1444) | def testExposed4x4paste(self):
    method testExposedPadEdgeCase1 (line 1473) | def testExposedPadEdgeCase1(self):
    method testExposedPasteViaTented (line 1505) | def testExposedPasteViaTented(self):

FILE: KicadModTree/tests/moduletests/test_kicad5_padshapes.py
  class Kicad5PadsTests (line 342) | class Kicad5PadsTests(unittest.TestCase):
    method testRoundRectPad (line 344) | def testRoundRectPad(self):
    method testRoundRectPad2 (line 370) | def testRoundRectPad2(self):
    method testPolygonPad (line 396) | def testPolygonPad(self):
    method testCustomPadOtherPrimitives (line 415) | def testCustomPadOtherPrimitives(self):
    method testCutPolygon (line 457) | def testCutPolygon(self):
    method testChamferedPad (line 480) | def testChamferedPad(self):
    method testChamferedPadAvoidCircle (line 506) | def testChamferedPadAvoidCircle(self):
    method testChamferedPadGrid (line 533) | def testChamferedPadGrid(self):
    method testChamferedPadGridCornerOnly (line 555) | def testChamferedPadGridCornerOnly(self):
    method testChamferedRoundedPad (line 586) | def testChamferedRoundedPad(self):

FILE: KicadModTree/tests/moduletests/test_rotation.py
  class RotationTests (line 156) | class RotationTests(unittest.TestCase):
    method testTextRotation (line 158) | def testTextRotation(self):
    method testLineRotation (line 172) | def testLineRotation(self):
    method testArcRotation (line 187) | def testArcRotation(self):
    method testCircleRotation (line 205) | def testCircleRotation(self):
    method testPolygonRotation (line 220) | def testPolygonRotation(self):
    method testPadRotation (line 235) | def testPadRotation(self):

FILE: KicadModTree/tests/moduletests/test_simple_footprints.py
  class SimpleFootprintTests (line 75) | class SimpleFootprintTests(unittest.TestCase):
    method testMinimum (line 77) | def testMinimum(self):
    method testBasicTags (line 83) | def testBasicTags(self):
    method testSampleFootprint (line 93) | def testSampleFootprint(self):
    method testBasicNodes (line 113) | def testBasicNodes(self):

FILE: KicadModTree/tests/nodes/test_Node.py
  class TestChildNode (line 21) | class TestChildNode(Node):
    method __init__ (line 22) | def __init__(self):
  class NodeTests (line 26) | class NodeTests(unittest.TestCase):
    method testInit (line 28) | def testInit(self):
    method testAppend (line 36) | def testAppend(self):
    method testExtend (line 96) | def testExtend(self):
    method testRemove (line 182) | def testRemove(self):
    method testInsert (line 233) | def testInsert(self):
    method testInsertWithManyChilds (line 254) | def testInsertWithManyChilds(self):

FILE: KicadModTree/tests/test.py
  function run_tests (line 27) | def run_tests():

FILE: KicadModTree/util/geometric_util.py
  class geometricLine (line 21) | class geometricLine():
    method __init__ (line 31) | def __init__(self, **kwargs):
    method copy (line 40) | def copy(self):
    method rotate (line 43) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method translate (line 59) | def translate(self, distance_vector):
    method isPointOnSelf (line 71) | def isPointOnSelf(self, point, tolerance=1e-7):
    method sortPointsRelativeToStart (line 86) | def sortPointsRelativeToStart(self, points):
    method cut (line 105) | def cut(self, *other):
    method to_homogeneous (line 128) | def to_homogeneous(self):
    method __iter__ (line 135) | def __iter__(self):
    method __len__ (line 139) | def __len__(self):
    method __getitem__ (line 142) | def __getitem__(self, key):
    method __setitem__ (line 150) | def __setitem__(self, key, item):
  class geometricCircle (line 159) | class geometricCircle():
    method __init__ (line 169) | def __init__(self, center, radius):
    method getRadius (line 173) | def getRadius(self):
    method rotate (line 176) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method translate (line 191) | def translate(self, distance_vector):
    method isPointOnSelf (line 202) | def isPointOnSelf(self, point, tolerance=1e-7):
    method sortPointsRelativeToStart (line 216) | def sortPointsRelativeToStart(self, points):
    method cut (line 226) | def cut(self, *other):
    method __iter__ (line 237) | def __iter__(self):
    method __len__ (line 240) | def __len__(self):
    method __getitem__ (line 243) | def __getitem__(self, key):
    method __setitem__ (line 249) | def __setitem__(self, key, item):
  class geometricArc (line 256) | class geometricArc():
    method __init__ (line 275) | def __init__(self, **kwargs):
    method normalizeAngle (line 292) | def normalizeAngle(angle):
    method _initAngle (line 298) | def _initAngle(self, angle):
    method _initFromCenterAndAngle (line 301) | def _initFromCenterAndAngle(self, **kwargs):
    method _initFromCenterAndEnd (line 317) | def _initFromCenterAndEnd(self, **kwargs):
    method rotate (line 346) | def rotate(self, angle, origin=(0, 0), use_degrees=True):
    method translate (line 362) | def translate(self, distance_vector):
    method getRadius (line 374) | def getRadius(self):
    method getStartPoint (line 378) | def getStartPoint(self):
    method getMidPoint (line 381) | def getMidPoint(self):
    method getEndPoint (line 384) | def getEndPoint(self):
    method setRadius (line 387) | def setRadius(self, radius):
    method _calulateEndPos (line 392) | def _calulateEndPos(self):
    method _toLocalCoordinates (line 400) | def _toLocalCoordinates(self, point):
    method _compareAngles (line 409) | def _compareAngles(self, a1, a2, tolerance=1e-7):
    method isPointOnSelf (line 438) | def isPointOnSelf(self, point, tolerance=1e-7):
    method sortPointsRelativeToStart (line 457) | def sortPointsRelativeToStart(self, points):
    method cut (line 480) | def cut(self, *other):
    method __iter__ (line 508) | def __iter__(self):
    method __len__ (line 512) | def __len__(self):
    method __getitem__ (line 515) | def __getitem__(self, key):
    method __setitem__ (line 523) | def __setitem__(self, key, item):
  class BaseNodeIntersection (line 532) | class BaseNodeIntersection():
    method intersectTwoNodes (line 534) | def intersectTwoNodes(*nodes):
    method intersectTwoLines (line 566) | def intersectTwoLines(line1, line2):
    method intersectLineWithCircle (line 578) | def intersectLineWithCircle(line, circle):

FILE: KicadModTree/util/kicad_util.py
  function formatFloat (line 20) | def formatFloat(val):
  function lispString (line 30) | def lispString(string):
  function lispTokenizer (line 43) | def lispTokenizer(input):
  function parseLispString (line 92) | def parseLispString(input):
  class SexprSerializer (line 122) | class SexprSerializer(object):
    method __init__ (line 129) | def __init__(self, sexpr):
    method primitive_to_string (line 135) | def primitive_to_string(self, primitive):
    method sexpr_to_string (line 146) | def sexpr_to_string(self, sexpr, prefix=None):
    method __str__ (line 188) | def __str__(self):
  function parseTimestamp (line 195) | def parseTimestamp(timestamp):
  function formatTimestamp (line 200) | def formatTimestamp(timestamp=None):

FILE: KicadModTree/util/paramUtil.py
  function toNumberArray (line 21) | def toNumberArray(value, length=2, min_value=1, member_type=int):
  function toIntArray (line 70) | def toIntArray(value, length=2, min_value=1):
  function toFloatArray (line 91) | def toFloatArray(value, length=2, min_value=1):
  function isAnyLarger (line 112) | def isAnyLarger(values, low_limits, must_be_larger=False):
  function toVectorUseCopyIfNumber (line 133) | def toVectorUseCopyIfNumber(value, length=2, low_limit=None, must_be_lar...
  function getOptionalNumberTypeParam (line 171) | def getOptionalNumberTypeParam(
  function round_to (line 212) | def round_to(value, base):

FILE: scripts/Battery/BatteryHolder.py
  function qfn (line 16) | def qfn(args):

FILE: scripts/Buttons_Switches/rotary_coded_switch.py
  function rotary_coded_switch (line 11) | def rotary_coded_switch(args):

FILE: scripts/Buzzers_Beepers/buzzer_round_tht.py
  function buzzer_round_tht (line 12) | def buzzer_round_tht(args):

FILE: scripts/Capacitors_SMD/CP_Elec_round.py
  function create_footprint (line 16) | def create_footprint(name, configuration, **kwargs):
  function parse_and_execute_yml_file (line 188) | def parse_and_execute_yml_file(filepath, configuration):

FILE: scripts/Capacitors_SMD/C_Elec_round.py
  function create_footprint (line 16) | def create_footprint(name, configuration, **kwargs):

FILE: scripts/Capacitors_SMD/C_Trimmer_factory.py
  class Dimensions (line 15) | class Dimensions(object):
    method __init__ (line 17) | def __init__(self, base, variant, cut_pin=False, tab_linked=False):
    method _round_to (line 61) | def _round_to(self, n, precision):
    method _footprint_name (line 66) | def _footprint_name(self, manufacturer, series):
  class CapacitorTrimmer (line 71) | class CapacitorTrimmer(object):
    method __init__ (line 73) | def __init__(self, config_file):
    method _load_config (line 78) | def _load_config(self, config_file):
    method _add_properties (line 92) | def _add_properties(self, m, variant):
    method _add_labels (line 99) | def _add_labels(self, m, variant, dim):
    method _draw_pads (line 107) | def _draw_pads(self, m, variant, dim):
    method _draw_fab_outline (line 119) | def _draw_fab_outline(self, m, variant, dim, width, offset):
    method _draw_silk_outline (line 148) | def _draw_silk_outline(self, m, variant, dim, width, offset):
    method _draw_courtyard (line 163) | def _draw_courtyard(self, m ,dim):
    method _add_3D_model (line 170) | def _add_3D_model(self, m, base, dim):
    method _build_footprint (line 177) | def _build_footprint(self, base, variant, cut_pin=False, tab_linked=Fa...
    method build_series (line 212) | def build_series(self, verbose=False):
  class StyleA (line 219) | class StyleA(CapacitorTrimmer):
    method __init__ (line 221) | def __init__(self, config_file):
  class StyleB (line 226) | class StyleB(CapacitorTrimmer):
    method __init__ (line 228) | def __init__(self, config_file):
  class StyleC (line 233) | class StyleC(CapacitorTrimmer):
    method __init__ (line 235) | def __init__(self, config_file):
  class StyleD (line 240) | class StyleD(CapacitorTrimmer):
    method __init__ (line 242) | def __init__(self, config_file):
  class Factory (line 247) | class Factory(object):
    method __init__ (line 249) | def __init__(self, config_file):
    method _parse_command_line (line 255) | def _parse_command_line(self):
    method _create_build_list (line 263) | def _create_build_list(self):

FILE: scripts/Capacitors_SMD/bump.py
  function add_bump (line 3) | def add_bump(m, anchor_pos, bump_length, bump_width, direction, layer, w...

FILE: scripts/Capacitors_SMD/chamfers.py
  function add_rect_chamfer (line 3) | def add_rect_chamfer(m, start_pos, end_pos, layer, width, offset=(0,0), ...

FILE: scripts/Capacitors_SMD/corners.py
  function add_corners (line 3) | def add_corners(m, start_pos, end_pos, size_x, size_y, layer, width, off...

FILE: scripts/Connector/Connector_Harwin/conn_harwin_m20-781xx45_smd_top_dual_row.py
  function generate_footprint (line 43) | def generate_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Harwin/m20-89xx.py
  function roundToBase (line 24) | def roundToBase(value, base):
  function gen_fab_pins (line 29) | def gen_fab_pins(origx, origy, kicad_mod, configuration):
  function gen_silk_pins (line 47) | def gen_silk_pins(origx, origy, kicad_mod, configuration, fill):
  function gen_footprint (line 71) | def gen_footprint(pinnum, manpart, configuration):
  function gen_family (line 190) | def gen_family(configuration):

FILE: scripts/Connector/Connector_Hirose/conn_ffc_hirose_fh12_smd_side.py
  function generate_one_footprint (line 54) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Hirose/conn_hirose_df11_tht_top.py
  function generate_one_footprint (line 53) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Hirose/conn_hirose_df12c_ds_smd_top.py
  function generate_one_footprint (line 49) | def generate_one_footprint(idx, pins, configuration):

FILE: scripts/Connector/Connector_Hirose/conn_hirose_df12e_dp_smd_top.py
  function generate_one_footprint (line 49) | def generate_one_footprint(idx, pins, configuration):

FILE: scripts/Connector/Connector_Hirose/conn_hirose_df13_tht_side.py
  function generate_one_footprint (line 53) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Hirose/conn_hirose_df13_tht_top.py
  function generate_one_footprint (line 53) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Hirose/conn_hirose_df13c_smd_top.py
  function generate_one_footprint (line 51) | def generate_one_footprint(idx, pins, configuration):

FILE: scripts/Connector/Connector_Hirose/conn_hirose_df63_tht_top.py
  function generate_one_footprint (line 83) | def generate_one_footprint(pins, form_type, configuration):

FILE: scripts/Connector/Connector_Hirose/helpers.py
  function roundToBase (line 1) | def roundToBase(value, base):

FILE: scripts/Connector/Connector_Hirose/not_in_official_lib/df63_angled.py
  function outline (line 134) | def outline(offset=0):

FILE: scripts/Connector/Connector_IEC_DIN/generate_din41612.py
  function AllPins (line 49) | def AllPins(row, col):
  function EvenColPins (line 52) | def EvenColPins(row, col):
  function OptionalPin (line 55) | def OptionalPin(kicad_mod, row, col, row_step, col_step, pin_pad, pin_dr...
  function BFemale (line 77) | def BFemale(size, pin_cb, more_description):
  function BMale (line 219) | def BMale(size, pin_cb, more_description):

FILE: scripts/Connector/Connector_JAE/conn_ffc_jae_ff08.py
  function make_module (line 41) | def make_module(pin_count, configuration):

FILE: scripts/Connector/Connector_JAE/conn_jae_LY20_tht_side.py
  function incrementPadNumber (line 55) | def incrementPadNumber(old_number):
  function make_module (line 63) | def make_module(pins_per_row, configuration):

FILE: scripts/Connector/Connector_JAE/conn_jae_LY20_tht_top.py
  function incrementPadNumber (line 55) | def incrementPadNumber(old_number):
  function make_module (line 63) | def make_module(pins_per_row, configuration):

FILE: scripts/Connector/Connector_JAE/helpers.py
  function roundToBase (line 1) | def roundToBase(value, base):

FILE: scripts/Connector/Connector_JST/conn_jst_J2100_tht_side.py
  function incrementPadNumber (line 55) | def incrementPadNumber(old_number):
  function generate_one_footprint (line 59) | def generate_one_footprint(pins, configuration, keying):

FILE: scripts/Connector/Connector_JST/conn_jst_J2100_tht_top.py
  function incrementPadNumber (line 56) | def incrementPadNumber(old_number):
  function generate_one_footprint (line 61) | def generate_one_footprint(pins, configuration, keying):

FILE: scripts/Connector/Connector_JST/conn_jst_JWPF_tht_top.py
  function generate_one_footprint (line 59) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_NV_tht_top.py
  function generate_one_footprint (line 50) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_PHD_horizontal.py
  function generate_one_footprint (line 50) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_PHD_vertical.py
  function generate_one_footprint (line 50) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_PUD_tht_side.py
  function generate_one_footprint (line 55) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_PUD_tht_top.py
  function generate_one_footprint (line 53) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_VH_tht_side-stabilizer.py
  function generate_one_footprint (line 52) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_VH_tht_side.py
  function generate_one_footprint (line 51) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_VH_tht_top-shrouded.py
  function generate_one_footprint (line 50) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_eh_tht_side.py
  function generate_one_footprint (line 29) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_eh_tht_top.py
  function generate_one_footprint (line 28) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_ph_tht_side.py
  function generate_one_footprint (line 42) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_ph_tht_top.py
  function generate_one_footprint (line 43) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_vh_tht_top.py
  function generate_one_footprint (line 48) | def generate_one_footprint(pins, series_params, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_xh_tht_side.py
  function generate_one_footprint (line 62) | def generate_one_footprint(pins, variant, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_xh_tht_top.py
  function generate_one_footprint (line 68) | def generate_one_footprint(pins, variant, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_ze_tht_side.py
  function generate_one_footprint (line 31) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_JST/conn_jst_ze_tht_top.py
  function generate_one_footprint (line 47) | def generate_one_footprint(pincount, variant, configuration):

FILE: scripts/Connector/Connector_JST/helpers.py
  function roundToBase (line 1) | def roundToBase(value, base):

FILE: scripts/Connector/Connector_Molex/conn_ffc_molex_200528.py
  function make_module (line 44) | def make_module(pin_count, configuration):

FILE: scripts/Connector/Connector_Molex/conn_ffc_molex_502250.py
  function make_module (line 41) | def make_module(pin_count, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_SPOX_tht_side.py
  function generate_one_footprint (line 64) | def generate_one_footprint(pins_per_row, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_SPOX_tht_top.py
  function generate_one_footprint (line 68) | def generate_one_footprint(pins_per_row, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_kk_254_tht_top.py
  function generate_one_footprint (line 60) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_kk_396_tht_top.py
  function generate_one_footprint (line 60) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_mega-fit_tht_side_dual-row.py
  function generate_one_footprint (line 70) | def generate_one_footprint(pins_per_row, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_mega-fit_tht_top_dual_row.py
  function generate_one_footprint (line 86) | def generate_one_footprint(pins_per_row, variant, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-clasp_tht_side.py
  function generate_one_footprint (line 80) | def generate_one_footprint(pins, variant, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-clasp_tht_top.py
  function generate_one_footprint (line 82) | def generate_one_footprint(pins, variant, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_smd_side_dual_row.py
  function generate_one_footprint (line 62) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_smd_top_dual_row.py
  function generate_one_footprint (line 72) | def generate_one_footprint(pins_per_row, variant, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_tht_side_dual_row.py
  function generate_one_footprint (line 55) | def generate_one_footprint(pins, configuration, variant):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_tht_side_single_row.py
  function generate_one_footprint (line 73) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_tht_top_dual_row.py
  function generate_one_footprint (line 76) | def generate_one_footprint(pins_per_row, variant, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_tht_top_single_row.py
  function generate_one_footprint (line 75) | def generate_one_footprint(pins_per_row, variant, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-latch_tht_side.py
  function generate_one_footprint (line 72) | def generate_one_footprint(pins_per_row, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_micro-latch_tht_top.py
  function generate_one_footprint (line 72) | def generate_one_footprint(pins_per_row, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_mini-fit-sr_tht_side.py
  function generate_one_footprint (line 85) | def generate_one_footprint(pins, params, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_mini-fit-sr_tht_top.py
  function generate_one_footprint (line 83) | def generate_one_footprint(pins, params, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_mini-fit-sr_tht_top_dual.py
  function generate_one_footprint (line 82) | def generate_one_footprint(pins, params, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_mini-fit_Jr_tht_side_dual-row.py
  function generate_one_footprint (line 88) | def generate_one_footprint(pins_per_row, variant, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_mini-fit_Jr_tht_top_dual-row.py
  function generate_one_footprint (line 88) | def generate_one_footprint(pins_per_row, variant, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_nano-fit_tht_side.py
  function generate_one_footprint (line 67) | def generate_one_footprint(pins, params, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_nano-fit_tht_top.py
  function generate_one_footprint (line 67) | def generate_one_footprint(pins, params, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_picoblade_tht_side.py
  function generate_one_footprint (line 68) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_picoblade_tht_top.py
  function generate_one_footprint (line 68) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_picoflex_smd_top.py
  function generate_one_footprint (line 50) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_picoflex_tht_top.py
  function generate_one_footprint (line 61) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_sabre_tht_side.py
  function generate_one_footprint (line 106) | def generate_one_footprint(pins, params, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_sabre_tht_top.py
  function generate_one_footprint (line 106) | def generate_one_footprint(pins, params, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_slimstack-501920.py
  function generate_one_footprint (line 49) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_slimstack-502426.py
  function generate_one_footprint (line 63) | def generate_one_footprint(partnumber, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_slimstack-502430.py
  function generate_one_footprint (line 68) | def generate_one_footprint(partnumber, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_slimstack-52991.py
  function generate_one_footprint (line 49) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_slimstack-53748.py
  function generate_one_footprint (line 50) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_slimstack-54722.py
  function generate_one_footprint (line 49) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_slimstack-55560.py
  function generate_one_footprint (line 49) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_Molex/conn_molex_stackable-linear_tht_top.py
  function generate_one_footprint (line 74) | def generate_one_footprint(pins_per_row, variant, configuration):

FILE: scripts/Connector/Connector_Molex/helpers.py
  function roundToBase (line 1) | def roundToBase(value, base):

FILE: scripts/Connector/Connector_PhoenixContact/helpers.py
  function round_to (line 1) | def round_to(value, base):
  function v_add (line 4) | def v_add(p1,p2):
  function round_crty_point (line 7) | def round_crty_point(point, grid_size):
  function offset_dir (line 10) | def offset_dir(coordinate, offset, center=0):
  function v_offset (line 18) | def v_offset(point, offset, center = (0,0)):
  function offset_polyline (line 37) | def offset_polyline(polyline_points, offset, center=(0,0)):
  function create_pin1_marker_triangle (line 44) | def create_pin1_marker_triangle(bottom_y, center_x = 0, dimensions = [0....
  function create_pin1_marker_corner (line 58) | def create_pin1_marker_corner(top_y, left_x, sidelength = [1,1]):

FILE: scripts/Connector/Connector_PhoenixContact/mc.py
  function generate_one_footprint (line 23) | def generate_one_footprint(motel, params, configuration):

FILE: scripts/Connector/Connector_PhoenixContact/mc_params.py
  class seriesParams (line 4) | class seriesParams():
  function generate_params (line 59) | def generate_params(num_pins, series_name, pin_pitch, angled, flanged, o...
  function dimensions (line 359) | def dimensions(params):
  function generate_description (line 373) | def generate_description(params, mpn):

FILE: scripts/Connector/Connector_PhoenixContact/mstb.py
  function generate_one_footprint (line 24) | def generate_one_footprint(model, params, configuration):

FILE: scripts/Connector/Connector_PhoenixContact/mstb_params.py
  class seriesParams (line 4) | class seriesParams():
  function generate_params (line 44) | def generate_params(num_pins, series_name, pin_pitch, angled, flanged, o...
  function dimensions (line 364) | def dimensions(params):
  function generate_description (line 376) | def generate_description(params, mpn):

FILE: scripts/Connector/Connector_SMD_single_row_plus_mounting_pad/helpers.py
  function roundToBase (line 4) | def roundToBase(value, base):
  function parseAdditionalDrawing (line 7) | def parseAdditionalDrawing(footprint, drawing_definition, configuration,...

FILE: scripts/Connector/Connector_SMD_single_row_plus_mounting_pad/smd_single_row_plus_mounting_pad.py
  function generate_one_footprint (line 19) | def generate_one_footprint(idx, pincount, series_definition, configurati...
  function generate_series (line 385) | def generate_series(configuration, series_definition, id, group_definiti...

FILE: scripts/Connector/Connector_Samtec/conn_samtec_LSHM_smd_top.py
  function generate_one_footprint (line 68) | def generate_one_footprint(pins_per_row, params, configuration):

FILE: scripts/Connector/Connector_Samtec/conn_samtec_hle.py
  function generate_one_footprint (line 149) | def generate_one_footprint(pins_per_row, variant, configuration):

FILE: scripts/Connector/Connector_Samtec/helpers.py
  function roundToBase (line 1) | def roundToBase(value, base):

FILE: scripts/Connector/Connector_Samtec/mecf_connector.py
  function generate_one_footprint (line 69) | def generate_one_footprint(pol, n, configuration):

FILE: scripts/Connector/Connector_Samtec/mecf_socket.py
  function generate_one_footprint (line 100) | def generate_one_footprint(weld, pol, pcb_thickness, n, configuration):

FILE: scripts/Connector/Connector_TE-Connectivity/conn_ffc_te_84952-84953.py
  function generate_one_footprint (line 53) | def generate_one_footprint(partnumber, pincount, configuration):

FILE: scripts/Connector/Connector_TE-Connectivity/conn_fpc_te_1734839.py
  function generate_one_footprint (line 48) | def generate_one_footprint(partnumber, pincount, configuration):

FILE: scripts/Connector/Connector_TE-Connectivity/conn_te_826576.py
  function generate_one_footprint (line 67) | def generate_one_footprint(pins, configuration):

FILE: scripts/Connector/Connector_TE-Connectivity/conn_te_mate-n-lock_tht_side.py
  function generate_one_footprint (line 119) | def generate_one_footprint(pins_per_row, variant_param, configuration):

FILE: scripts/Connector/Connector_TE-Connectivity/conn_te_mate-n-lock_tht_top.py
  function generate_one_footprint (line 110) | def generate_one_footprint(pins_per_row, variant_param, configuration):

FILE: scripts/Connector/Connector_TE-Connectivity/helpers.py
  function roundToBase (line 1) | def roundToBase(value, base):

FILE: scripts/Connector/Connector_Wago/conn_wago_734_horizontal.py
  function generate_one_footprint (line 75) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_Wago/conn_wago_734_vertical.py
  function generate_one_footprint (line 75) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector/Connector_Wago/helpers.py
  function roundToBase (line 1) | def roundToBase(value, base):

FILE: scripts/Connector/Connector_Wire/solder_wire_tht.py
  function bend_radius (line 44) | def bend_radius(wire_def):
  function fp_name_gen (line 47) | def fp_name_gen(wire_def, fp_type, pincount, pitch):
  function description_gen (line 57) | def description_gen(wire_def, fp_type, pincount, pitch):
  function tag_gen (line 78) | def tag_gen(wire_def, fp_type, pincount, pitch):
  function make_fp (line 84) | def make_fp(wire_def, fp_type, pincount, configuration):
  function make_for_wire (line 301) | def make_for_wire(wire_def, configuration):
  function make_for_file (line 306) | def make_for_file(filepath, configuration):

FILE: scripts/Connector/Connector_Wuerth/wuerth_6480xx11622.py
  function roundToBase (line 42) | def roundToBase(value, base):
  function generate_one_footprint (line 45) | def generate_one_footprint(pincount, configuration):

FILE: scripts/Connector_PinSocket/canvas.py
  class Layer (line 60) | class Layer:
    method __init__ (line 77) | def __init__(self, footprint, layer='F.Fab', origin=(0,0), line_width=...
    method getBevel (line 101) | def getBevel(width, height):
    method setOrigin (line 104) | def setOrigin(self, x, y):
    method getOrigin (line 109) | def getOrigin(self):
    method setLineWidth (line 112) | def setLineWidth(self, width):
    method getSoldermaskMargin (line 118) | def getSoldermaskMargin(self):
    method setTextDefaults (line 121) | def setTextDefaults(self, max_size=None, min_size=None):
    method setTextSize (line 132) | def setTextSize(self, height, width=None, thickness=None):
    method setGridSpacing (line 139) | def setGridSpacing(self, grid):
    method goHome (line 145) | def goHome(self):
    method goto (line 150) | def goto(self, x, y):
    method gotoX (line 155) | def gotoX(self, x):
    method gotoY (line 159) | def gotoY(self, y):
    method jump (line 163) | def jump(self, x, y):
    method _align (line 168) | def _align(self, value):
    method alignToGrid (line 172) | def alignToGrid(self):
    method _line (line 178) | def _line(self, x, y):
    method to (line 190) | def to(self, x, y, draw=True):
    method left (line 199) | def left(self, distance, draw=True):
    method right (line 206) | def right(self, distance, draw=True):
    method up (line 213) | def up(self, distance, draw=True):
    method down (line 220) | def down(self, distance, draw=True):
    method polyline (line 227) | def polyline(self, vertices, close=False):
    method close (line 240) | def close(self):
    method arc (line 247) | def arc(self, center_x, center_y, angle):
    method circle (line 255) | def circle(self, radius, filled=False):
    method fillrect (line 267) | def fillrect(self, w, h): #TODO: add origin handling
    method rect (line 289) | def rect(self, w, h, bevel=(0.0, 0.0, 0.0, 0.0), draw=(True, True, Tru...
    method rrect (line 332) | def rrect(self, w, h, radius, origin='center'):
    method text (line 360) | def text(self, type, text, rotation=0):
  class PolyLine (line 365) | class PolyLine ():
    method __init__ (line 367) | def __init__(self, vertices=None):
    method __getattr__ (line 373) | def __getattr__(self, name):
    method append (line 379) | def append(self, x, y):
  class PadLayer (line 384) | class PadLayer:
    method __init__ (line 386) | def __init__(self, footprint, size, type, shape, shape_first=None, dri...
    method _init_layers (line 400) | def _init_layers(self, layers):
    method add (line 410) | def add(self, x, y, number=None, type=None, shape=None, size=None, x_o...
    method getLast (line 434) | def getLast(self):
  class _Point (line 444) | class _Point:
    method __init__ (line 445) | def __init__(self, x, y):
    method __repr__ (line 449) | def __repr__(self):
  class _Line (line 452) | class _Line:
    method __init__ (line 453) | def __init__(self, a, b, x1=None, y1=None, normalize=False):
    method _add_points (line 459) | def _add_points(self, a, b, normalize):
    method __repr__ (line 476) | def __repr__(self):
  class _Keepout (line 480) | class _Keepout:
    method __init__ (line 481) | def __init__(self, a, b, x1=None, y1=None, radius=0.0):
    method _add_points (line 489) | def _add_points(self, a, b):
    method pointIsInside (line 495) | def pointIsInside(self, x, y):
    method _feq (line 499) | def _feq(self, a, b):
    method _bbox_overlap (line 502) | def _bbox_overlap(self, bbox):
    method lineIntersects (line 509) | def lineIntersects(self, l):
    method HlineIntersects (line 554) | def HlineIntersects(self, y):
    method VlineIntersects (line 557) | def VlineIntersects(self, x):
    method _HLineTrim (line 560) | def _HLineTrim(self, y, r):
    method _VLineTrim (line 564) | def _VLineTrim(self, x, r):
    method HLineTrim (line 568) | def HLineTrim(self, l):
    method VLineTrim (line 596) | def VLineTrim(self, l):
    method __repr__ (line 625) | def __repr__(self):
  class Keepout (line 631) | class Keepout():
    method __init__ (line 636) | def __init__(self, layer):
    method frange (line 644) | def frange(x, y, jump):
    method __getattr__ (line 649) | def __getattr__(self, name):
    method _align (line 655) | def _align(self, value):
    method _add (line 658) | def _add(self, x0, y0, x1, y1, radius=0.0):
    method addRect (line 662) | def addRect(self, x, y, w, h, offset=None):
    method addRound (line 671) | def addRound(self, x, y, w, h, offset=None):
    method addPads (line 682) | def addPads(self):
    method getPadBB (line 692) | def getPadBB(self, number):
    method _processHVLine (line 703) | def _processHVLine(self, line):
    method processLine (line 741) | def processLine(self, x0, y0, x1, y1):
    method debug_draw (line 763) | def debug_draw(self):
  class OutDir (line 781) | class OutDir:
    method __init__ (line 783) | def __init__(self, root_dir=None):
    method saveTo (line 788) | def saveTo(self, lib_name):

FILE: scripts/Connector_PinSocket/cq_base_parameters.py
  class CaseType (line 38) | class CaseType:
  class PinStyle (line 50) | class PinStyle:
  class PartParametersBase (line 63) | class PartParametersBase:
    method __init__ (line 119) | def __init__(self):
    method _make_params (line 122) | def _make_params(self, pin_pitch, num_pin_rows, pin_style, type):
    method getAllModels (line 132) | def getAllModels(self, model_classes):
    method getSampleModels (line 161) | def getSampleModels(self, model_classes):

FILE: scripts/Connector_PinSocket/parameters.py
  class params (line 39) | class params (PartParametersBase):
    method __init__ (line 75) | def __init__(self, parameter_file=None):
    method _import_params (line 128) | def _import_params(self, device):
    method _make_params (line 158) | def _make_params(self, pin_pitch, num_pin_rows, pin_style, type, pin1s...
    method getAllModels (line 168) | def getAllModels(self, model_classes):
    method getSampleModels (line 183) | def getSampleModels(self, model_classes):
    method getModel (line 197) | def getModel(self, model_class, variant):

FILE: scripts/Connector_PinSocket/socket_strips.py
  function getPadOffsets (line 45) | def getPadOffsets(overall_width, pad):
  function getPinLength (line 48) | def getPinLength(overall_width, packwidth):
  class pinSocketVerticalTHT (line 51) | class pinSocketVerticalTHT (object):
    method __init__ (line 52) | def __init__(self, params):
    method makeModelName (line 56) | def makeModelName(self, genericName):
    method make (line 59) | def make(self, tags_additional=[], isSocket=True):
  class pinSocketHorizontalTHT (line 221) | class pinSocketHorizontalTHT (object):
    method __init__ (line 222) | def __init__(self, params):
    method makeModelName (line 226) | def makeModelName(self, genericName):
    method make (line 229) | def make(self, tags_additional=[], isSocket=True):
  class pinSocketVerticalSMD (line 372) | class pinSocketVerticalSMD (object):
    method __init__ (line 373) | def __init__(self, params):
    method makeModelName (line 377) | def makeModelName(self, genericName):
    method make (line 381) | def make(self, tags_additional=[], isSocket=True):

FILE: scripts/Converter_DCDC/Converter_DCDC.py
  function qfn (line 16) | def qfn(args):

FILE: scripts/Converter_DCDC/XP_Power_SF_THT.py
  function generate_one_footprint (line 34) | def generate_one_footprint(fpid, rows, datasheet, configuration):

FILE: scripts/Fuse/ptc-fuse-tht.py
  function ptc_fuse_tht (line 13) | def ptc_fuse_tht(args):

FILE: scripts/Inductor_SMD/Inductor_SMD.py
  function qfn (line 16) | def qfn(args):

FILE: scripts/LEDs_SMD/plcc4.py
  function plcc4 (line 11) | def plcc4(args):

FILE: scripts/Mounting_Hardware/mounting_hole.py
  function round_to (line 16) | def round_to(n, precision):
  function create_footprint (line 21) | def create_footprint(name, **kwargs):
  function parse_and_execute_yml_file (line 152) | def parse_and_execute_yml_file(filepath):

FILE: scripts/Mounting_Hardware/wuerth_smt_spacer.py
  function roundToBase (line 16) | def roundToBase(value, base):
  function generate_footprint (line 19) | def generate_footprint(params, mpn, configuration):

FILE: scripts/Multicomp/connectors_multicomp_mc9a12.py
  function round_to (line 93) | def round_to(n, precision):

FILE: scripts/Multicomp/connectors_multicomp_mc9a22.py
  function draw_pin_silk (line 40) | def draw_pin_silk(slot_pin_x):
  function round_to (line 90) | def round_to(n, precision):

FILE: scripts/Packages/Package_BGA/ipc_bga_generator.py
  function generateFootprint (line 20) | def generateFootprint(config, fpParams, fpId):
  function __createFootprintVariant (line 52) | def __createFootprintVariant(config, fpParams, fpId):
  function rowNameGenerator (line 226) | def rowNameGenerator(seq):

FILE: scripts/Packages/Package_Gullwing__QFP_SOIC_SO/ipc_gullwing_generator.py
  function roundToBase (line 29) | def roundToBase(value, base):
  class Gullwing (line 32) | class Gullwing():
    method __init__ (line 33) | def __init__(self, configuration):
    method calcPadDetails (line 51) | def calcPadDetails(self, device_dimensions, EP_size, ipc_data, ipc_rou...
    method deviceDimensions (line 106) | def deviceDimensions(device_size_data):
    method generateFootprint (line 140) | def generateFootprint(self, device_params, header):
    method __createFootprintVariant (line 159) | def __createFootprintVariant(self, device_params, header, dimensions, ...

FILE: scripts/Packages/Package_NoLead__DFN_QFN_LGA_SON/ipc_noLead_generator.py
  function roundToBase (line 36) | def roundToBase(value, base):
  class NoLead (line 39) | class NoLead():
    method __init__ (line 40) | def __init__(self, configuration):
    method calcPadDetails (line 58) | def calcPadDetails(self, device_dimensions, EP_size, ipc_data, ipc_rou...
    method deviceDimensions (line 135) | def deviceDimensions(device_size_data, fp_id):
    method generateFootprint (line 190) | def generateFootprint(self, device_params, fp_id):
    method __createFootprintVariant (line 199) | def __createFootprintVariant(self, device_params, device_dimensions, w...

FILE: scripts/Packages/Package_NoLead__DFN_QFN_LGA_SON/qfn.py
  function qfn (line 14) | def qfn(args):

FILE: scripts/Packages/Package_PLCC/ipc_plcc_jLead_generator.py
  function roundToBase (line 20) | def roundToBase(value, base):
  function params_inch_to_metric (line 23) | def params_inch_to_metric(device_params):
  class QFP (line 28) | class QFP():
    method __init__ (line 29) | def __init__(self, configuration):
    method calcPadDetails (line 39) | def calcPadDetails(self, device_params, ipc_data, ipc_round_base):
    method generateFootprint (line 161) | def generateFootprint(self, device_params):

FILE: scripts/Packages/TO_SOT_Packages_SMD/DPAK.py
  class Dimensions (line 12) | class Dimensions(object):
    method __init__ (line 14) | def __init__(self, base, variant, cut_pin=False, tab_linked=False):
    method round_to (line 58) | def round_to(self, n, precision):
    method footprint_name (line 63) | def footprint_name(self, series, num_pins, add_tab, tab_number):
  class DPAK (line 71) | class DPAK(object):
    method __init__ (line 73) | def __init__(self, config_file):
    method load_config (line 78) | def load_config(self, config_file):
    method add_properties (line 92) | def add_properties(self, m, variant):
    method add_labels (line 99) | def add_labels(self, m, variant, dim):
    method draw_tab (line 107) | def draw_tab(self, m, dim):
    method draw_body (line 117) | def draw_body(self, m, dim):
    method draw_pins (line 128) | def draw_pins(self, m, variant, dim, cut_pin):
    method draw_outline (line 144) | def draw_outline(self, m, variant, dim, cut_pin=False):
    method draw_markers (line 151) | def draw_markers(self, m, variant, dim):
    method draw_pads (line 169) | def draw_pads(self, m, base, variant, dim, cut_pin):
    method add_3D_model (line 201) | def add_3D_model(self, m, base, dim):
    method draw_courtyard (line 208) | def draw_courtyard(self, m ,dim):
    method build_footprint (line 215) | def build_footprint(self, base, variant, cut_pin=False, tab_linked=Fal...
    method build_series (line 249) | def build_series(self, verbose=False):
  class TO252 (line 260) | class TO252(DPAK):
    method __init__ (line 262) | def __init__(self, config_file):
  class TO263 (line 267) | class TO263(DPAK):
    method __init__ (line 269) | def __init__(self, config_file):
  class TO268 (line 274) | class TO268(DPAK):
    method __init__ (line 276) | def __init__(self, config_file):
  class ATPAK (line 280) | class ATPAK(DPAK):
    method __init__ (line 282) | def __init__(self, config_file):

FILE: scripts/Packages/TO_SOT_Packages_SMD/make_DPAK.py
  function get_args (line 29) | def get_args():

FILE: scripts/Packages/TO_SOT_THT/TO_SOT_THT_generate.py
  function makeVERT (line 20) | def makeVERT(lib_name, pck, has3d=False, x_3d=[0, 0, 0], s_3d=[1,1,1], l...
  function makeHOR (line 226) | def makeHOR(lib_name, pck, has3d=False, x_3d=[0, 0, 0], s_3d=[1,1,1], lp...
  function makeVERTLS (line 451) | def makeVERTLS(lib_name, pck, has3d=False, x_3d=[0, 0, 0], s_3d=[1,1,1],...
  function makeHORLS (line 625) | def makeHORLS(lib_name, pck, has3d=False, x_3d=[0, 0, 0], s_3d=[1,1,1], ...
  function makeHORREV (line 831) | def makeHORREV(lib_name, pck, has3d=False, x_3d=[0, 0, 0], s_3d=[1 ,1,1]...
  function makeTORound (line 992) | def makeTORound(lib_name, pck, has3d=False, x_3d=[0, 0, 0], s_3d=[1,1,1]...

FILE: scripts/Packages/TO_SOT_THT/TO_THT_packages.py
  class pack_round (line 18) | class pack_round:
    method __init__ (line 32) | def __init__(self):
    method __init__ (line 53) | def __init__(self, name, pins=3, modifier="", largepads=False):
  class pack (line 187) | class pack:
    method __init__ (line 220) | def __init__(self):
    method __init__ (line 252) | def __init__(self ,name ,pins=3 ,rm=0, staggered_type=0,largepads=Fals...

FILE: scripts/Packages/TO_SOT_THT/tools.py
  function roundG (line 18) | def roundG(x, g):
  function roundCrt (line 25) | def roundCrt(x):
  function frange (line 29) | def frange(x, y, jump):
  function frangei (line 35) | def frangei(x, y, jump):
  function addKeepoutRect (line 41) | def addKeepoutRect(x, y, w, h):
  function addKeepoutRound (line 47) | def addKeepoutRound(x,y, w,h):
  function applyKeepouts (line 67) | def applyKeepouts(lines_in, y, xi, yi, keepouts):
  function addHLineWithKeepout (line 109) | def addHLineWithKeepout(kicad_mod, x0, x1, y,layer, width, keepouts=[], ...
  function addHDLineWithKeepout (line 116) | def addHDLineWithKeepout(kicad_mod, x0, dx, x1, y, layer, width, keepout...
  function addVLineWithKeepout (line 139) | def addVLineWithKeepout(kicad_mod, x, y0, y1,layer, width, keepouts=[], ...
  function addVDLineWithKeepout (line 146) | def addVDLineWithKeepout(kicad_mod, x, y0, dy, y1, layer, width, keepout...
  function addRectAngledTop (line 166) | def addRectAngledTop(kicad_mod, x1, x2, angled_delta, layer, width, roun...
  function addRectAngledTopNoBottom (line 186) | def addRectAngledTopNoBottom(kicad_mod, x1, x2, angled_delta, layer, wid...
  function addRectAngledBottom (line 203) | def addRectAngledBottom(kicad_mod, x1, x2, angled_delta, layer, width, r...
  function addCircleLF (line 220) | def addCircleLF(kicad_mod, center, radius, layer, width, linedist=0.3, r...

FILE: scripts/Packages/utils/ep_handling_utils.py
  function getEpRoundRadiusParams (line 5) | def getEpRoundRadiusParams(device_params, configuration, pad_radius):

FILE: scripts/Potentiometers/slide_Potentiometer.py
  function slide_pot (line 14) | def slide_pot(args):

FILE: scripts/Recom_DCDC/Recom_SIP.py
  function recom_78_3pin (line 20) | def recom_78_3pin():
  function recom_78_4pin (line 62) | def recom_78_4pin():
  function recom_r5 (line 78) | def recom_r5():

FILE: scripts/SMD_chip_package_rlc-etc/SMD_chip_package_rlc-etc.py
  function roundToBase (line 19) | def roundToBase(value, base):
  function merge_dicts (line 22) | def merge_dicts(*dict_args):
  class TwoTerminalSMDchip (line 32) | class TwoTerminalSMDchip():
    method __init__ (line 33) | def __init__(self, command_file, configuration):
    method calcPadDetails (line 47) | def calcPadDetails(self, device_dimensions, ipc_data, ipc_round_base, ...
    method deviceDimensions (line 88) | def deviceDimensions(device_size_data):
    method generateFootprints (line 105) | def generateFootprints(self):
    method generateFootprint (line 129) | def generateFootprint(self, device_size_data, footprint_group_data):

FILE: scripts/Shielding/smd_shielding.py
  function round_to (line 15) | def round_to(n, precision):
  function calculate_pad_spacer (line 20) | def calculate_pad_spacer(pad_spacer, mirror_spacer):
  function create_smd_shielding (line 32) | def create_smd_shielding(name, **kwargs):
  function parse_and_execute_yml_file (line 158) | def parse_and_execute_yml_file(filepath):

FILE: scripts/Shielding/wuerth_electronic_smd_shielding.py
  function create_shielding (line 12) | def create_shielding(name, outer_size, size,

FILE: scripts/Shielding/wuerth_electronic_tht_shielding.py
  function create_shielding (line 12) | def create_shielding(name, outer_size, size,

FILE: scripts/Socket/3M_Textool.py
  function roundCrtYd (line 11) | def roundCrtYd(x):
  function textool (line 15) | def textool(args):

FILE: scripts/TerminalBlock_Altech/Altech.py
  function qfn (line 17) | def qfn(args):

FILE: scripts/general/StandardBox.py
  class koaLine (line 28) | class koaLine:
    method __init__ (line 30) | def __init__(self, sx, sy, ex, ey, layer, width):
  class StandardBox (line 62) | class StandardBox(Node):
    method __init__ (line 102) | def __init__(self, **kwargs):
    method getVirtualChilds (line 135) | def getVirtualChilds(self):
    method _initPosition (line 140) | def _initPosition(self, **kwargs):
    method _initSize (line 146) | def _initSize(self, **kwargs):
    method _initFootPrint (line 159) | def _initFootPrint(self, **kwargs):
    method _initDesriptionNode (line 201) | def _initDesriptionNode(self, **kwargs):
    method _initTagNode (line 209) | def _initTagNode(self, **kwargs):
    method _initAttributeNode (line 215) | def _initAttributeNode(self, **kwargs):
    method _initFile3DNameNode (line 221) | def _initFile3DNameNode(self, **kwargs):
    method _initExtraTextNode (line 230) | def _initExtraTextNode(self, **kwargs):
    method _createFFabLine (line 246) | def _createFFabLine(self):
    method _createPin1MarkerLine (line 389) | def _createPin1MarkerLine(self):
    method _createFSilkSLine (line 404) | def _createFSilkSLine(self):
    method _createFCrtYdLine (line 675) | def _createFCrtYdLine(self):
    method calculateBoundingBox (line 983) | def calculateBoundingBox(self):
    method _createPinsNode (line 999) | def _createPinsNode(self):

FILE: scripts/general/smd_chip.py
  function smd_chip (line 12) | def smd_chip(args):

FILE: scripts/tools/dict_tools.py
  function dictMerge (line 6) | def dictMerge(a, b):
  function dictInherit (line 40) | def dictInherit(d):

FILE: scripts/tools/drawing_tools.py
  function script3d_writevariable (line 18) | def script3d_writevariable(file, line, varname, value):
  function roundG (line 23) | def roundG(x, g):
  function sqr (line 30) | def sqr(x):
  function roundCrt (line 35) | def roundCrt(x):
  function frange (line 40) | def frange(x, y, jump):
  function frangei (line 47) | def frangei(x, y, jump):
  function addKeepoutRect (line 54) | def addKeepoutRect(x, y, w, h):
  function addKeepoutRound (line 60) | def addKeepoutRound(x, y, w, h):
  function applyKeepouts (line 79) | def applyKeepouts(lines_in, y, xi, yi, keepouts):
  function containedInAnyKeepout (line 126) | def containedInAnyKeepout(x,y, keepouts):
  function debug_draw_keepouts (line 136) | def debug_draw_keepouts(kicad_modg, keepouts):
  function addHLineWithKeepout (line 143) | def addHLineWithKeepout(kicad_mod, x0, x1, y, layer, width, keepouts=[],...
  function addCircleWithKeepout (line 154) | def addCircleWithKeepout(kicad_mod, x, y, radius, layer, width, keepouts...
  function addArcByAngles (line 183) | def addArcByAngles(kicad_mod, x, y, radius, angle_start, angle_end, laye...
  function addArcByAnglesWithKeepout (line 189) | def addArcByAnglesWithKeepout(kicad_mod, x, y, radius, angle_start, angl...
  function addArcWithKeepout (line 195) | def addArcWithKeepout(kicad_mod, x, y, startx, starty, angle, layer, wid...
  function addEllipse (line 231) | def addEllipse(kicad_mod, x, y, w, h, layer, width, roun=0.001):
  function addEllipseWithKeepout (line 239) | def addEllipseWithKeepout(kicad_mod, x, y, w, h, layer, width, keepouts=...
  function addDCircleWithKeepout (line 247) | def addDCircleWithKeepout(kicad_mod, x, y, radius, layer, width, keepout...
  function addLineWithKeepout (line 268) | def addLineWithKeepout(kicad_mod, x1, y1, x2,y2, layer, width, keepouts=...
  function addPolyLineWithKeepout (line 290) | def addPolyLineWithKeepout(kicad_mod, poly, layer, width, keepouts=[], r...
  function addDCircle (line 298) | def addDCircle(kicad_mod, x, y, radius, layer, width, roun=0.001):
  function addSlitScrew (line 311) | def addSlitScrew(kicad_mod, x, y, radius, layer, width, roun=0.001):
  function addSlitScrewWithKeepouts (line 329) | def addSlitScrewWithKeepouts(kicad_mod, x, y, radius, layer, width, keep...
  function addCrossScrew (line 346) | def addCrossScrew(kicad_mod, x, y, radius, layer, width, roun=0.001):
  function addCrossScrewWithKeepouts (line 369) | def addCrossScrewWithKeepouts(kicad_mod, x, y, radius, layer, width, kee...
  function addVLineWithKeepout (line 393) | def addVLineWithKeepout(kicad_mod, x, y0, y1, layer, width, keepouts=[],...
  function addHDLineWithKeepout (line 405) | def addHDLineWithKeepout(kicad_mod, x0, x1, y, layer, width, keepouts=[]...
  function addVDLineWithKeepout (line 413) | def addVDLineWithKeepout(kicad_mod, x, y0, y1, layer, width, keepouts=[]...
  function addRectWith (line 423) | def addRectWith(kicad_mod, x, y, w, h, layer, width, roun=0.001):
  function addRectWithKeepout (line 428) | def addRectWithKeepout(kicad_mod, x, y, w, h, layer, width, keepouts=[],...
  function addRectAndTLMarkWithKeepout (line 435) | def addRectAndTLMarkWithKeepout(kicad_mod, x, y, w, h, mark_len, layer, ...
  function addDRectWithKeepout (line 445) | def addDRectWithKeepout(kicad_mod, x, y, w, h, layer, width, keepouts=[]...
  function addPlusWithKeepout (line 452) | def addPlusWithKeepout(km, x, y, w, h, layer, width, keepouts=[], roun=0...
  function allBevelRect (line 467) | def allBevelRect(model, x, size, layer, width, bevel_size=0.2):
  function allTrapezoid (line 490) | def allTrapezoid(model, x, size, angle, layer, width):
  function allEqualSidedDownTriangle (line 508) | def allEqualSidedDownTriangle(model, xcenter, side_length, layer, width):
  function allRoundedBevelRect (line 525) | def allRoundedBevelRect(model, x, size, angle, corner_radius, layer, wid...
  function addRoundedRect (line 576) | def addRoundedRect(model, x, size, corner_radius, layer, width=0.2):
  function fillCircle (line 592) | def fillCircle(model, center, radius, layer, width):
  function bevelRectTL (line 616) | def bevelRectTL(model, x, size, layer, width, bevel_size=1):
  function bevelRectBL (line 633) | def bevelRectBL(model, x, size, layer, width, bevel_size=1):
  function DIPRectT (line 648) | def DIPRectT(model, x, size, layer, width, marker_size=2):
  function DIPRectL (line 664) | def DIPRectL(model, x, size, layer, width, marker_size=2):
  function DIPRectL_LeftOnly (line 682) | def DIPRectL_LeftOnly(model, x, size, layer, width, marker_size=2):
  function THTQuartzRect (line 703) | def THTQuartzRect(model, x, size, inner_size, layer, width):
  function THTQuartz (line 714) | def THTQuartz(model, x, size, layer, width):
  function THTQuartzIncomplete (line 723) | def THTQuartzIncomplete(model, x, size, angle, layer, width):
  function nearestSilkPointOnOrthogonalLineSmallClerance (line 761) | def nearestSilkPointOnOrthogonalLineSmallClerance(pad_size, pad_position...
  function nearestSilkPointOnOrthogonalLine (line 792) | def nearestSilkPointOnOrthogonalLine(pad_size, pad_position, pad_radius,...

FILE: scripts/tools/footprint_keepout_area.py
  function addRectangularKeepout (line 23) | def addRectangularKeepout(kicad_mod, center, size, text='KEEPOUT', confi...

FILE: scripts/tools/footprint_scripts_DIP.py
  function makeDIP (line 32) | def makeDIP(pins, rm, pinrow_distance_in, package_width, overlen_top, ov...
  function makeDIPSwitch (line 226) | def makeDIPSwitch(pins, rm, pinrow_distance, package_width, overlen_top,...

FILE: scripts/tools/footprint_scripts_LEDs.py
  function makeLEDRadial (line 61) | def makeLEDRadial(rm, w, h, ddrill, win=0, rin=0, pins=2, type="round", ...
  function makeLEDHorizontal (line 352) | def makeLEDHorizontal(pins=2,rm=2.544,dled=5,dledout=5.8,offsetled=2.54,...

FILE: scripts/tools/footprint_scripts_crystals.py
  function makeSMDCrystalAndHand (line 17) | def makeSMDCrystalAndHand(footprint_name, addSizeFootprintName, pins, pa...
  function makeSMDCrystal (line 68) | def makeSMDCrystal(footprint_name, addSizeFootprintName, pins, pad_sep_x...
  function makeCrystalAll (line 356) | def makeCrystalAll(footprint_name, rm, pad_size, ddrill, pack_width, pac...
  function makeCrystal (line 398) | def makeCrystal(footprint_name, rm, pad_size, ddrill, pack_width, pack_h...
  function makeCrystalHC49Vert (line 611) | def makeCrystalHC49Vert(footprint_name, pins, rm, pad_size, ddrill, pack...
  function makeCrystalRoundVert (line 764) | def makeCrystalRoundVert(footprint_name, rm, pad_size, ddrill, pack_diam...

FILE: scripts/tools/footprint_scripts_dsub.py
  function makeDSubStraight (line 21) | def makeDSubStraight(pins, isMale, HighDensity, rmx, rmy, pindrill, pad,...
  function makeDSubEdge (line 263) | def makeDSubEdge(pins, isMale, rmx, pad, mountingdrill, mountingdistance...
  function makeDSubAngled (line 458) | def makeDSubAngled(pins, isMale, HighDensity, rmx, rmy, pindrill, pad, p...

FILE: scripts/tools/footprint_scripts_pin_headers.py
  function makePinHeadStraight (line 21) | def makePinHeadStraight(rows, cols, rm, coldist, package_width, overlen_...
  function makeIdcHeader (line 280) | def makeIdcHeader(rows, cols, rm, coldist, body_width, overlen_top, over...
  function makePinHeadAngled (line 516) | def makePinHeadAngled(rows, cols, rm, coldist, pack_width, pack_offset, ...
  function makeSocketStripAngled (line 798) | def makeSocketStripAngled(rows, cols, rm, coldist, pack_width, pack_offs...
  function makePinHeadStraightSMD (line 967) | def makePinHeadStraightSMD(rows, cols, rm, coldist, rmx_pad_offset,rmx_p...

FILE: scripts/tools/footprint_scripts_potentiometers.py
  function makePotentiometerHorizontal (line 29) | def makePotentiometerHorizontal(class_name="", wbody=0, hbody=0, dscrew=...
  function makePotentiometerVertical (line 343) | def makePotentiometerVertical(class_name, wbody, hbody, screwstyle="none...
  function makeSpindleTrimmer (line 745) | def makeSpindleTrimmer(class_name, wbody, hbody, pinxoffset, pinyoffset,...

FILE: scripts/tools/footprint_scripts_resistorlike.py
  function getFancyClassName (line 21) | def getFancyClassName(classname="R"):
  function getPowRat (line 33) | def getPowRat(R_POW=0.0):
  function makeResistorAxialHorizontal (line 49) | def makeResistorAxialHorizontal(seriesname, rm, rmdisp, w, d, ddrill, R_...
  function makeResistorAxialVertical (line 297) | def makeResistorAxialVertical(seriesname,rm, rmdisp, l, d, ddrill, R_POW...
  function makeResistorRadial (line 618) | def makeResistorRadial(seriesname, rm, w, h, ddrill, R_POW, innerw=0,inn...

FILE: scripts/tools/footprint_scripts_sip.py
  function makeSIPVertical (line 18) | def makeSIPVertical(pins, rm, ddrill, pad, package_size, left_offset, to...
  function makeSIPHorizontal (line 110) | def makeSIPHorizontal(pins, rm, ddrill, pad, package_size, left_offset, ...
  function makeResistorSIP (line 188) | def makeResistorSIP(pins, footprint_name, description):

FILE: scripts/tools/footprint_scripts_terminal_blocks.py
  function makeTerminalBlockStd (line 35) | def makeTerminalBlockStd(footprint_name, pins, rm, package_height, leftb...
  function makeTerminalBlockVertical (line 256) | def makeTerminalBlockVertical(footprint_name, pins, rm, package_height, ...
  function makeTerminalBlock45Degree (line 479) | def makeTerminalBlock45Degree(footprint_name, pins, rm, package_height, ...
  function makeScrewTerminalSingleStd (line 714) | def makeScrewTerminalSingleStd(footprint_name, block_size, block_offset,...

FILE: scripts/tools/footprint_text_fields.py
  function _roundToBase (line 5) | def _roundToBase(value, base):
  function _getTextFieldDetails (line 8) | def _getTextFieldDetails(field_definition, body_edges, courtyard, text_y...
  function addTextFields (line 85) | def addTextFields(kicad_mod, configuration, body_edges, courtyard, fp_na...

FILE: scripts/tools/ipc_pad_size_calculators.py
  function roundToBase (line 5) | def roundToBase(value, base):
  class TolerancedSize (line 8) | class TolerancedSize():
    method to_metric (line 9) | def to_metric(value, unit):
    method __init__ (line 18) | def __init__(self, minimum=None, nominal=None, maximum=None, tolerance...
    method updateRMS (line 61) | def updateRMS(self, tolerances):
    method __add__ (line 78) | def __add__(self, other):
    method __sub__ (line 93) | def __sub__(self, other):
    method __mul__ (line 108) | def __mul__(self, other):
    method __div__ (line 118) | def __div__(self, other):
    method __truediv__ (line 121) | def __truediv__(self, other):
    method __floordiv__ (line 131) | def __floordiv__(self, other):
    method fromString (line 142) | def fromString(input, unit=None):
    method fromYaml (line 189) | def fromYaml(yaml, base_name=None, unit=None):
    method __str__ (line 211) | def __str__(self):
  function ipc_body_edge_inside (line 214) | def ipc_body_edge_inside(ipc_data, ipc_round_base, manf_tol, body_size, ...
  function ipc_body_edge_inside_pull_back (line 224) | def ipc_body_edge_inside_pull_back(ipc_data, ipc_round_base, manf_tol, b...
  function ipc_gull_wing (line 264) | def ipc_gull_wing(ipc_data, ipc_round_base, manf_tol, lead_width, lead_o...
  function ipc_pad_center_plus_size (line 297) | def ipc_pad_center_plus_size(ipc_data, ipc_round_base, manf_tol,

FILE: scripts/tools/pad_number_generators.py
  function increment (line 25) | def increment(pincount, init=1, **kwargs):
  function _get_pin_cw (line 45) | def _get_pin_cw(pincount, loc):
  function _get_pin_ccw (line 67) | def _get_pin_ccw(pincount, loc):
  function clockwise_dual (line 89) | def clockwise_dual(pincount, init=1, start="top_left", axis="x", **kwargs):
  function counter_clockwise_dual (line 113) | def counter_clockwise_dual(pincount, init=1, start="top_left", axis="x",...
  function get_generator (line 145) | def get_generator(device_params):

FILE: scripts/tools/quad_dual_pad_border.py
  function add_dual_or_quad_pad_border (line 8) | def add_dual_or_quad_pad_border(kicad_mod, configuration, pad_details, d...
  function add_dual_pad_border_y (line 32) | def add_dual_pad_border_y(kicad_mod, pad_details, device_params, pad_sha...
  function add_dual_pad_border_x (line 63) | def add_dual_pad_border_x(kicad_mod, pad_details, device_params, pad_sha...
  function add_quad_pad_border (line 94) | def add_quad_pad_border(kicad_mod, pad_details, device_params, pad_shape...
Condensed preview — 414 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,102K chars).
[
  {
    "path": ".codeclimate.yml",
    "chars": 295,
    "preview": "engines:\n  duplication:\n    enabled: true\n    config:\n      languages:\n      - python\n  fixme:\n    enabled: true\n  radon"
  },
  {
    "path": ".gitignore",
    "chars": 726,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
  },
  {
    "path": ".travis.yml",
    "chars": 282,
    "preview": "sudo: false\ncache:\n  - pip\n  - directories:\n    - $HOME/.cache/pip\nlanguage: python\npython:\n  - \"2.7\"\n  - \"3.4\"\n  - \"3.5"
  },
  {
    "path": "AUTHORS.md",
    "chars": 1860,
    "preview": "**Maintainer:**\n\n* Thomas Pointhuber <thomas.pointhuber@gmx.at> @pointhi\n* Rene Pöschl, @poeschlr\n* @evanshultz\n\n**Contr"
  },
  {
    "path": "KicadModTree/FileHandler.py",
    "chars": 2666,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/KicadFileHandler.py",
    "chars": 13744,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/ModArgparser.py",
    "chars": 10013,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/Point.py",
    "chars": 1616,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/PolygonPoints.py",
    "chars": 6403,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/Vector.py",
    "chars": 14503,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/__init__.py",
    "chars": 1010,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/examples/__init__.py",
    "chars": 660,
    "preview": "'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under the terms of the GNU Gene"
  },
  {
    "path": "KicadModTree/examples/argparse_example.py",
    "chars": 1623,
    "preview": "#!/usr/bin/env python\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of th"
  },
  {
    "path": "KicadModTree/examples/padArrayWithOutline.py",
    "chars": 2359,
    "preview": "#!/usr/bin/env python\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of th"
  },
  {
    "path": "KicadModTree/examples/params.csv",
    "chars": 130,
    "preview": "name,        diameter,    pad_length,      pad_width\n10x2x5,10,2,5\n15x2x5,15,2,5\n18x2x5,18,2,5\n\"Jsjdlfmlakefjsl , asldl\""
  },
  {
    "path": "KicadModTree/examples/params.yml",
    "chars": 51,
    "preview": "asdf:\n  diameter: 10\n  pad_length: 3\n  pad_width: 7"
  },
  {
    "path": "KicadModTree/examples/polygon.py",
    "chars": 1687,
    "preview": "#!/usr/bin/env python\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of th"
  },
  {
    "path": "KicadModTree/examples/simpleFootprint.py",
    "chars": 2278,
    "preview": "#!/usr/bin/env python\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of th"
  },
  {
    "path": "KicadModTree/nodes/Footprint.py",
    "chars": 2307,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/Node.py",
    "chars": 6713,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/__init__.py",
    "chars": 889,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/base/Arc.py",
    "chars": 4364,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/base/Circle.py",
    "chars": 3521,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/base/Line.py",
    "chars": 3724,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/base/Model.py",
    "chars": 2263,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/base/Pad.py",
    "chars": 15994,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/base/Polygon.py",
    "chars": 3551,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/base/Text.py",
    "chars": 4556,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/base/__init__.py",
    "chars": 891,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/ChamferedPad.py",
    "chars": 14685,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/ChamferedPadGrid.py",
    "chars": 13891,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/ExposedPad.py",
    "chars": 23620,
    "preview": "#!/usr/bin/env python\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of th"
  },
  {
    "path": "KicadModTree/nodes/specialized/FilledRect.py",
    "chars": 2496,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/PadArray.py",
    "chars": 13433,
    "preview": "#!/usr/bin/env python\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of th"
  },
  {
    "path": "KicadModTree/nodes/specialized/PolygoneLine.py",
    "chars": 2947,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/RectFill.py",
    "chars": 2940,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/RectLine.py",
    "chars": 3966,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/RingPad.py",
    "chars": 17524,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/Rotation.py",
    "chars": 2069,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/Translation.py",
    "chars": 2028,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/nodes/specialized/__init__.py",
    "chars": 1100,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/__init__.py",
    "chars": 710,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/datatypes/__init__.py",
    "chars": 798,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/datatypes/test_Vector2D.py",
    "chars": 5520,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/datatypes/test_Vector3D.py",
    "chars": 6153,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/moduletests/__init__.py",
    "chars": 937,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/moduletests/test_arc.py",
    "chars": 16308,
    "preview": "import unittest\nimport math\nfrom KicadModTree import *\n\nRESULT_kx90DEG = \"\"\"(module test (layer F.Cu) (tedit 0)\n  (fp_ar"
  },
  {
    "path": "KicadModTree/tests/moduletests/test_exposed_pad.py",
    "chars": 73818,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/moduletests/test_kicad5_padshapes.py",
    "chars": 26838,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/moduletests/test_rotation.py",
    "chars": 13351,
    "preview": "import unittest\nimport math\nfrom KicadModTree import *\n\nRESULT_rotText = \"\"\"(module test_rotate (layer F.Cu) (tedit 0)\n "
  },
  {
    "path": "KicadModTree/tests/moduletests/test_simple_footprints.py",
    "chars": 5507,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/nodes/__init__.py",
    "chars": 744,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/nodes/test_Node.py",
    "chars": 11416,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/tests/test.py",
    "chars": 1017,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/util/__init__.py",
    "chars": 710,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/util/geometric_util.py",
    "chars": 19512,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/util/kicad_util.py",
    "chars": 5566,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "KicadModTree/util/paramUtil.py",
    "chars": 7979,
    "preview": "# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of the GNU General Public Li"
  },
  {
    "path": "LICENSE",
    "chars": 35142,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "README.md",
    "chars": 5105,
    "preview": "## :warning: 301 Moved Permanently\nLocation: https://gitlab.com/kicad/libraries/kicad-footprint-generator\n\n---\n\nThis rep"
  },
  {
    "path": "docs/KicadModTree.nodes.base.rst",
    "chars": 1316,
    "preview": "KicadModTree.nodes.base package\n===============================\n\nThose nodes represent the primitives which we can use t"
  },
  {
    "path": "docs/KicadModTree.nodes.rst",
    "chars": 470,
    "preview": "KicadModTree.nodes package\n==========================\n\n.. toctree::\n\n    KicadModTree.nodes.base\n    KicadModTree.nodes."
  },
  {
    "path": "docs/KicadModTree.nodes.specialized.rst",
    "chars": 1697,
    "preview": "KicadModTree.nodes.specialized package\n======================================\n\nTo simpilfy the creation on footprints, w"
  },
  {
    "path": "docs/KicadModTree.rst",
    "chars": 808,
    "preview": "KicadModTree package\n====================\n\n.. toctree::\n\n    KicadModTree.nodes\n    KicadModTree.util\n\n\nKicadModTree.Fil"
  },
  {
    "path": "docs/KicadModTree.util.rst",
    "chars": 228,
    "preview": "KicadModTree.util package\n=========================\n\nKicadModTree.util.kicad_util module\n-------------------------------"
  },
  {
    "path": "docs/Makefile",
    "chars": 609,
    "preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHI"
  },
  {
    "path": "docs/conf.py",
    "chars": 4993,
    "preview": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n#\n# KicadModTree documentation build configuration file, created by\n# sph"
  },
  {
    "path": "docs/index.rst",
    "chars": 1555,
    "preview": ".. KicadModTree documentation master file, created by\n   sphinx-quickstart on Sun Feb 19 20:08:44 2017.\n   You can adapt"
  },
  {
    "path": "manage.sh",
    "chars": 1898,
    "preview": "#!/usr/bin/env bash\n\nif [[ \"$OSTYPE\" == \"darwin\"* ]]; then\ncommand -v greadlink >/dev/null 2>&1 || { echo >&2 \"greadlink"
  },
  {
    "path": "requirements-dev.txt",
    "chars": 62,
    "preview": "pep8\nflake8\nunittest2\nnose2\nnose2-cov\nsphinx\nsphinx_rtd_theme\n"
  },
  {
    "path": "requirements.txt",
    "chars": 14,
    "preview": "pyyaml\nfuture\n"
  },
  {
    "path": "scripts/Battery/BatteryHolder.py",
    "chars": 1961,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\nimport re\n\n# load parent path of KicadModTree\nsys.path.append(os.path.join("
  },
  {
    "path": "scripts/Battery/BatteryHolder.yml",
    "chars": 7476,
    "preview": "BatteryHolder_Bulgin_BX0033_1xPP3:\n  description: \"Bulgin Battery Holder, BX0033, Battery Type 1xPP3\"\n  datasheet: \"http"
  },
  {
    "path": "scripts/Battery/README.txt",
    "chars": 102,
    "preview": "Script to generate the battery holders\n\nTo create all, type\npython BatteryHolder.py BatteryHolder.yml\n"
  },
  {
    "path": "scripts/Buttons_Switches/make_DIPSwitches.py",
    "chars": 9398,
    "preview": "#!/usr/bin/env python\n\nimport sys\nimport os\nimport math\n\n# ensure that the kicad-footprint-generator directory is availa"
  },
  {
    "path": "scripts/Buttons_Switches/rotary_coded_switch.py",
    "chars": 7499,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n\n# load parent path of KicadModTree\nsys.path.append(os.path.join(sys.path[0"
  },
  {
    "path": "scripts/Buttons_Switches/rotary_coded_switch.yml",
    "chars": 395,
    "preview": "Nidec_Copal_SH-7010A:\n  style: J-hook\n  pad_width: 2.5\n  pad_x_spacing: 6.5\nNidec_Copal_SH-7010B:\n  style: gull wing\n  p"
  },
  {
    "path": "scripts/Buzzers_Beepers/buzzer_round_tht.py",
    "chars": 2683,
    "preview": "#!/usr/bin/env python\n\nimport sys\nimport os\n\nsys.path.append(os.path.join(sys.path[0], \"..\", \"..\"))  # load parent path "
  },
  {
    "path": "scripts/Buzzers_Beepers/buzzer_round_tht_star_mictronics.csv",
    "chars": 1361,
    "preview": "name,datasheet,diameter,hole_size,pad_size,pad_spacing\nMagneticBuzzer_StarMicronics_QMB-105,http://datasheet.octopart.co"
  },
  {
    "path": "scripts/Capacitors_SMD/CP_Elec_round.py",
    "chars": 13320,
    "preview": "#!/usr/bin/env python\n\nimport sys\nimport os\nimport argparse\nimport yaml\nimport math\nfrom collections import namedtuple\n\n"
  },
  {
    "path": "scripts/Capacitors_SMD/CP_Elec_round.yaml",
    "chars": 21184,
    "preview": "#CP_Elec_6.3x5.8:\n#    body_length:\n#      nominal: 6.6\n#    body_width:\n#      nominal: 6.6\n#    body_height:\n#      no"
  },
  {
    "path": "scripts/Capacitors_SMD/C_Elec_round.py",
    "chars": 17853,
    "preview": "#!/usr/bin/env python\n\nimport sys\nimport os\nimport argparse\nimport yaml\nimport math\n\nsys.path.append(os.path.join(sys.pa"
  },
  {
    "path": "scripts/Capacitors_SMD/C_Elec_round.yaml",
    "chars": 5678,
    "preview": "# http://nichicon-us.com/english/products/pdfs/e-uup.pdf\n# http://nichicon-us.com/english/products/pdfs/e-uwp.pdf\n# http"
  },
  {
    "path": "scripts/Capacitors_SMD/C_Trimmer_config.yaml",
    "chars": 9184,
    "preview": "# SMD trimmer capacitors STYLE A\nbase:\n    family: STYLE-A\n    description: 'trimmer capacitor SMD horizontal'\n    keywo"
  },
  {
    "path": "scripts/Capacitors_SMD/C_Trimmer_factory.py",
    "chars": 11119,
    "preview": "import sys\nimport os\nimport argparse\nimport yaml\nimport pprint\n\nsys.path.append(os.path.join(sys.path[0], \"../..\"))  # e"
  },
  {
    "path": "scripts/Capacitors_SMD/C_Trimmer_make.py",
    "chars": 1197,
    "preview": "#!/usr/bin/env python\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of th"
  },
  {
    "path": "scripts/Capacitors_SMD/bump.py",
    "chars": 1616,
    "preview": "from KicadModTree import *  # NOQA\n\ndef add_bump(m, anchor_pos, bump_length, bump_width, direction, layer, width, offset"
  },
  {
    "path": "scripts/Capacitors_SMD/chamfers.py",
    "chars": 4640,
    "preview": "from KicadModTree import *\n\ndef add_rect_chamfer(m, start_pos, end_pos, layer, width, offset=(0,0), chamfers=[]):\n\n    #"
  },
  {
    "path": "scripts/Capacitors_SMD/corners.py",
    "chars": 2443,
    "preview": "from KicadModTree import *  # NOQA\n\ndef add_corners(m, start_pos, end_pos, size_x, size_y, layer, width, offset=(0, 0), "
  },
  {
    "path": "scripts/Capacitors_SMD/ipc7351B_capae_crystal.yaml",
    "chars": 1303,
    "preview": "# Dimensions taken from ipc7351b table 3-20\n\n# Aluminum Electrolytic Capacitor and 2-Pin Crystal\n#           | Minimum |"
  },
  {
    "path": "scripts/Capacitors_SMD/tantal and normal smd generator found under SMD_chip_package_rlc-etc",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "scripts/Capacitors_THT/make_Capacitors_THT.py",
    "chars": 52775,
    "preview": "#!/usr/bin/env python\r\n\r\nimport sys\r\nimport os\r\nimport math\r\n\r\n# ensure that the kicad-footprint-generator directory is "
  },
  {
    "path": "scripts/Chokes_THT/make_Chokes_THT.py",
    "chars": 106367,
    "preview": "#!/usr/bin/env python\n\nimport sys\nimport os\nimport math\n\n# ensure that the kicad-footprint-generator directory is availa"
  },
  {
    "path": "scripts/Connector/Connector_Audio/Jack_3.5mm_Switronic_ST-005-G_horizontal.py",
    "chars": 5828,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n\n# load parent path of KicadModTree\nsys.path.append(os.path.join(sys.path[0"
  },
  {
    "path": "scripts/Connector/Connector_Harwin/conn_harwin_m20-781xx45_smd_top_dual_row.py",
    "chars": 9644,
    "preview": "#!/usr/bin/env python3\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under th"
  },
  {
    "path": "scripts/Connector/Connector_Harwin/m20-89xx.py",
    "chars": 10111,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n\nsys.path.append(os.path.join(sys.path[0], \"..\", \"..\", \"..\"))  # load paren"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/00-SMD footprint generators can be found in Connector_SMD_single_row_plus_mounting_pad.md",
    "chars": 137,
    "preview": "The following connector footprints are generated in the generic scirpt located in ../Connector_SMD_single_row_plus_mount"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/conn_ffc_hirose_fh12_smd_side.py",
    "chars": 9855,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/conn_hirose_df11_tht_top.py",
    "chars": 8658,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/conn_hirose_df12c_ds_smd_top.py",
    "chars": 10382,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/conn_hirose_df12e_dp_smd_top.py",
    "chars": 10467,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/conn_hirose_df13_tht_side.py",
    "chars": 9300,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/conn_hirose_df13_tht_top.py",
    "chars": 9149,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/conn_hirose_df13c_smd_top.py",
    "chars": 8869,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/conn_hirose_df63_tht_top.py",
    "chars": 9525,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/helpers.py",
    "chars": 105,
    "preview": "def roundToBase(value, base):\n    if base == 0:\n        return value\n    return round(value/base) * base\n"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/not_in_official_lib/df33_straight_pth.py",
    "chars": 4440,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\nsys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\"))\n\nfrom kica"
  },
  {
    "path": "scripts/Connector/Connector_Hirose/not_in_official_lib/df63_angled.py",
    "chars": 6204,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_IEC_DIN/generate_din41612.py",
    "chars": 15748,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\nimport math\n\nsys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"..\")) # fo"
  },
  {
    "path": "scripts/Connector/Connector_JAE/conn_ffc_jae_ff08.py",
    "chars": 8762,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_JAE/conn_jae_LY20_tht_side.py",
    "chars": 11432,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_JAE/conn_jae_LY20_tht_top.py",
    "chars": 9924,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_JAE/helpers.py",
    "chars": 105,
    "preview": "def roundToBase(value, base):\n    if base == 0:\n        return value\n    return round(value/base) * base\n"
  },
  {
    "path": "scripts/Connector/Connector_JST/00-SMD footprint generators can be found in Connector_SMD_single_row_plus_mounting_pad.md",
    "chars": 246,
    "preview": "The following connector footprints are generated in the generic scirpt located in ../Connector_SMD_single_row_plus_mount"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_J2100_tht_side.py",
    "chars": 8956,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_J2100_tht_top.py",
    "chars": 9777,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_JWPF_tht_top.py",
    "chars": 9716,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n\n# export PYTHONPATH=\"${PYTHONPATH}<path to kicad-footprint-generator direc"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_NV_tht_top.py",
    "chars": 7530,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_PHD_horizontal.py",
    "chars": 8469,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_PHD_vertical.py",
    "chars": 9785,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_PUD_tht_side.py",
    "chars": 8536,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_PUD_tht_top.py",
    "chars": 8495,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_VH_tht_side-stabilizer.py",
    "chars": 12839,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_VH_tht_side.py",
    "chars": 10170,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_VH_tht_top-shrouded.py",
    "chars": 9277,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_eh_tht_side.py",
    "chars": 9377,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_eh_tht_top.py",
    "chars": 7422,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_ph_tht_side.py",
    "chars": 11192,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_ph_tht_top.py",
    "chars": 9980,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_vh_tht_top.py",
    "chars": 10886,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_xh_tht_side.py",
    "chars": 9161,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_xh_tht_top.py",
    "chars": 13069,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_ze_tht_side.py",
    "chars": 8543,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n\n# export PYTHONPATH=\"${PYTHONPATH}<path to kicad-footprint-generator direc"
  },
  {
    "path": "scripts/Connector/Connector_JST/conn_jst_ze_tht_top.py",
    "chars": 12182,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\nsys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\"))\n\nfrom math"
  },
  {
    "path": "scripts/Connector/Connector_JST/helpers.py",
    "chars": 66,
    "preview": "def roundToBase(value, base):\n    return round(value/base) * base\n"
  },
  {
    "path": "scripts/Connector/Connector_Molex/00-SMD footprint generators can be found in Connector_SMD_single_row_plus_mounting_pad.md",
    "chars": 534,
    "preview": "The following connector footprints are generated in the generic scirpt located in ../Connector_SMD_single_row_plus_mount"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_ffc_molex_200528.py",
    "chars": 10667,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_ffc_molex_502250.py",
    "chars": 10410,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n#sys.path.append(os.path.join(sys.path[0],\"..\",\"..\",\"kicad_mod\")) # load ki"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_SPOX_tht_side.py",
    "chars": 8214,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_SPOX_tht_top.py",
    "chars": 8194,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_kk_254_tht_top.py",
    "chars": 10248,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_kk_396_tht_top.py",
    "chars": 10827,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_mega-fit_tht_side_dual-row.py",
    "chars": 10087,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_mega-fit_tht_top_dual_row.py",
    "chars": 15380,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-clasp_tht_side.py",
    "chars": 10046,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-clasp_tht_top.py",
    "chars": 10368,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_smd_side_dual_row.py",
    "chars": 10855,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_smd_top_dual_row.py",
    "chars": 14413,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_tht_side_dual_row.py",
    "chars": 17419,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_tht_side_single_row.py",
    "chars": 12169,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_tht_top_dual_row.py",
    "chars": 11953,
    "preview": "#!/usr/bin/env python\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under th"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-fit-3.0_tht_top_single_row.py",
    "chars": 11756,
    "preview": "#!/usr/bin/env python\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under th"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-latch_tht_side.py",
    "chars": 9709,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_micro-latch_tht_top.py",
    "chars": 8875,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_mini-fit-sr_tht_side.py",
    "chars": 12238,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_mini-fit-sr_tht_top.py",
    "chars": 14020,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_mini-fit-sr_tht_top_dual.py",
    "chars": 13662,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_mini-fit_Jr_tht_side_dual-row.py",
    "chars": 13523,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_mini-fit_Jr_tht_top_dual-row.py",
    "chars": 14841,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_nano-fit_tht_side.py",
    "chars": 9414,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_nano-fit_tht_top.py",
    "chars": 11752,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_picoblade_tht_side.py",
    "chars": 8439,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_picoblade_tht_top.py",
    "chars": 8201,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_picoflex_smd_top.py",
    "chars": 16587,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_picoflex_tht_top.py",
    "chars": 10594,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_sabre_tht_side.py",
    "chars": 13110,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_sabre_tht_top.py",
    "chars": 12138,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_slimstack-501920.py",
    "chars": 7549,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_slimstack-502426.py",
    "chars": 9489,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_slimstack-502430.py",
    "chars": 9128,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_slimstack-52991.py",
    "chars": 9194,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_slimstack-53748.py",
    "chars": 9779,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_slimstack-54722.py",
    "chars": 7591,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_slimstack-55560.py",
    "chars": 7596,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/conn_molex_stackable-linear_tht_top.py",
    "chars": 11602,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Molex/helpers.py",
    "chars": 105,
    "preview": "def roundToBase(value, base):\n    if base == 0:\n        return value\n    return round(value/base) * base\n"
  },
  {
    "path": "scripts/Connector/Connector_PCBEdge/molex_EDGELOCK.py",
    "chars": 12566,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\n\n# load parent path of KicadModTree\nsys.path.append(os.path.join(sys.path[0"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/config_phoenix_KLCv1.0.yaml",
    "chars": 1203,
    "preview": "# This holds the configuration information\n# using this config file will create KLCv2.x compatible footprints.\n\nlib_name"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/config_phoenix_KLCv1.1.yaml",
    "chars": 1202,
    "preview": "# This holds the configuration information\n# using this config file will create KLCv2.x compatible footprints.\n\nlib_name"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/config_phoenix_KLCv2.0.yaml",
    "chars": 1202,
    "preview": "# This holds the configuration information\n# using this config file will create KLCv2.x compatible footprints.\n\nlib_name"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/config_phoenix_KLCv3.0.yaml",
    "chars": 1241,
    "preview": "# This holds the configuration information\n# using this config file will create KLCv2.x compatible footprints.\n\n#lib_nam"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/config_phoenix_TERA.yaml",
    "chars": 1206,
    "preview": "# This holds the configuration information\n# using this config file will create KLCv2.x compatible footprints.\n\nlib_name"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/helpers.py",
    "chars": 2002,
    "preview": "def round_to(value, base):\n    return round(value/base) * base\n\ndef v_add(p1,p2):\n    return [p1[0]+p2[0],p1[1]+p2[1]]\n\n"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/mc.py",
    "chars": 17880,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\nfrom helpers import *\nimport re\nimport fnmatch\nimport argparse\nimport yaml\n"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/mc_params.py",
    "chars": 49496,
    "preview": "from collections import namedtuple\nfrom collections import OrderedDict\n\nclass seriesParams():\n    drill = 1.2\n    annula"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/mstb.py",
    "chars": 19260,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\nfrom helpers import *\nimport re\nimport fnmatch\nimport argparse\nimport yaml\n"
  },
  {
    "path": "scripts/Connector/Connector_PhoenixContact/mstb_params.py",
    "chars": 51623,
    "preview": "from collections import namedtuple\nfrom collections import OrderedDict\n\nclass seriesParams():\n    drill = 1.4\n    annula"
  },
  {
    "path": "scripts/Connector/Connector_SMD_single_row_plus_mounting_pad/conn_hirose.yaml",
    "chars": 5718,
    "preview": "group_definitions:\n    manufacturer: 'Hirose'\n\ndevice_definition:\n    DF3EA:\n        series: ''\n        mpn_format_strin"
  },
  {
    "path": "scripts/Connector/Connector_SMD_single_row_plus_mounting_pad/conn_jst.yaml",
    "chars": 25912,
    "preview": "group_definitions:\n    manufacturer: 'JST'\n\ndevice_definition:\n    ACH_top_entry_1:\n        series: 'ACH'\n        mpn_fo"
  },
  {
    "path": "scripts/Connector/Connector_SMD_single_row_plus_mounting_pad/conn_molex.yaml",
    "chars": 22639,
    "preview": "group_definitions:\n    manufacturer: 'Molex'\n\ndevice_definition:\n    Panelmate_side_entry:\n        series: 'Panelmate'\n "
  },
  {
    "path": "scripts/Connector/Connector_SMD_single_row_plus_mounting_pad/helpers.py",
    "chars": 3674,
    "preview": "\nfrom KicadModTree import *\n\ndef roundToBase(value, base):\n    return round(value/base) * base\n\ndef parseAdditionalDrawi"
  },
  {
    "path": "scripts/Connector/Connector_SMD_single_row_plus_mounting_pad/smd_single_row_plus_mounting_pad.py",
    "chars": 24422,
    "preview": "#!/usr/bin/env python3\n\n# Generator for jst smd connectors (single row with two mounting pads)\n\nimport sys\nimport os\n\n# "
  },
  {
    "path": "scripts/Connector/Connector_Samtec/conn_samtec_LSHM_smd_top.py",
    "chars": 12557,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_Samtec/conn_samtec_hle.py",
    "chars": 17822,
    "preview": "#!/usr/bin/env python\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under th"
  },
  {
    "path": "scripts/Connector/Connector_Samtec/helpers.py",
    "chars": 105,
    "preview": "def roundToBase(value, base):\n    if base == 0:\n        return value\n    return round(value/base) * base\n"
  },
  {
    "path": "scripts/Connector/Connector_Samtec/mecf_connector.py",
    "chars": 13408,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\nimport math\n\nfrom operator import add\nfrom helpers import *\nfrom math impor"
  },
  {
    "path": "scripts/Connector/Connector_Samtec/mecf_socket.py",
    "chars": 10589,
    "preview": "#!/usr/bin/env python3\n\nimport sys\nimport os\nimport math\n\nfrom operator import add\nfrom helpers import *\nfrom math impor"
  },
  {
    "path": "scripts/Connector/Connector_Stocko/conn_Stocko_MKS_16xx.py",
    "chars": 10547,
    "preview": "#!/usr/bin/env python3\n\n'''\nkicad-footprint-generator is free software: you can redistribute it and/or\nmodify it under t"
  },
  {
    "path": "scripts/Connector/Connector_TE-Connectivity/conn_ffc_te_84952-84953.py",
    "chars": 10757,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  },
  {
    "path": "scripts/Connector/Connector_TE-Connectivity/conn_fpc_te_1734839.py",
    "chars": 9782,
    "preview": "#!/usr/bin/env python3\n\n# KicadModTree is free software: you can redistribute it and/or\n# modify it under the terms of t"
  }
]

// ... and 214 more files (download for full content)

About this extraction

This page contains the full source code of the pointhi/kicad-footprint-generator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 414 files (3.8 MB), approximately 1.0M tokens, and a symbol index with 1014 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!