diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 485e92ac..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/MySymbols.pretty/bt_player.kicad_mod b/MySymbols.pretty/bt_player.kicad_mod new file mode 100644 index 00000000..6d5020f9 --- /dev/null +++ b/MySymbols.pretty/bt_player.kicad_mod @@ -0,0 +1,41 @@ +(module bt_player (layer F.Cu) (tedit 619E2E58) + (fp_text reference REF** (at 8.6 5.5) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value bt_player (at 13.7 -8) (layer F.Fab) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_line (start -4.05 5.25) (end -4.05 -7.18312) (layer Dwgs.User) (width 0.12)) + (fp_line (start -5.25 6.35762) (end -5.25 5.25) (layer Dwgs.User) (width 0.12)) + (fp_line (start -5.25 5.25) (end -4.05 5.25) (layer Dwgs.User) (width 0.12)) + (fp_line (start 5.95 -1.75) (end 4.05 -1.75) (layer Dwgs.User) (width 0.12)) + (fp_line (start 4.05 -1.75) (end 4.05 -7.182366) (layer Dwgs.User) (width 0.12)) + (fp_line (start 5.95 -1.75) (end 5.95 -0.81) (layer Dwgs.User) (width 0.12)) + (fp_line (start 5.95 -0.81) (end 8.20674 -0.81) (layer Dwgs.User) (width 0.12)) + (fp_arc (start 0 0) (end -4.049999 -7.183119) (angle -301.1588483) (layer Dwgs.User) (width 0.12)) + (fp_text user BATT (at 8 -3.3) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text user SPK (at -6.1 -2.45) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text user ANT (at -6.05 2.7) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_line (start -3.92 7.25) (end 3.91 7.25) (layer Dwgs.User) (width 0.12)) + (fp_poly (pts (xy 4.07 -1.75) (xy 5.95 -1.75) (xy 5.97 -0.81) (xy 8.19 -0.81) + (xy 8.22 0.53) (xy 8.09 1.56) (xy 7.83 2.63) (xy 7.58 3.26) + (xy 7.39 3.64) (xy 7.09 4.22) (xy 6.74 4.77) (xy 6.23 5.39) + (xy 5.74 5.9) (xy 5.46 6.18) (xy 4.91 6.62) (xy 4.13 7.13) + (xy 3.88 7.26) (xy -3.85 7.27) (xy -4.2 7.09) (xy -4.54 6.87) + (xy -4.82 6.68) (xy -5.25 6.33) (xy -5.25 5.26) (xy -4.05 5.26) + (xy -4.04 -7.19) (xy 4.05 -7.19)) (layer Eco2.User) (width 0.1)) + (fp_text user Cutt-out (at 0.59 0.89) (layer Dwgs.User) + (effects (font (size 1 1) (thickness 0.15))) + ) + (pad 4 thru_hole circle (at 5.25 -3.75) (size 1 1) (drill 0.3) (layers *.Cu *.Mask)) + (pad 5 thru_hole circle (at 6.8 -1.75) (size 1 1) (drill 0.3) (layers *.Cu *.Mask)) + (pad 3 thru_hole circle (at -5.1 -5.1) (size 1 1) (drill 0.3) (layers *.Cu *.Mask)) + (pad 2 thru_hole circle (at -6.1 -3.9) (size 1 1) (drill 0.3) (layers *.Cu *.Mask)) + (pad 1 thru_hole circle (at -6.25 4.25) (size 1 1) (drill 0.3) (layers *.Cu *.Mask)) +) diff --git a/kicad-symbols/Device.bck b/kicad-symbols/Device.bck new file mode 100644 index 00000000..7b15e6b6 --- /dev/null +++ b/kicad-symbols/Device.bck @@ -0,0 +1,3387 @@ +EESchema-DOCLIB Version 2.0 +# +$CMP Ammeter_AC +D AC ammeter +K ammeter AC ampere meter +F ~ +$ENDCMP +# +$CMP Ammeter_DC +D DC ammeter +K ammeter DC ampere meter +F ~ +$ENDCMP +# +$CMP Antenna +D Antenna +K antenna +F ~ +$ENDCMP +# +$CMP Antenna_Chip +D Ceramic chip antenna with pin for PCB trace +K antenna +F ~ +$ENDCMP +# +$CMP Antenna_Dipole +D Dipole antenna +K dipole antenna +F ~ +$ENDCMP +# +$CMP Antenna_Loop +D Loop antenna +K loop antenna +F ~ +$ENDCMP +# +$CMP Antenna_Shield +D Antenna with extra pin for shielding +K antenna +F ~ +$ENDCMP +# +$CMP Battery +D Multiple-cell battery +K batt voltage-source cell +F ~ +$ENDCMP +# +$CMP Battery_Cell +D Single-cell battery +K battery cell +F ~ +$ENDCMP +# +$CMP Buzzer +D Buzzer, polarized +K quartz resonator ceramic +F ~ +$ENDCMP +# +$CMP C +D Unpolarized capacitor +K cap capacitor +F ~ +$ENDCMP +# +$CMP C_Feedthrough +D Feedthrough capacitor +K EMI filter feedthrough capacitor +F ~ +$ENDCMP +# +$CMP C_Polarized +D Polarized capacitor +K cap capacitor +F ~ +$ENDCMP +# +$CMP C_Polarized_Small +D Polarized capacitor, small symbol +K cap capacitor +F ~ +$ENDCMP +# +$CMP C_Polarized_Small_US +D Polarized capacitor, small US symbol +K cap capacitor +F ~ +$ENDCMP +# +$CMP C_Polarized_US +D Polarized capacitor, US symbol +K cap capacitor +F ~ +$ENDCMP +# +$CMP C_Small +D Unpolarized capacitor, small symbol +K capacitor cap +F ~ +$ENDCMP +# +$CMP C_Trim +D Trimmable capacitor +K trimmer variable capacitor +F ~ +$ENDCMP +# +$CMP C_Trim_Differential +D Differential variable capacitor with two stators +K trimmer capacitor +F ~ +$ENDCMP +# +$CMP C_Trim_Small +D Trimmable capacitor, small symbol +K trimmer variable capacitor +F ~ +$ENDCMP +# +$CMP C_Variable +D Variable capacitor +K trimmer capacitor +F ~ +$ENDCMP +# +$CMP CircuitBreaker_1P +D Single pole circuit breaker +K CB +F ~ +$ENDCMP +# +$CMP CircuitBreaker_1P_US +D Single pole circuit breaker, US symbol +K CB +F ~ +$ENDCMP +# +$CMP CircuitBreaker_2P +D Double pole circuit breaker +K CB 2P +F ~ +$ENDCMP +# +$CMP CircuitBreaker_2P_US +D Double pole circuit breaker, US symbol +K CB 2P +F ~ +$ENDCMP +# +$CMP CircuitBreaker_3P +D Triple pole circuit breaker +K CB 3P +F ~ +$ENDCMP +# +$CMP CircuitBreaker_3P_US +D Triple pole circuit breaker, US symbol +K CB 3P +F ~ +$ENDCMP +# +$CMP Crystal +D Two pin crystal +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP Crystal_GND2 +D Three pin crystal, GND on pin 2 +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP Crystal_GND23 +D Four pin crystal, GND on pins 2 and 3 +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP Crystal_GND23_Small +D Four pin crystal, GND on pins 2 and 3, small symbol +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP Crystal_GND24 +D Four pin crystal, GND on pins 2 and 4 +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP Crystal_GND24_Small +D Four pin crystal, GND on pins 2 and 4, small symbol +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP Crystal_GND2_Small +D Three pin crystal, GND on pin 2, small symbol +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP Crystal_GND3 +D Three pin crystal, GND on pin 3 +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP Crystal_GND3_Small +D Three pin crystal, GND on pin 3, small symbol +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP Crystal_Small +D Two pin crystal, small symbol +K quartz ceramic resonator oscillator +F ~ +$ENDCMP +# +$CMP D +D Diode +K diode +F ~ +$ENDCMP +# +$CMP DIAC +D Diode for alternating current +K AC diode DIAC +F ~ +$ENDCMP +# +$CMP DIAC_Filled +D Diode for alternating current, filled shape +K AC diode DIAC +F ~ +$ENDCMP +# +$CMP D_AAK +D Diode, anode on pins 1 and 2 +K diode +F ~ +$ENDCMP +# +$CMP D_Bridge_+-AA +D Diode bridge, +ve/-ve/AC/AC +K rectifier ACDC +F ~ +$ENDCMP +# +$CMP D_Bridge_+A-A +D Diode bridge, +ve/AC/-ve/AC +K rectifier ACDC +F ~ +$ENDCMP +# +$CMP D_Bridge_+AA- +D Diode bridge, +ve/AC/AC/-ve +K rectifier ACDC +F ~ +$ENDCMP +# +$CMP D_Bridge_-A+A +D Diode bridge, -ve/AC/+ve/AC +K rectifier ACDC +F ~ +$ENDCMP +# +$CMP D_Bridge_-AA+ +D Diode bridge, -ve/AC/AC/+ve +K rectifier ACDC +F ~ +$ENDCMP +# +$CMP D_Capacitance +D Variable capacitance diode +K capacitance diode varicap varactor +F ~ +$ENDCMP +# +$CMP D_Capacitance_Filled +D Variable capacitance diode, filled shape +K capacitance diode varicap varactor +F ~ +$ENDCMP +# +$CMP D_Dual_CommonAnode_AKK +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonAnode_AKK_Parallel +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonAnode_AKK_Split +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonAnode_KAK +D Dual diode, common anode on pin 2 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonAnode_KAK_Parallel +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonAnode_KAK_Split +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonAnode_KKA +D Dual diode, common anode on pin 3 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonAnode_KKA_Parallel +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonAnode_KKA_Split +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonCathode_AAK +D Dual diode, common cathode on pin 3 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonCathode_AAK_Parallel +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonCathode_AAK_Split +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonCathode_AKA +D Dual diode, common cathode on pin 2 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonCathode_AKA_Parallel +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonCathode_AKA_Split +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonCathode_KAA +D Dual diode, common cathode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonCathode_KAA_Parallel +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_CommonCathode_KAA_Split +D Dual diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_ACK +D Dual diode, anode/center/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_ACK_Parallel +D Dual diode, anode/center/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_ACK_Split +D Dual diode, anode/center/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_AKC +D Dual diode, anode/cathode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_AKC_Parallel +D Dual diode, anode/cathode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_AKC_Split +D Dual diode, anode/cathode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_CAK +D Dual diode, center/anode/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_CAK_Parallel +D Dual diode, center/anode/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_CAK_Split +D Dual diode, center/anode/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_CKA +D Dual diode, center/cathode/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_CKA_Parallel +D Dual diode, center/cathode/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_CKA_Split +D Dual diode, center/cathode/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_KAC +D Dual diode, cathode/anode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_KAC_Parallel +D Dual diode, cathode/anode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_KAC_Split +D Dual diode, cathode/anode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_KCA +D Dual diode, cathode/center/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_KCA_Parallel +D Dual diode, cathode/center/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Dual_Series_KCA_Split +D Dual diode, cathode/center/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Filled +D Diode, filled shape +K diode +F ~ +$ENDCMP +# +$CMP D_KAA +D Diode, anode on pins 2 and 3 +K diode +F ~ +$ENDCMP +# +$CMP D_KAK +D Diode, cathode on pins 1 and 3 +K diode +F ~ +$ENDCMP +# +$CMP D_KKA +D Diode, cathode on pins 1 and 2 +K diode +F ~ +$ENDCMP +# +$CMP D_Laser_1A3C +D Laser diode, cathode on pin 3, anode on pin 1 +K opto laserdiode +F ~ +$ENDCMP +# +$CMP D_Laser_1C2A +D Laser diode, cathode on pin 1, anode on pin 2 +K opto laserdiode +F ~ +$ENDCMP +# +$CMP D_Laser_Photo_MType +D Laser diode with photodiode, common cathode on pin 2 +K opto laserdiode photodiode +F http://www.egismos.disonhu.com/laser/diode-package.htm +$ENDCMP +# +$CMP D_Laser_Photo_NType +D Laser diode with photodiode, center on pin 2, LD cathode on pin 1 +K opto laserdiode photodiode +F http://www.egismos.disonhu.com/laser/diode-package.htm +$ENDCMP +# +$CMP D_Laser_Photo_PType +D Laser diode with photodiode, center on pin 2, PD cathode on pin 3 +K opto laserdiode photodiode +F http://www.egismos.disonhu.com/laser/diode-package.htm +$ENDCMP +# +$CMP D_Photo +D Photodiode +K photodiode diode opto +F ~ +$ENDCMP +# +$CMP D_Photo_Filled +D Photodiode, filled shape +K photodiode diode opto +F ~ +$ENDCMP +# +$CMP D_Radiation +D Semiconductor radiation detector +K radiation detector diode +F ~ +$ENDCMP +# +$CMP D_Radiation_Filled +D Semiconductor radiation detector, filled shape +K radiation detector diode +F ~ +$ENDCMP +# +$CMP D_Schottky +D Schottky diode +K diode Schottky +F ~ +$ENDCMP +# +$CMP D_Schottky_AAK +D Schottky diode, anode on pins 1 and 2 +K diode Schottky SCHDPAK +F ~ +$ENDCMP +# +$CMP D_Schottky_AKA +D Schottky diode, anode on pins 1 and 3 +K diode Schottky SCHDPAK +F ~ +$ENDCMP +# +$CMP D_Schottky_AKK +D Schottky diode, cathode on pins 2 and 3 +K diode Schottky SCHDPAK +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonAnode_AKK +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonAnode_AKK_Parallel +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonAnode_AKK_Split +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonAnode_KAK +D Dual Schottky diode, common anode on pin 2 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonAnode_KAK_Parallel +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonAnode_KAK_Split +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonAnode_KKA +D Dual Schottky diode, common anode on pin 3 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonAnode_KKA_Parallel +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonAnode_KKA_Split +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonCathode_AAK +D Dual Schottky diode, common cathode on pin 3 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonCathode_AAK_Parallel +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonCathode_AAK_Split +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonCathode_AKA +D Dual Schottky diode, common cathode on pin 2 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonCathode_AKA_Parallel +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonCathode_AKA_Split +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonCathode_KAA +D Dual Schottky diode, common cathode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonCathode_KAA_Parallel +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_CommonCathode_KAA_Split +D Dual Schottky diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_ACK +D Dual Schottky diode, anode/center/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_ACK_Parallel +D Dual Schottky diode, anode/center/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_ACK_Split +D Dual Schottky diode, anode/center/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_AKC +D Dual Schottky diode, anode/cathode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_AKC_Parallel +D Dual Schottky diode, anode/cathode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_AKC_Split +D Dual Schottky diode, anode/cathode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_CAK +D Dual Schottky diode, center/anode/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_CAK_Parallel +D Dual Schottky diode, center/anode/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_CAK_Split +D Dual Schottky diode, center/anode/cathode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_CKA +D Dual Schottky diode, center/cathode/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_CKA_Parallel +D Dual Schottky diode, center/cathode/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_CKA_Split +D Dual Schottky diode, center/cathode/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_KAC +D Dual Schottky diode, cathode/anode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_KAC_Parallel +D Dual Schottky diode, cathode/anode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_KAC_Split +D Dual Schottky diode, cathode/anode/center +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_KCA +D Dual Schottky diode, cathode/center/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_KCA_Parallel +D Dual Schottky diode, cathode/center/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Dual_Series_KCA_Split +D Dual Schottky diode, cathode/center/anode +K diode +F ~ +$ENDCMP +# +$CMP D_Schottky_Filled +D Schottky diode, filled shape +K diode Schottky +F ~ +$ENDCMP +# +$CMP D_Schottky_KAA +D Schottky diode, anode on pins 2 and 3 +K diode Schottky SCHDPAK +F ~ +$ENDCMP +# +$CMP D_Schottky_KAK +D Schottky diode, cathode on pins 1 and 3 +K diode Schottky SCHDPAK +F ~ +$ENDCMP +# +$CMP D_Schottky_KKA +D Schottky diode, cathode on pins 1 and 2 +K diode Schottky SCHDPAK +F ~ +$ENDCMP +# +$CMP D_Schottky_Small +D Schottky diode, small symbol +K diode Schottky +F ~ +$ENDCMP +# +$CMP D_Schottky_Small_Filled +D Schottky diode, small symbol, filled shape +K diode Schottky +F ~ +$ENDCMP +# +$CMP D_Shockley +D Shockley (PNPN) diode +K Shockley diode PNPN +F ~ +$ENDCMP +# +$CMP D_SiPM +D Silicon photomultiplier +K SiPM MPPC SPAD photon counting +F ~ +$ENDCMP +# +$CMP D_Small +D Diode, small symbol +K diode +F ~ +$ENDCMP +# +$CMP D_Small_Filled +D Diode, small symbol, filled shape +K diode +F ~ +$ENDCMP +# +$CMP D_TVS +D Bidirectional transient-voltage-suppression diode +K diode TVS thyrector +F ~ +$ENDCMP +# +$CMP D_TVS_Dual_AAC +D Bidirectional dual transient-voltage-suppression diode, center on pin 3 +K diode TVS thyrector +F ~ +$ENDCMP +# +$CMP D_TVS_Dual_ACA +D Bidirectional dual transient-voltage-suppression diode, center on pin 2 +K diode TVS thyrector +F ~ +$ENDCMP +# +$CMP D_TVS_Dual_CAA +D Bidirectional dual transient-voltage-suppression diode, center on pin 1 +K diode TVS thyrector +F ~ +$ENDCMP +# +$CMP D_TVS_Filled +D Bidirectional transient-voltage-suppression diode, filled shape +K diode TVS thyrector +F ~ +$ENDCMP +# +$CMP D_TemperatureDependent +D Temperature dependent diode +K temperature sensor diode +F ~ +$ENDCMP +# +$CMP D_TemperatureDependent_Filled +D Temperature dependent diode, filled shape +K temperature sensor diode +F ~ +$ENDCMP +# +$CMP D_Tunnel +D Tunnel diode (Esaki diode) +K tunnel diode +F ~ +$ENDCMP +# +$CMP D_Tunnel_Filled +D Tunnel diode (Esaki diode), filled shape +K tunnel diode +F ~ +$ENDCMP +# +$CMP D_Unitunnel +D Unitunnel diode +K unitunnel diode +F ~ +$ENDCMP +# +$CMP D_Unitunnel_Filled +D Unitunnel diode, filled shape +K unitunnel diode +F ~ +$ENDCMP +# +$CMP D_Zener +D Zener diode +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonAnode_AKK +D Dual Zener diode, common anode on pin 1 +K diode zener dual +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonAnode_AKK_Parallel +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonAnode_AKK_Split +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonAnode_KAK +D Dual Zener diode, common anode on pin 2 +K diode zener dual +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonAnode_KAK_Parallel +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonAnode_KAK_Split +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonAnode_KKA +D Dual Zener diode, common anode on pin 3 +K diode zener dual +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonAnode_KKA_Parallel +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonAnode_KKA_Split +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonCathode_AAK +D Dual Zener diode, common cathode on pin 3 +K diode zener dual +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonCathode_AAK_Parallel +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonCathode_AAK_Split +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonCathode_AKA +D Dual Zener diode, common cathode on pin 2 +K diode zener dual +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonCathode_AKA_Parallel +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonCathode_AKA_Split +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonCathode_KAA +D Dual Zener diode, common cathode on pin 1 +K diode zener dual +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonCathode_KAA_Parallel +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Dual_CommonCathode_KAA_Split +D Dual Zener diode, common anode on pin 1 +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Filled +D Zener diode, filled shape +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Small +D Zener diode, small symbol +K diode +F ~ +$ENDCMP +# +$CMP D_Zener_Small_Filled +D Zener diode, small symbol, filled shape +K diode +F ~ +$ENDCMP +# +$CMP DelayLine +D Delay line +K delay propagation retard impedance +F ~ +$ENDCMP +# +$CMP Earphone +D Earphone, polarized +K earphone speaker headphone +F ~ +$ENDCMP +# +$CMP ElectromagneticActor +D Electromagnetic actor +K electromagnet coil inductor +F ~ +$ENDCMP +# +$CMP FerriteBead +D Ferrite bead +K L ferrite bead inductor filter +F ~ +$ENDCMP +# +$CMP FerriteBead_Small +D Ferrite bead, small symbol +K L ferrite bead inductor filter +F ~ +$ENDCMP +# +$CMP Filter_EMI_C +D EMI filter, single capacitor +K EMI filter feedthrough capacitor +F http://www.murata.com/~/media/webrenewal/support/library/catalog/products/emc/emifil/c31e.ashx?la=en-gb +$ENDCMP +# +$CMP Filter_EMI_CLC +D EMI T-filter (CLC) +K EMI T-filter +F http://www.murata.com/~/media/webrenewal/support/library/catalog/products/emc/emifil/c31e.ashx?la=en-gb +$ENDCMP +# +$CMP Filter_EMI_CommonMode +D EMI 2-inductor common mode filter +K EMI common mode filter +F ~ +$ENDCMP +# +$CMP Filter_EMI_LCL +D EMI T-filter (LCL) +K EMI T-filter +F http://www.murata.com/~/media/webrenewal/support/library/catalog/products/emc/emifil/c31e.ashx?la=en-gb +$ENDCMP +# +$CMP Filter_EMI_LL +D EMI 2-inductor filter +K EMI filter +F ~ +$ENDCMP +# +$CMP Filter_EMI_LL_1423 +D EMI 2-inductor filter, pin-connections 1-4 and 2-3 +K EMI filter common-mode choke +F ~ +$ENDCMP +# +$CMP FrequencyCounter +D Frequency counter +K frequency counter +F ~ +$ENDCMP +# +$CMP Fuse +D Fuse +K fuse +F ~ +$ENDCMP +# +$CMP Fuse_Polarized +D Polarized fuse +K fuse +F ~ +$ENDCMP +# +$CMP Fuse_Polarized_Small +D Polarized fuse, small symbol +K fuse +F ~ +$ENDCMP +# +$CMP Fuse_Small +D Fuse, small symbol +K fuse +F ~ +$ENDCMP +# +$CMP GDT_2Pin +D Gas Discharge Tube with 2 Pins +K gdt +F ~ +$ENDCMP +# +$CMP GDT_3Pin +D Gas Discharge Tube with 3 Pins +K gdt +F ~ +$ENDCMP +# +$CMP Galvanometer +D Galvanometer +K galvanometer +F ~ +$ENDCMP +# +$CMP HallGenerator +D Hall effect generator +K Hall generator magnet +F ~ +$ENDCMP +# +$CMP Heater +D Resistive heater +K heater R resistor +F ~ +$ENDCMP +# +$CMP L +D Inductor +K inductor choke coil reactor magnetic +F ~ +$ENDCMP +# +$CMP LED +D Light emitting diode +K LED diode +F ~ +$ENDCMP +# +$CMP LED_ABGR +D RGB LED, anode/blue/green/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_ABRG +D RGB LED, anode/blue/red/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_AGBR +D RGB LED, anode/green/blue/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_AGRB +D RGB LED, anode/green/red/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_ARBG +D RGB LED, anode/red/blue/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_ARGB +D RGB LED, anode/red/green/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BAGR +D RGB LED, blue/anode/green/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BARG +D RGB LED, blue/anode/red/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BGAR +D RGB LED, blue/green/anode/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BGKR +D RGB LED, blue/green/cathode/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BGRA +D RGB LED, blue/green/red/anode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BGRK +D RGB LED, blue/green/red/cathode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BKGR +D RGB LED, blue/cathode/green/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BKRG +D RGB LED, blue/cathode/red/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BRAG +D RGB LED, blue/red/anode/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BRGA +D RGB LED, blue/red/green/anode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BRGK +D RGB LED, blue/red/green/cathode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_BRKG +D RGB LED, blue/red/cathode/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_Dual_AAK +D Dual LED, common cathode on pin 3 +K LED diode bicolor dual +F ~ +$ENDCMP +# +$CMP LED_Dual_AAKK +D Dual LED, cathodes on pins 3 and 4 +K LED diode bicolor dual +F ~ +$ENDCMP +# +$CMP LED_Dual_AKA +D Dual LED, common cathode on pin 2 +K LED diode bicolor dual +F ~ +$ENDCMP +# +$CMP LED_Dual_AKAK +D Dual LED, cathodes on pins 2 and 4 +K LED diode bicolor dual +F ~ +$ENDCMP +# +$CMP LED_Dual_Bidirectional +D Dual LED, bidirectional +K LED diode bicolor dual +F ~ +$ENDCMP +# +$CMP LED_Dual_KAK +D Dual LED, common anode on pin 2 +K LED diode bicolor dual +F ~ +$ENDCMP +# +$CMP LED_Dual_KAKA +D Dual LED, cathodes on pins 1 and 3 +K LED diode bicolor dual +F ~ +$ENDCMP +# +$CMP LED_Dual_KKA +D Dual LED, common anode on pin 3 +K LED diode bicolor dual +F ~ +$ENDCMP +# +$CMP LED_Filled +D Light emitting diode, filled shape +K LED diode +F ~ +$ENDCMP +# +$CMP LED_GABR +D RGB LED, green/anode/blue/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GARB +D RGB LED, green/anode/red/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GBAR +D RGB LED, green/blue/anode/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GBKR +D RGB LED, green/blue/cathode/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GBRA +D RGB LED, green/blue/red/anode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GBRK +D RGB LED, green/blue/red/cathode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GKBR +D RGB LED, green/cathode/blue/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GKRB +D RGB LED, green/cathode/red/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GRAB +D RGB LED, green/red/anode/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GRBA +D RGB LED, green/red/blue/anode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GRBK +D RGB LED, green/red/blue/cathode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_GRKB +D RGB LED, green/red/cathode/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_KBGR +D RGB LED, cathode/blue/green/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_KBRG +D RGB LED, cathode/blue/red/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_KGBR +D RGB LED, cathode/green/blue/red +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_KGRB +D RGB LED, cathode/green/red/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_KRBG +D RGB LED, cathode/red/blue/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_KRGB +D RGB LED, cathode/red/green/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_Pad +D Light emitting diode with pad +K LED diode pad +F ~ +$ENDCMP +# +$CMP LED_RABG +D RGB LED, red/anode/blue/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RAGB +D RGB LED, red/anode/green/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RBAG +D RGB LED, red/blue/anode/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RBGA +D RGB LED, red/blue/green/anode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RBGK +D RGB LED, red/blue/green/cathode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RBKG +D RGB LED, red/blue/cathode/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RGAB +D RGB LED, red/green/anode/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RGB +D RGB LED, 6 pin package +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RGBA +D RGB LED, red/green/blue/anode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RGBK +D RGB LED, red/green/blue/cathode +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RGB_EP +D RGB LED, 6 pin package with exposed pad +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RGKB +D RGB LED, red/green/cathode/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RKBG +D RGB LED, red/cathode/blue/green +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_RKGB +D RGB LED, red/cathode/green/blue +K LED RGB diode +F ~ +$ENDCMP +# +$CMP LED_Series +D Several LEDs in series +K LED diode +F ~ +$ENDCMP +# +$CMP LED_Series_Pad +D Several LEDs in series with exposed pad +K LED diode pad +F ~ +$ENDCMP +# +$CMP LED_Small +D Light emitting diode, small symbol +K LED diode light-emitting-diode +F ~ +$ENDCMP +# +$CMP LED_Small_Filled +D Light emitting diode, small symbol, filled shape +K LED diode light-emitting-diode +F ~ +$ENDCMP +# +$CMP L_Coupled +D Coupled inductor +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Coupled_1243 +D Coupled inductor +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Coupled_1324 +D Coupled inductor +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Coupled_1342 +D Coupled inductor +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Coupled_1423 +D Coupled inductor +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Coupled_Small +D Coupled inductor, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Coupled_Small_1243 +D Coupled inductor, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Coupled_Small_1324 +D Coupled inductor, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Coupled_Small_1342 +D Coupled inductor, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Coupled_Small_1423 +D Coupled inductor, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite +D Inductor with ferrite core +K inductor choke coil reactor magnetic +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled +D Coupled inductor with ferrite core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled_1243 +D Coupled inductor with ferrite core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled_1324 +D Coupled inductor with ferrite core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled_1342 +D Coupled inductor with ferrite core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled_1423 +D Coupled inductor with ferrite core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled_Small +D Coupled inductor with ferrite core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled_Small_1243 +D Coupled inductor with ferrite core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled_Small_1324 +D Coupled inductor with ferrite core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled_Small_1342 +D Coupled inductor with ferrite core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Coupled_Small_1423 +D Coupled inductor with ferrite core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Ferrite_Small +D Inductor with ferrite core, small symbol +K inductor choke coil reactor magnetic +F ~ +$ENDCMP +# +$CMP L_Iron +D Inductor with iron core +K inductor choke coil reactor magnetic +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled +D Coupled inductor with iron core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled_1243 +D Coupled inductor with iron core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled_1324 +D Coupled inductor with iron core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled_1342 +D Coupled inductor with iron core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled_1423 +D Coupled inductor with iron core +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled_Small +D Coupled inductor with iron core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled_Small_1243 +D Coupled inductor with iron core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled_Small_1324 +D Coupled inductor with iron core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled_Small_1342 +D Coupled inductor with iron core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Coupled_Small_1423 +D Coupled inductor with iron core, small symbol +K inductor choke coil reactor magnetic coupled +F ~ +$ENDCMP +# +$CMP L_Iron_Small +D Inductor with iron core, small symbol +K inductor choke coil reactor magnetic +F ~ +$ENDCMP +# +$CMP L_Small +D Inductor, small symbol +K inductor choke coil reactor magnetic +F ~ +$ENDCMP +# +$CMP L_Trim +D Variable inductor +K inductor choke coil reactor magnetic +F ~ +$ENDCMP +# +$CMP Lamp +D Lamp +K lamp +F ~ +$ENDCMP +# +$CMP Lamp_Flash +D Flash lamp tube +K flash lamp +F ~ +$ENDCMP +# +$CMP Lamp_Neon +D Neon lamp +K neon lamp +F ~ +$ENDCMP +# +$CMP Memristor +D Memristor +K memristor +F ~ +$ENDCMP +# +$CMP Microphone +D Microphone +K microphone +F ~ +$ENDCMP +# +$CMP Microphone_Condenser +D Condenser microphone +K capacitance condenser microphone +F ~ +$ENDCMP +# +$CMP Microphone_Crystal +D Crystal microphone +K microphone crystal +F ~ +$ENDCMP +# +$CMP Microphone_Ultrasound +D Ultrasound receiver +K microphone ultrasound crystal +F ~ +$ENDCMP +# +$CMP NetTie_2 +D Net tie, 2 pins +K net tie short +F ~ +$ENDCMP +# +$CMP NetTie_3 +D Net tie, 3 pins +K net tie short +F ~ +$ENDCMP +# +$CMP NetTie_3_Tee +D Net tie, 3 pins, tee +K net tie short +F ~ +$ENDCMP +# +$CMP NetTie_4 +D Net tie, 4 pins +K net tie short +F ~ +$ENDCMP +# +$CMP NetTie_4_Cross +D Net tie, 4 pins, cross +K net tie short +F ~ +$ENDCMP +# +$CMP Ohmmeter +D Ohmmeter +K ohmmeter resistance +F ~ +$ENDCMP +# +$CMP Opamp_Dual +D Dual operational amplifier +K dual opamp +F ~ +$ENDCMP +# +$CMP Opamp_Quad +D Quad operational amplifier +K quad opamp +F ~ +$ENDCMP +# +$CMP Oscilloscope +D Oscilloscope +K oscilloscope +F ~ +$ENDCMP +# +$CMP PeltierElement +D Peltier element, thermoelectric cooler +K Peltier TEC +F ~ +$ENDCMP +# +$CMP Polyfuse +D Resettable fuse, polymeric positive temperature coefficient +K resettable fuse PTC PPTC polyfuse polyswitch +F ~ +$ENDCMP +# +$CMP Polyfuse_Small +D Resettable fuse, polymeric positive temperature coefficient, small symbol +K resettable fuse PTC PPTC polyfuse polyswitch +F ~ +$ENDCMP +# +$CMP Q_Dual_NMOS_G1S2G2D2S1D1 +D Dual NMOS transistor, 6 pin package +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_Dual_NMOS_S1G1D2S2G2D1 +D Dual NMOS transistor, 6 pin package +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_Dual_NMOS_S1G1S2G2D2D2D1D1 +D Dual NMOS transistor, 8 pin package +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_Dual_NPN_C2C1E1E2 +D Double NPN transistors, current mirror configuration +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_Dual_NPN_NPN_BRT_E1B1C2E2B2C1 +D Dual NPN bias resistor transistor, 6 pin package +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_Dual_NPN_NPN_C2E2C1E1B1B2 +D Dual NPN transistor, 6 pin package +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_Dual_NPN_NPN_E1B1C2E2B2C1 +D Dual NPN transistor, 6 pin package +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_Dual_NPN_PNP_BRT_E1B1C2E2B2C1 +D Dual NPN/PNP bias resistor transistor, 6 pin package +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_Dual_NPN_PNP_E1B1C2E2B2C1 +D Dual NPN/PNP transistor, 6 pin package +K transistor NPN PNP +F ~ +$ENDCMP +# +$CMP Q_Dual_PMOS_G1S2G2D2S1D1 +D Dual PMOS transistor, 6 pin package +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_Dual_PMOS_S1G1D2S2G2D1 +D Dual PMOS transistor, 6 pin package +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_Dual_PMOS_S1G1S2G2D2D2D1D1 +D Dual PMOS transistor, 8 pin package +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_Dual_PNP_C2C1E1E2 +D Double PNP transistors, current mirror configuration +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_Dual_PNP_NPN_BRT_E1B1C2E2B2C1 +D Dual PNP/NPN bias resistor transistor, 6 pin package +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_Dual_PNP_PNP_BRT_E1B1C2E2B2C1 +D Dual PNP bias resistor transistor, 6 pin package +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_Dual_PNP_PNP_C1B1B2C2E2E1 +D Dual PNP transistor, 6 pin package +K transistor PNP +F https://www.diodes.com/assets/Datasheets/ds30437.pdf +$ENDCMP +# +$CMP Q_Dual_PNP_PNP_C2E2C1E1B1B2 +D Dual PNP transistor, 6 pin package +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_Dual_PNP_PNP_E1B1C2E2B2C1 +D Dual PNP transistor, 6 pin package +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_NIGBT_CEG +D N-IGBT transistor, collector/emitter/gate +K transistor IGBT N-IGBT +F ~ +$ENDCMP +# +$CMP Q_NIGBT_CGE +D N-IGBT transistor, collector/gate/emitter +K transistor IGBT N-IGBT +F ~ +$ENDCMP +# +$CMP Q_NIGBT_ECG +D N-IGBT transistor, emitter/collector/gate +K transistor IGBT N-IGBT +F ~ +$ENDCMP +# +$CMP Q_NIGBT_ECGC +D N-IGBT transistor, emitter/collector/gate, collector connected to mounting plane +K transistor IGBT N-IGBT +F ~ +$ENDCMP +# +$CMP Q_NIGBT_EGC +D N-IGBT transistor, emitter/gate/collector +K transistor IGBT N-IGBT +F ~ +$ENDCMP +# +$CMP Q_NIGBT_GCE +D N-IGBT transistor, gate/collector/emitter +K transistor IGBT N-IGBT +F ~ +$ENDCMP +# +$CMP Q_NIGBT_GCEC +D N-IGBT transistor, gate/collector/emitter, collector connected to mounting plane +K transistor IGBT N-IGBT +F ~ +$ENDCMP +# +$CMP Q_NIGBT_GEC +D N-IGBT transistor, gate/emitter/collector +K transistor IGBT N-IGBT +F ~ +$ENDCMP +# +$CMP Q_NJFET_DGS +D N-JFET transistor, drain/gate/source +K transistor NJFET N-JFET +F ~ +$ENDCMP +# +$CMP Q_NJFET_DSG +D N-JFET transistor, drain/source/gate +K transistor NJFET N-JFET +F ~ +$ENDCMP +# +$CMP Q_NJFET_GDS +D N-JFET transistor, gate/drain/source +K transistor NJFET N-JFET +F ~ +$ENDCMP +# +$CMP Q_NJFET_GSD +D N-JFET transistor, gate/source/drain +K transistor NJFET N-JFET +F ~ +$ENDCMP +# +$CMP Q_NJFET_SDG +D N-JFET transistor, source/drain/gate +K transistor NJFET N-JFET +F ~ +$ENDCMP +# +$CMP Q_NJFET_SGD +D N-JFET transistor, source/gate/drain +K transistor NJFET N-JFET +F ~ +$ENDCMP +# +$CMP Q_NMOS_DGS +D N-MOSFET transistor, drain/gate/source +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_NMOS_DSG +D N-MOSFET transistor, drain/source/gate +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_NMOS_GDS +D N-MOSFET transistor, gate/drain/source +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_NMOS_GDSD +D N-MOSFET transistor, gate/drain/source, drain connected to mounting plane +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_NMOS_GSD +D N-MOSFET transistor, gate/source/drain +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_NMOS_SDG +D N-MOSFET transistor, source/drain/gate +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_NMOS_SDGD +D N-MOSFET transistor, source/drain/gate, drain connected to mounting plane +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_NMOS_SGD +D N-MOSFET transistor, source/gate/drain +K transistor NMOS N-MOS N-MOSFET +F ~ +$ENDCMP +# +$CMP Q_NPN_BCE +D NPN transistor, base/collector/emitter +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NPN_BCEC +D NPN transistor, base/collector/emitter, collector connected to mounting plane +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NPN_BEC +D NPN transistor, base/emitter/collector +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NPN_BEC_BRT +D NPN bias resistor transistor, base/emitter/collector +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NPN_CBE +D NPN transistor, collector/base/emitter +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NPN_CEB +D NPN transistor, collector/emitter/base +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NPN_Darlington_BCE +D NPN Darlington transistor, base/collector/emitter +K transistor NPN Darlington +F ~ +$ENDCMP +# +$CMP Q_NPN_Darlington_BCEC +D NPN Darlington transistor, base/collector/emitter, collector connected to mounting plane +K transistor NPN Darlington +F ~ +$ENDCMP +# +$CMP Q_NPN_Darlington_BEC +D NPN Darlington transistor, base/emitter/collector +K transistor NPN Darlington +F ~ +$ENDCMP +# +$CMP Q_NPN_Darlington_CBE +D NPN Darlington transistor, collector/base/emitter +K transistor NPN Darlington +F ~ +$ENDCMP +# +$CMP Q_NPN_Darlington_CEB +D NPN Darlington transistor, collector/emitter/base +K transistor NPN Darlington +F ~ +$ENDCMP +# +$CMP Q_NPN_Darlington_EBC +D NPN Darlington transistor, emitter/base/collector +K transistor NPN Darlington +F ~ +$ENDCMP +# +$CMP Q_NPN_Darlington_ECB +D NPN Darlington transistor, emitter/collector/base +K transistor NPN Darlington +F ~ +$ENDCMP +# +$CMP Q_NPN_Darlington_ECBC +D NPN Darlington transistor, emitter/collector/base, collector connected to mounting plane +K transistor NPN Darlington +F ~ +$ENDCMP +# +$CMP Q_NPN_EBC +D NPN transistor, emitter/base/collector +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NPN_ECB +D NPN transistor, emitter/collector/base +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NPN_ECBC +D NPN transistor, emitter/collector/base, collector connected to mounting plane +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NPN_ECB_BRT +D NPN transistor, emitter/collector/base +K transistor NPN +F ~ +$ENDCMP +# +$CMP Q_NUJT_BEB +D N-Type unijunction transistor +K transistor UJT +F ~ +$ENDCMP +# +$CMP Q_PJFET_DGS +D P-JFET transistor, drain/gate/source +K transistor PJFET P-JFET +F ~ +$ENDCMP +# +$CMP Q_PJFET_DSG +D P-JFET transistor, drain/source/gate +K transistor PJFET P-JFET +F ~ +$ENDCMP +# +$CMP Q_PJFET_GDS +D P-JFET transistor, gate/drain/source +K transistor PJFET P-JFET +F ~ +$ENDCMP +# +$CMP Q_PJFET_GSD +D P-JFET transistor, gate/source/drain +K transistor PJFET P-JFET +F ~ +$ENDCMP +# +$CMP Q_PJFET_SDG +D P-JFET transistor, source/drain/gate +K transistor PJFET P-JFET +F ~ +$ENDCMP +# +$CMP Q_PJFET_SGD +D P-JFET transistor, source/gate/drain +K transistor PJFET P-JFET +F ~ +$ENDCMP +# +$CMP Q_PMOS_DGS +D P-MOSFET transistor, drain/gate/source +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_PMOS_DSG +D P-MOSFET transistor, drain/source/gate +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_PMOS_GDS +D P-MOSFET transistor, gate/drain/source +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_PMOS_GDSD +D P-MOSFET transistor, gate/drain/source, drain connected to mounting plane +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_PMOS_GSD +D P-MOSFET transistor, gate/source/drain +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_PMOS_SDG +D P-MOSFET transistor, source/drain/gate +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_PMOS_SDGD +D P-MOSFET transistor, source/drain/gate, drain connected to mounting plane +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_PMOS_SGD +D P-MOSFET transistor, source/gate/drain +K transistor PMOS P-MOS P-MOSFET +F ~ +$ENDCMP +# +$CMP Q_PNP_BCE +D PNP transistor, base/collector/emitter +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PNP_BCEC +D PNP transistor, base/collector/emitter, collector connected to mounting plane +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PNP_BEC +D PNP transistor, base/emitter/collector +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PNP_BEC_BRT +D PNP bias resistor transistor, base/emitter/collector +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PNP_CBE +D PNP transistor, collector/base/emitter +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PNP_CEB +D PNP transistor, collector/emitter/base +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PNP_Darlington_BCE +D PNP Darlington transistor, base/collector/emitter +K transistor PNP Darlington +F ~ +$ENDCMP +# +$CMP Q_PNP_Darlington_BCEC +D PNP Darlington transistor, base/collector/emitter, collector connected to mounting plane +K transistor PNP Darlington +F ~ +$ENDCMP +# +$CMP Q_PNP_Darlington_BEC +D PNP Darlington transistor, base/emitter/collector +K transistor PNP Darlington +F ~ +$ENDCMP +# +$CMP Q_PNP_Darlington_CBE +D PNP Darlington transistor, collector/base/emitter +K transistor PNP Darlington +F ~ +$ENDCMP +# +$CMP Q_PNP_Darlington_CEB +D PNP Darlington transistor, collector/emitter/base +K transistor PNP Darlington +F ~ +$ENDCMP +# +$CMP Q_PNP_Darlington_EBC +D PNP Darlington transistor, emitter/base/collector +K transistor PNP Darlington +F ~ +$ENDCMP +# +$CMP Q_PNP_Darlington_ECB +D PNP Darlington transistor, emitter/collector/base +K transistor PNP Darlington +F ~ +$ENDCMP +# +$CMP Q_PNP_Darlington_ECBC +D PNP Darlington transistor, emitter/collector/base, collector connected to mounting plane +K transistor PNP Darlington +F ~ +$ENDCMP +# +$CMP Q_PNP_EBC +D PNP transistor, emitter/base/collector +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PNP_ECB +D PNP transistor, emitter/collector/base +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PNP_ECBC +D PNP transistor, emitter/collector/base, collector connected to mounting plane +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PNP_ECB_BRT +D PNP bias resistor transistor, emitter/collector/base +K transistor PNP +F ~ +$ENDCMP +# +$CMP Q_PUJT_BEB +D P-Type unijunction transistor +K transistor UJT +F ~ +$ENDCMP +# +$CMP Q_Photo_NPN +D NPN phototransistor, collector/emitter +K phototransistor NPN +F ~ +$ENDCMP +# +$CMP Q_Photo_NPN_CBE +D NPN phototransistor, collector/base/emitter +K phototransistor NPN +F ~ +$ENDCMP +# +$CMP Q_Photo_NPN_CE +D NPN phototransistor, collector/emitter +K phototransistor NPN +F ~ +$ENDCMP +# +$CMP Q_Photo_NPN_EBC +D NPN phototransistor, emitter/base/collector +K phototransistor NPN +F ~ +$ENDCMP +# +$CMP Q_Photo_NPN_EC +D NPN phototransistor, emitter/collector +K phototransistor NPN +F ~ +$ENDCMP +# +$CMP Q_SCR_AGK +D Silicon controlled rectifier, anode/gate/cathode +K SCR thyristor +F ~ +$ENDCMP +# +$CMP Q_SCR_AKG +D Silicon controlled rectifier, anode/cathode/gate +K SCR thyristor +F ~ +$ENDCMP +# +$CMP Q_SCR_GAK +D Silicon controlled rectifier, gate/anode/cathode +K SCR thyristor +F ~ +$ENDCMP +# +$CMP Q_SCR_GKA +D Silicon controlled rectifier, gate/cathode/anode +K SCR thyristor +F ~ +$ENDCMP +# +$CMP Q_SCR_KAG +D Silicon controlled rectifier, cathode/anode/gate +K SCR thyristor +F ~ +$ENDCMP +# +$CMP Q_SCR_KGA +D Silicon controlled rectifier, cathode/gate/anode +K SCR thyristor +F ~ +$ENDCMP +# +$CMP Q_TRIAC_A1A2G +D Triode for alternating current, anode1/anode2/gate +K TRIAC +F ~ +$ENDCMP +# +$CMP Q_TRIAC_A1GA2 +D Triode for alternating current, anode1/gate/anode2 +K TRIAC +F ~ +$ENDCMP +# +$CMP Q_TRIAC_A2A1G +D Triode for alternating current, anode2/anode1/gate +K TRIAC +F ~ +$ENDCMP +# +$CMP Q_TRIAC_A2GA1 +D Triode for alternating current, anode2/gate/anode1 +K TRIAC +F ~ +$ENDCMP +# +$CMP Q_TRIAC_GA1A2 +D Triode for alternating current, gate/anode1/anode2 +K TRIAC +F ~ +$ENDCMP +# +$CMP Q_TRIAC_GA2A1 +D Triode for alternating current, gate/anode2/anode1 +K TRIAC +F ~ +$ENDCMP +# +$CMP R +D Resistor +K R res resistor +F ~ +$ENDCMP +# +$CMP RFShield_OnePiece +D One-piece EMI RF shielding cabinet +K RF EMI shielding cabinet +F ~ +$ENDCMP +# +$CMP RFShield_TwoPieces +D Two-piece EMI RF shielding cabinet +K RF EMI shielding cabinet +F ~ +$ENDCMP +# +$CMP R_Network03 +D 3 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network03_Split +D 3 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network03_US +D 3 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network04 +D 4 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network04_Split +D 4 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network04_US +D 4 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network05 +D 5 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network05_Split +D 5 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network05_US +D 5 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network06 +D 6 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network06_Split +D 6 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network06_US +D 6 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network07 +D 7 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network07_Split +D 7 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network07_US +D 7 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network08 +D 8 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network08_Split +D 8 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network08_US +D 8 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network09 +D 9 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network09_Split +D 9 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network09_US +D 9 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network10 +D 10 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network10_Split +D 10 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network10_US +D 10 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network11 +D 11 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network11_Split +D 11 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network11_US +D 11 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network12 +D 12 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network12_Split +D 12 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network12_US +D 12 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network13 +D 13 resistor network, star topology, bussed resistors, small symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network13_Split +D 13 resistor network, star topology, bussed resistors, split +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network13_US +D 13 resistor network, star topology, bussed resistors, small US symbol +K R network star-topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x02_SIP +D 2 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x03_SIP +D 3 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x04_SIP +D 4 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x05_SIP +D 5 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x06_SIP +D 6 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x07_SIP +D 7 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x08_SIP +D 8 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x09_SIP +D 9 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x10_SIP +D 10 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Network_Dividers_x11_SIP +D 11 voltage divider network, dual terminator, SIP package +K R network divider topology +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack02 +D 2 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack02_SIP +D 2 resistor network, parallel topology, SIP package +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack02_SIP_Split +D 2 resistor network, parallel topology, SIP package, split +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack02_Split +D 2 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack03 +D 3 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack03_SIP +D 3 resistor network, parallel topology, SIP package +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack03_SIP_Split +D 3 resistor network, parallel topology, SIP package, split +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack03_Split +D 3 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack04 +D 4 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack04_SIP +D 4 resistor network, parallel topology, SIP package +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack04_SIP_Split +D 4 resistor network, parallel topology, SIP package, split +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack04_Split +D 4 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack05 +D 5 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack05_SIP +D 5 resistor network, parallel topology, SIP package +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack05_SIP_Split +D 5 resistor network, parallel topology, SIP package, split +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack05_Split +D 5 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack06 +D 6 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack06_SIP +D 6 resistor network, parallel topology, SIP package +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack06_SIP_Split +D 6 resistor network, parallel topology, SIP package, split +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack06_Split +D 6 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack07 +D 7 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack07_SIP +D 7 resistor network, parallel topology, SIP package +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack07_SIP_Split +D 7 resistor network, parallel topology, SIP package, split +K R network parallel topology isolated +F http://www.vishay.com/docs/31509/csc.pdf +$ENDCMP +# +$CMP R_Pack07_Split +D 7 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack08 +D 8 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack08_Split +D 8 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack09 +D 9 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack09_Split +D 9 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack10 +D 10 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack10_Split +D 10 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack11 +D 11 resistor network, parallel topology +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Pack11_Split +D 11 resistor network, parallel topology, split +K R network parallel topology isolated +F ~ +$ENDCMP +# +$CMP R_Photo +D Photoresistor +K resistor variable light sensitive opto LDR +F ~ +$ENDCMP +# +$CMP R_Potentiometer +D Potentiometer +K resistor variable +F ~ +$ENDCMP +# +$CMP R_Potentiometer_Dual +D Dual potentiometer +K resistor variable +F ~ +$ENDCMP +# +$CMP R_Potentiometer_Dual_Separate +D Dual potentiometer, separate units +K resistor variable +F ~ +$ENDCMP +# +$CMP R_Potentiometer_MountingPin +D Potentiometer with a mounting pin +K resistor variable +F ~ +$ENDCMP +# +$CMP R_Potentiometer_Small +D Potentiometer +K resistor variable +F ~ +$ENDCMP +# +$CMP R_Potentiometer_Trim +D Trim-potentiometer +K resistor variable trimpot trimmer +F ~ +$ENDCMP +# +$CMP R_Potentiometer_Trim_US +D Trim-potentiometer, US symbol +K resistor variable trimpot trimmer +F ~ +$ENDCMP +# +$CMP R_Potentiometer_US +D Potentiometer, US symbol +K resistor variable +F ~ +$ENDCMP +# +$CMP R_Shunt +D Shunt resistor +K R res shunt resistor +F ~ +$ENDCMP +# +$CMP R_Shunt_US +D Shunt resistor, US symbol +K R res shunt resistor +F ~ +$ENDCMP +# +$CMP R_Small +D Resistor, small symbol +K R resistor +F ~ +$ENDCMP +# +$CMP R_Small_US +D Resistor, small US symbol +K r resistor +F ~ +$ENDCMP +# +$CMP R_Trim +D Trimmable resistor (preset resistor) +K R res resistor variable potentiometer trimmer +F ~ +$ENDCMP +# +$CMP R_US +D Resistor, US symbol +K R res resistor +F ~ +$ENDCMP +# +$CMP R_Variable +D Variable resistor +K R res resistor variable potentiometer rheostat +F ~ +$ENDCMP +# +$CMP R_Variable_US +D Variable resistor, US symbol +K R res resistor variable potentiometer rheostat +F ~ +$ENDCMP +# +$CMP Resonator +D Three pin ceramic resonator +K ceramic resonator +F ~ +$ENDCMP +# +$CMP Resonator_Small +D Three pin ceramic resonator, small symbol +K ceramic resonator +F ~ +$ENDCMP +# +$CMP RotaryEncoder +D Rotary encoder, dual channel, incremental quadrate outputs +K rotary switch encoder +F ~ +$ENDCMP +# +$CMP RotaryEncoder_Switch +D Rotary encoder, dual channel, incremental quadrate outputs, with switch +K rotary switch encoder switch push button +F ~ +$ENDCMP +# +$CMP Solar_Cell +D Single solar cell +K solar cell +F ~ +$ENDCMP +# +$CMP Solar_Cells +D Multiple solar cells +K solar cell +F ~ +$ENDCMP +# +$CMP SparkGap +D Spark gap +K spark gap ESD electrostatic suppression +F ~ +$ENDCMP +# +$CMP Speaker +D Speaker +K speaker sound +F ~ +$ENDCMP +# +$CMP Speaker_Crystal +D Crystal speaker/transducer +K crystal speaker ultrasonic transducer +F ~ +$ENDCMP +# +$CMP Speaker_Ultrasound +D Ultrasonic transducer +K crystal speaker ultrasonic transducer +F ~ +$ENDCMP +# +$CMP Thermistor +D Temperature dependent resistor +K R res thermistor +F ~ +$ENDCMP +# +$CMP Thermistor_NTC +D Temperature dependent resistor, negative temperature coefficient +K thermistor NTC resistor sensor RTD +F ~ +$ENDCMP +# +$CMP Thermistor_NTC_3Wire +D Temperature dependent resistor, negative temperature coefficient, 3-wire interface +K thermistor NTC resistor sensor RTD +F ~ +$ENDCMP +# +$CMP Thermistor_NTC_4Wire +D Temperature dependent resistor, negative temperature coefficient, 4-wire interface +K thermistor NTC resistor sensor RTD +F ~ +$ENDCMP +# +$CMP Thermistor_NTC_US +D Temperature dependent resistor, negative temperature coefficient, US symbol +K thermistor NTC resistor sensor RTD +F ~ +$ENDCMP +# +$CMP Thermistor_PTC +D Temperature dependent resistor, positive temperature coefficient +K resistor PTC thermistor sensor RTD +F ~ +$ENDCMP +# +$CMP Thermistor_PTC_3Wire +D Temperature dependent resistor, positive temperature coefficient, 3-wire interface +K resistor PTC thermistor sensor RTD +F ~ +$ENDCMP +# +$CMP Thermistor_PTC_4Wire +D Temperature dependent resistor, positive temperature coefficient, 3-wire interface +K resistor PTC thermistor sensor RTD +F ~ +$ENDCMP +# +$CMP Thermistor_PTC_US +D Temperature dependent resistor, positive temperature coefficient, US symbol +K resistor PTC thermistor sensor RTD +F ~ +$ENDCMP +# +$CMP Thermistor_US +D Thermistor, temperature dependent resistor, US symbol +K R res thermistor +F ~ +$ENDCMP +# +$CMP Thermocouple +D Thermocouple +K thermocouple temperature sensor cold junction +F ~ +$ENDCMP +# +$CMP Thermocouple_Alt +D Thermocouple with connector block +K thermocouple temperature sensor cold junction +F ~ +$ENDCMP +# +$CMP Thermocouple_Block +D Thermocouple with isothermal block +K thermocouple temperature sensor cold junction +F ~ +$ENDCMP +# +$CMP Transformer_1P_1S +D Transformer, single primary, single secondary +K transformer coil magnet +F ~ +$ENDCMP +# +$CMP Transformer_1P_1S_SO8 +D Transformer, single primary, single secondary, SO-8 package +K transformer coil magnet +F ~ +$ENDCMP +# +$CMP Transformer_1P_2S +D Transformer, single primary, dual secondary +K transformer coil magnet +F ~ +$ENDCMP +# +$CMP Transformer_1P_SS +D Transformer, single primary, split secondary +K transformer coil magnet +F ~ +$ENDCMP +# +$CMP Transformer_Audio +D Audio transformer +K transformer coil magnet sound +F ~ +$ENDCMP +# +$CMP Transformer_SP_1S +D Transformer, split primary, single secondary +K transformer coil magnet +F ~ +$ENDCMP +# +$CMP Transformer_SP_2S +D Transformer, split primary, dual secondary +K transformer coil magnet +F ~ +$ENDCMP +# +$CMP Varistor +D Voltage dependent resistor +K VDR resistance +F ~ +$ENDCMP +# +$CMP Varistor_US +D Voltage dependent resistor, US symbol +K VDR resistance +F ~ +$ENDCMP +# +$CMP VoltageDivider +D Voltage divider +K R network voltage divider +F ~ +$ENDCMP +# +$CMP VoltageDivider_CenterPin1 +D Voltage divider, center on pin 1 +K R network voltage divider +F ~ +$ENDCMP +# +$CMP VoltageDivider_CenterPin3 +D Voltage divider, center on pin 3 +K R network voltage divider +F ~ +$ENDCMP +# +$CMP Voltmeter_AC +D AC voltmeter +K voltmeter AC +F ~ +$ENDCMP +# +$CMP Voltmeter_DC +D DC voltmeter +K voltmeter DC +F ~ +$ENDCMP +# +#End Doc Library diff --git a/kicad-symbols/Device.lib b/kicad-symbols/Device.lib index 8afec21d..109667b4 100644 --- a/kicad-symbols/Device.lib +++ b/kicad-symbols/Device.lib @@ -16811,4 +16811,21 @@ X + 2 0 200 100 D 50 50 1 1 P ENDDRAW ENDDEF # +# bt_player +# +DEF bt_player U 0 40 Y Y 1 F N +F0 "U" -50 250 50 H V C CNN +F1 "bt_player" -50 -450 50 H V C CNN +F2 "" 0 0 50 H I C CNN +F3 "" 0 0 50 H I C CNN +DRAW +S -550 200 150 -400 0 1 0 N +X ANT 1 250 100 100 L 50 50 1 1 I +X SPK+ 2 250 -150 100 L 50 50 1 1 I +X SPK- 3 250 -250 100 L 50 50 1 1 I +X BATT- 4 -650 0 100 R 50 50 1 1 I +X BATT+ 5 -650 100 100 R 50 50 1 1 I +ENDDRAW +ENDDEF +# #End Library diff --git a/kicad_plugins/.gitattributes b/kicad_plugins/.gitattributes new file mode 100644 index 00000000..dfe07704 --- /dev/null +++ b/kicad_plugins/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/kicad_plugins/LICENSE b/kicad_plugins/LICENSE new file mode 100644 index 00000000..e62ec04c --- /dev/null +++ b/kicad_plugins/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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. + + This program 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 this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/kicad_plugins/README.md b/kicad_plugins/README.md new file mode 100644 index 00000000..7c23484c --- /dev/null +++ b/kicad_plugins/README.md @@ -0,0 +1,81 @@ +# RF-Tools for KiCAD +**compatibility: KiCAD 5.1.x** + +**

Rounder tools for tracks

** + +(to be copied on [KiCAD plugins dir](https://kicad-source-mirror.readthedocs.io/en/latest/Documentation/development/pcbnew-plugins/#typical-plugin-structure-ppi_pi_struct)) + +* Rounder for tracks (*Action Plugin*) +* Solder Mask Expander (*Action Plugin*) +* Track Length (*Action Plugin*) +* Via Fence Generator (*Action Plugin*) [pyclipper required] +* Trace Clearance Generator + +
+ +[![Tracks Rounder](resources/tracks-rounder-preview.png?raw=true "Tracks Rounder")](resources/tracks-rounder.gif?raw=true "Tracks Rounder") + +
+ +[![Solder Mask Expander](resources/solder-mask-expander-preview.png?raw=true "Solder Mask Expander")](resources/solder-mask-expander.gif?raw=true "Solder Mask Expander") + +
+ +[![Track Lenght](resources/track-length-preview.png?raw=true "Track Lenght")](resources/track-length.png?raw=true "Track Lenght") + +
+ +[![Via Fence Generator](resources/via-fencing-preview.png?raw=true "Via Fence Generator")](resources/via-fencing.png?raw=true "Via Fence Generator") + +
+ +Trace Clearance Generator: + +Generate a copper pour keepout for a selected trace. + +![Trace Clearance Generator](resources/trace-clearance.png?raw=true "trace clearance") + + +
+
+

Footprint Wizards:

+ +(to be copied on [KiCAD plugins dir](https://kicad-source-mirror.readthedocs.io/en/latest/Documentation/development/pcbnew-plugins/#typical-plugin-structure-ppi_pi_struct)) + +* microwave RF Arc footprint wizard +* microwave RF Mitered footprint wizard +* microwave RF Taper footprint wizard + + +[![microwave RF Arc](resources/uwave-Arc-footprint-preview.png?raw=true "microwave RF Arc")](resources/uwave-Arc-footprint.gif?raw=true "microwave RF Arc") + +[![microwave RF Mitered](resources/uwave-Mitered-footprint-preview.png?raw=true "microwave RF Mitered")](resources/uwave-Mitered-footprint.gif?raw=true "microwave RF Mitered") + +[![microwave RF Taper](resources/uwave-Tamper-footprint-preview.png?raw=true "microwave RF Taper")](resources/uwave-Tamper-footprint.gif?raw=true "microwave RF Taper") + +Simply launch the fotprint wizard and select the uwave tool: + +![microwave RF Wizards](resources/uw-footprint-wizards.png?raw=true "microwave RF Wizards") + +
+
+

Siblings/suggested plugins:

+
+ +[Via Stitching Generator](https://github.com/jsreynaud/kicad-action-scripts) + +
+ +![Via Stitching Generator](resources/extras/stitching-vias-help.png?raw=true "via stitching") + +
+
+ +[Via Teardrops Generator](https://github.com/NilujePerchut/kicad_scripts) + +
+ +![Via Teardrops Generator](resources/extras/teardrops-help.png?raw=true "teardrops") + + + diff --git a/kicad_plugins/__init__.py b/kicad_plugins/__init__.py new file mode 100644 index 00000000..0226e8ca --- /dev/null +++ b/kicad_plugins/__init__.py @@ -0,0 +1,14 @@ +# pcbnew loads this folder as a package using import +# thus __init__.py (this file) is executed +# We import the plugin class here and register it to pcbnew + +from . import rf_tools_wizards + +from . import round_tracks + +from . import trace_solder_expander +from . import tracks_length + +from . import via_fence_generator + +from . import trace_clearance diff --git a/kicad_plugins/resources/extras/stitching-vias-help.png b/kicad_plugins/resources/extras/stitching-vias-help.png new file mode 100644 index 00000000..b307d2d9 Binary files /dev/null and b/kicad_plugins/resources/extras/stitching-vias-help.png differ diff --git a/kicad_plugins/resources/extras/stitching-vias-help.svg b/kicad_plugins/resources/extras/stitching-vias-help.svg new file mode 100644 index 00000000..5aa37a88 --- /dev/null +++ b/kicad_plugins/resources/extras/stitching-vias-help.svg @@ -0,0 +1,252 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d + + diff --git a/kicad_plugins/resources/extras/stitching-vias.png b/kicad_plugins/resources/extras/stitching-vias.png new file mode 100644 index 00000000..22fba15c Binary files /dev/null and b/kicad_plugins/resources/extras/stitching-vias.png differ diff --git a/kicad_plugins/resources/extras/stitching-vias.svg b/kicad_plugins/resources/extras/stitching-vias.svg new file mode 100644 index 00000000..e00528b3 --- /dev/null +++ b/kicad_plugins/resources/extras/stitching-vias.svg @@ -0,0 +1,155 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kicad_plugins/resources/extras/teardrops-help.png b/kicad_plugins/resources/extras/teardrops-help.png new file mode 100644 index 00000000..bb089de4 Binary files /dev/null and b/kicad_plugins/resources/extras/teardrops-help.png differ diff --git a/kicad_plugins/resources/extras/teardrops-help.svg b/kicad_plugins/resources/extras/teardrops-help.svg new file mode 100644 index 00000000..a8a86d37 --- /dev/null +++ b/kicad_plugins/resources/extras/teardrops-help.svg @@ -0,0 +1,219 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + h% + v% + diff --git a/kicad_plugins/resources/extras/teardrops.png b/kicad_plugins/resources/extras/teardrops.png new file mode 100644 index 00000000..d808a367 Binary files /dev/null and b/kicad_plugins/resources/extras/teardrops.png differ diff --git a/kicad_plugins/resources/solder-mask-expander-preview.png b/kicad_plugins/resources/solder-mask-expander-preview.png new file mode 100644 index 00000000..cb873389 Binary files /dev/null and b/kicad_plugins/resources/solder-mask-expander-preview.png differ diff --git a/kicad_plugins/resources/solder-mask-expander.gif b/kicad_plugins/resources/solder-mask-expander.gif new file mode 100644 index 00000000..01a87e2f Binary files /dev/null and b/kicad_plugins/resources/solder-mask-expander.gif differ diff --git a/kicad_plugins/resources/trace-clearance.png b/kicad_plugins/resources/trace-clearance.png new file mode 100644 index 00000000..352681ec Binary files /dev/null and b/kicad_plugins/resources/trace-clearance.png differ diff --git a/kicad_plugins/resources/track-length-preview.png b/kicad_plugins/resources/track-length-preview.png new file mode 100644 index 00000000..296a8084 Binary files /dev/null and b/kicad_plugins/resources/track-length-preview.png differ diff --git a/kicad_plugins/resources/track-length.png b/kicad_plugins/resources/track-length.png new file mode 100644 index 00000000..ba60125e Binary files /dev/null and b/kicad_plugins/resources/track-length.png differ diff --git a/kicad_plugins/resources/tracks-rounder-preview.png b/kicad_plugins/resources/tracks-rounder-preview.png new file mode 100644 index 00000000..c593da82 Binary files /dev/null and b/kicad_plugins/resources/tracks-rounder-preview.png differ diff --git a/kicad_plugins/resources/tracks-rounder.gif b/kicad_plugins/resources/tracks-rounder.gif new file mode 100644 index 00000000..e60e3aa2 Binary files /dev/null and b/kicad_plugins/resources/tracks-rounder.gif differ diff --git a/kicad_plugins/resources/uw-footprint-wizards.png b/kicad_plugins/resources/uw-footprint-wizards.png new file mode 100644 index 00000000..0f669034 Binary files /dev/null and b/kicad_plugins/resources/uw-footprint-wizards.png differ diff --git a/kicad_plugins/resources/uwave-Arc-footprint-preview.png b/kicad_plugins/resources/uwave-Arc-footprint-preview.png new file mode 100644 index 00000000..82e6d515 Binary files /dev/null and b/kicad_plugins/resources/uwave-Arc-footprint-preview.png differ diff --git a/kicad_plugins/resources/uwave-Arc-footprint.gif b/kicad_plugins/resources/uwave-Arc-footprint.gif new file mode 100644 index 00000000..806dd62f Binary files /dev/null and b/kicad_plugins/resources/uwave-Arc-footprint.gif differ diff --git a/kicad_plugins/resources/uwave-Arc-footprint.mp4 b/kicad_plugins/resources/uwave-Arc-footprint.mp4 new file mode 100644 index 00000000..773eb191 Binary files /dev/null and b/kicad_plugins/resources/uwave-Arc-footprint.mp4 differ diff --git a/kicad_plugins/resources/uwave-Arc-footprint.png b/kicad_plugins/resources/uwave-Arc-footprint.png new file mode 100644 index 00000000..6438274f Binary files /dev/null and b/kicad_plugins/resources/uwave-Arc-footprint.png differ diff --git a/kicad_plugins/resources/uwave-Mitered-footprint-preview.png b/kicad_plugins/resources/uwave-Mitered-footprint-preview.png new file mode 100644 index 00000000..f1d7df58 Binary files /dev/null and b/kicad_plugins/resources/uwave-Mitered-footprint-preview.png differ diff --git a/kicad_plugins/resources/uwave-Mitered-footprint.gif b/kicad_plugins/resources/uwave-Mitered-footprint.gif new file mode 100644 index 00000000..f633bf06 Binary files /dev/null and b/kicad_plugins/resources/uwave-Mitered-footprint.gif differ diff --git a/kicad_plugins/resources/uwave-Mitered-footprint.mp4 b/kicad_plugins/resources/uwave-Mitered-footprint.mp4 new file mode 100644 index 00000000..b7662b4a Binary files /dev/null and b/kicad_plugins/resources/uwave-Mitered-footprint.mp4 differ diff --git a/kicad_plugins/resources/uwave-Mitered-footprint.png b/kicad_plugins/resources/uwave-Mitered-footprint.png new file mode 100644 index 00000000..8a08ba84 Binary files /dev/null and b/kicad_plugins/resources/uwave-Mitered-footprint.png differ diff --git a/kicad_plugins/resources/uwave-Tamper-footprint-preview.png b/kicad_plugins/resources/uwave-Tamper-footprint-preview.png new file mode 100644 index 00000000..ca6744a5 Binary files /dev/null and b/kicad_plugins/resources/uwave-Tamper-footprint-preview.png differ diff --git a/kicad_plugins/resources/uwave-Tamper-footprint.gif b/kicad_plugins/resources/uwave-Tamper-footprint.gif new file mode 100644 index 00000000..8534e6e3 Binary files /dev/null and b/kicad_plugins/resources/uwave-Tamper-footprint.gif differ diff --git a/kicad_plugins/resources/uwave-Tamper-footprint.mp4 b/kicad_plugins/resources/uwave-Tamper-footprint.mp4 new file mode 100644 index 00000000..7e692aa0 Binary files /dev/null and b/kicad_plugins/resources/uwave-Tamper-footprint.mp4 differ diff --git a/kicad_plugins/resources/uwave-Tamper-footprint.png b/kicad_plugins/resources/uwave-Tamper-footprint.png new file mode 100644 index 00000000..e0a91cdd Binary files /dev/null and b/kicad_plugins/resources/uwave-Tamper-footprint.png differ diff --git a/kicad_plugins/resources/via-fencing-preview.png b/kicad_plugins/resources/via-fencing-preview.png new file mode 100644 index 00000000..bafd0a1f Binary files /dev/null and b/kicad_plugins/resources/via-fencing-preview.png differ diff --git a/kicad_plugins/resources/via-fencing.png b/kicad_plugins/resources/via-fencing.png new file mode 100644 index 00000000..62a9428e Binary files /dev/null and b/kicad_plugins/resources/via-fencing.png differ diff --git a/kicad_plugins/rf_tools_wizards/__init__.py b/kicad_plugins/rf_tools_wizards/__init__.py new file mode 100644 index 00000000..3a31f371 --- /dev/null +++ b/kicad_plugins/rf_tools_wizards/__init__.py @@ -0,0 +1,11 @@ +# pcbnew loads this folder as a package using import +# thus __init__.py (this file) is executed +# We import the plugin class here and register it to pcbnew + +from . import uwArcPrimitive_wizard +from . import uwMitered_wizard +from . import uwTaper_wizard + + + + diff --git a/kicad_plugins/rf_tools_wizards/uwArcPrimitive_wizard.py b/kicad_plugins/rf_tools_wizards/uwArcPrimitive_wizard.py new file mode 100644 index 00000000..85556cc7 --- /dev/null +++ b/kicad_plugins/rf_tools_wizards/uwArcPrimitive_wizard.py @@ -0,0 +1,193 @@ +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +# This python script wizard creates an arc track for microwave applications +# Author easyw +# taskkill -im pcbnew.exe /f & C:\KiCad-v5-nightly\bin\pcbnew + +from __future__ import division + +import math, cmath + +from pcbnew import * +import pcbnew +import FootprintWizardBase + + +class uwArcPrimitive_wizard(FootprintWizardBase.FootprintWizard): + + def GetName(self): + return "uW Arc Pad" + + def GetDescription(self): + return "uW Arc Pad Footprint Wizard" + + def GenerateParameterList(self): + + self.AddParam("Corner", "width", self.uMM, 1.319) + self.AddParam("Corner", "radius", self.uMM, 5.0, min_value=0, designator='r', hint="Arc radius") + self.AddParam("Corner", "angle", self.uDegrees, 90, designator='a') + self.AddParam("Corner", "square_end", self.uBool, False) + self.AddParam("Corner", "solder_clearance", self.uMM, 0.0) + self.AddParam("Corner", "linear", self.uBool, False) + + def CheckParameters(self): + + pads = self.parameters['Corner'] + + + def GetValue(self): + name = "{0:.2f}_{1:0.2f}_{2:.0f}".format(pcbnew.ToMM(self.parameters["Corner"]["width"]),pcbnew.ToMM(self.parameters["Corner"]["radius"]),(self.parameters["Corner"]["angle"])) + if not self.parameters["Corner"]["linear"]: + pref = "uwArc" + else: + pref = "uwLine" + if self.parameters["Corner"]["square_end"]: + pref += "R" + return pref + "%s" % name + + def GetReferencePrefix(self): + if not self.parameters["Corner"]["linear"]: + pref = "uwA" + else: + pref = "uwL" + #if self.parameters["Corner"]["rectangle"]: + # pref += "R" + return pref + "***" + + # build a custom pad + def smdCustomArcPad(self, module, size, pos, rad, name, angle_D, layer, ln, solder_clearance): + if hasattr(pcbnew, 'D_PAD'): + pad = D_PAD(module) + else: + pad = PAD(module) + ## NB pads must be the same size and have the same center + pad.SetSize(size) + #pad.SetSize(pcbnew.wxSize(size[0]/5,size[1]/5)) + pad.SetShape(PAD_SHAPE_CUSTOM) #PAD_RECT) + pad.SetAttribute(PAD_ATTRIB_SMD) #PAD_SMD) + #pad.SetDrillSize (0.) + #Set only the copper layer without mask + #since nothing is mounted on these pads + pad.SetPos0(pos) + pad.SetPosition(pos) + pad.SetPadName(name) + #pad.Rotate(pos, angle) + pad.SetAnchorPadShape(PAD_SHAPE_CIRCLE) #PAD_SHAPE_RECT) + if solder_clearance > 0: + pad.SetLocalSolderMaskMargin(solder_clearance) + pad.SetLayerSet(pad.ConnSMDMask()) + else: + pad.SetLayerSet( LSET(layer) ) + + if not ln: + pad.AddPrimitive(pcbnew.wxPoint(0,rad), pcbnew.wxPoint(0,0), int(angle_D*10), (size[0])) + else: + pad.AddPrimitive(pcbnew.wxPoint(0,0), pcbnew.wxPoint(rad,0), (size[0])) + return pad + + def smdPad(self,module,size,pos,name,ptype,angle_D,layer,solder_clearance,offs=None): + if hasattr(pcbnew, 'D_PAD'): + pad = D_PAD(module) + else: + pad = PAD(module) + pad.SetSize(size) + pad.SetShape(ptype) #PAD_SHAPE_RECT PAD_SHAPE_OVAL PAD_SHAPE_TRAPEZOID PAD_SHAPE_CIRCLE + # PAD_ATTRIB_CONN PAD_ATTRIB_SMD + pad.SetAttribute(PAD_ATTRIB_SMD) + if solder_clearance > 0: + pad.SetLocalSolderMaskMargin(solder_clearance) + pad.SetLayerSet(pad.ConnSMDMask()) + else: + pad.SetLayerSet( LSET(layer) ) + #pad.SetDrillSize (0.) + #pad.SetLayerSet(pad.ConnSMDMask()) + pad.SetPos0(pos) + pad.SetPosition(pos) + #pad.SetOrientationDegrees(90-angle_D/10) + pad.SetOrientationDegrees(angle_D) + if offs is not None: + pad.SetOffset(offs) + pad.SetName(name) + return pad + + def BuildThisFootprint(self): + + pads = self.parameters['Corner'] + + radius = pads['radius'] #outline['diameter'] / 2 + width = pads['width'] + sold_clear = pads['solder_clearance'] + line = pads['linear'] + + angle_deg = float(pads["angle"]) #*10) + angle = math.radians(angle_deg) #/10) #To radians + sign = 1. + if angle < 0: + sign = -1. + + pos = pcbnew.wxPoint(0,0) + offset1 = pcbnew.wxPoint(-sign*width/2,0) + offset2 = pcbnew.wxPoint(0,0) + module = self.module + size_pad = pcbnew.wxSize(width, width) + #size_pad = pcbnew.wxSize(width/5, width/5) + module.Add(self.smdCustomArcPad(module, size_pad, pcbnew.wxPoint(0,0), radius, "1", (angle_deg), F_Cu, line, sold_clear)) + size_pad = pcbnew.wxSize(width, width) + end_coord = (radius) * cmath.exp(math.radians(angle_deg-90)*1j) + if pads['square_end'] or angle_deg == 0 or radius == 0: + if not line: + ## NB pads must be the same size and have the same center + module.Add(self.smdPad(module, size_pad, pcbnew.wxPoint(0,0), "1", PAD_SHAPE_RECT,0,F_Cu,sold_clear,offset1)) + else: + module.Add(self.smdPad(module, size_pad, pcbnew.wxPoint(0,0), "1", PAD_SHAPE_RECT,0,F_Cu,sold_clear)) + if not line: + #pos = pcbnew.wxPoint(end_coord.real+(sign*width/2)*math.cos(angle),end_coord.imag+(sign*width/2)*math.sin(angle)+radius) + pos = pcbnew.wxPoint(end_coord.real,end_coord.imag+radius) + module.Add(self.smdPad(module, size_pad, pos, "1", PAD_SHAPE_RECT,90-angle_deg,F_Cu,sold_clear,wxPoint(0,(sign*width/2)))) + #*math.sin(math.pi/2-angle),(sign*width/2)*math.cos(math.pi/2-angle)))) + else: + pos = pcbnew.wxPoint(radius,0) #+width/2,0) + module.Add(self.smdPad(module, size_pad, pos, "1", PAD_SHAPE_RECT,0,F_Cu,sold_clear)) + else: + ## NB pads must be the same size and have the same center + #size_pad = pcbnew.wxSize(width/5, width/5) + size_pad = pcbnew.wxSize(width, width) + if not line: + pos = pcbnew.wxPoint(end_coord.real,end_coord.imag+radius) + else: + pos = pcbnew.wxPoint(radius,0) + module.Add(self.smdPad(module, size_pad, pos, "1", PAD_SHAPE_CIRCLE,0,F_Cu,sold_clear)) + + # Text size + text_size = self.GetTextSize() # IPC nominal + thickness = self.GetTextThickness() + textposy = self.draw.GetLineThickness()/2 + self.GetTextSize()/2 + thickness #+ outline['margin'] + self.draw.Reference( 0, -textposy-width, text_size ) + if not line: + self.draw.Value( 0, radius+textposy+width, text_size ) + else: + self.draw.Value( 0, textposy+width, text_size ) + # set SMD attribute + # set SMD attribute + if hasattr(pcbnew, 'MOD_VIRTUAL'): + module.SetAttributes(pcbnew.MOD_VIRTUAL) + else: + module.SetAttributes(pcbnew.FP_EXCLUDE_FROM_BOM | pcbnew.FP_EXCLUDE_FROM_POS_FILES) + __version__ = 1.7 + self.buildmessages += ("version: {:.1f}".format(__version__)) + +uwArcPrimitive_wizard().register() diff --git a/kicad_plugins/rf_tools_wizards/uwMitered_wizard.py b/kicad_plugins/rf_tools_wizards/uwMitered_wizard.py new file mode 100644 index 00000000..eb2e70f2 --- /dev/null +++ b/kicad_plugins/rf_tools_wizards/uwMitered_wizard.py @@ -0,0 +1,352 @@ +# This python script wizard creates a mitered bend for microwave applications +# https://lists.launchpad.net/kicad-developers/msg17996.html +# Author Henrik Forsten & easyw +# improved pads using Primitive pads, single net node + +from __future__ import division +import FootprintWizardBase + +import pcbnew +from pcbnew import * +import math + +class UWMiterFootprintWizard(FootprintWizardBase.FootprintWizard): + def GetName(self): + return "uW Mitered Bend" + + def GetDescription(self): + return "Mitered Bend Footprint Wizard" + + def GenerateParameterList(self): + self.AddParam("Corner", "width", self.uMM, 1.31968) + self.AddParam("Corner", "height", self.uMM, 1.57) + self.AddParam("Corner", "*angle", self.uDegrees, 90) + self.AddParam("Corner", "solder_clearance", self.uMM, 0.0) + +# class UWMiterFootprintWizard(FootprintWizardBase.FootprintWizard): +# def __init__(self): +# FootprintWizardBase.FootprintWizard.__init__(self) +# self.name = "uW Mitered Bend" +# self.description = "Mitered Bend Footprint Wizard" +# self.parameters = { +# "Corner":{ +# "width": FromMM(0.34), +# "height": FromMM(0.17), +# "*angle": 90, +# } +# } +# +# self.ClearErrors() + + # build a rectangular pad + def smdRectPad(self, module, size, pos, name, angle, layer, solder_clearance): + if hasattr(pcbnew, 'D_PAD'): + pad = D_PAD(module) + else: + pad = PAD(module) + pad.SetSize(size) + pad.SetShape(PAD_SHAPE_RECT) #PAD_RECT) + pad.SetAttribute(PAD_ATTRIB_SMD) #PAD_SMD) + #Set only the copper layer without mask + #since nothing is mounted on these pads + pad.SetLayerSet( LSET(F_Cu) ) + pad.SetPos0(pos) + pad.SetPosition(pos) + pad.SetPadName(name) + pad.Rotate(pos, angle) + if solder_clearance > 0: + pad.SetLocalSolderMaskMargin(solder_clearance) + pad.SetLayerSet(pad.ConnSMDMask()) + else: + pad.SetLayerSet( LSET(layer) ) + #Set clearance to small value, because + #pads can be very close together. + #If distance is smaller than clearance + #DRC doesn't allow routing the pads + pad.SetLocalClearance(1) + return pad + + # build a custom pad + def smdCustomPolyPad(self, module, size, pos, name, vpoints, layer, solder_clearance): + if hasattr(pcbnew, 'D_PAD'): + pad = D_PAD(module) + else: + pad = PAD(module) + ## NB pads must be the same size and have the same center + pad.SetSize(size) + #pad.SetSize(pcbnew.wxSize(size[0]/5,size[1]/5)) + pad.SetShape(PAD_SHAPE_CUSTOM) #PAD_RECT) + pad.SetAttribute(PAD_ATTRIB_SMD) #PAD_SMD) + #pad.SetDrillSize (0.) + #Set only the copper layer without mask + #since nothing is mounted on these pads + #pad.SetPos0(wxPoint(0,0)) #pos) + #pad.SetPosition(wxPoint(0,0)) #pos) + pad.SetPos0(pos) + pad.SetPosition(pos) + #pad.SetOffset(pos) + pad.SetPadName(name) + #pad.Rotate(pos, angle) + pad.SetAnchorPadShape(PAD_SHAPE_RECT) #PAD_SHAPE_CIRCLE) #PAD_SHAPE_RECT) + if solder_clearance > 0: + pad.SetLocalSolderMaskMargin(solder_clearance) + pad.SetLayerSet(pad.ConnSMDMask()) + else: + pad.SetLayerSet( LSET(layer) ) + + if hasattr(pcbnew, 'D_PAD'): + pad.AddPrimitive(vpoints,0) # (size[0])) + else: + pad.AddPrimitivePoly(vpoints, 0, True) # (size[0])) + + return pad + + def Polygon(self, points, layer): + """ + Draw a polygon through specified points + """ + import pcbnew + + polygon = pcbnew.EDGE_MODULE(self.module) + polygon.SetWidth(0) #Disables outline + + polygon.SetLayer(layer) + polygon.SetShape(pcbnew.S_POLYGON) + + polygon.SetPolyPoints(points) + + self.module.Add(polygon) + + + # This method checks the parameters provided to wizard and set errors + def CheckParameters(self): + p = self.parameters + width = p["Corner"]["width"] + height = p["Corner"]["height"] + angle = p["Corner"]["*angle"] + + errors = [] + if (width<0): + errors.append("Width has invalid value") + if width/height < 0.25: + errors.append("Too small width to height ratio") + if angle > 90: + errors.append("Too large angle") + if angle < 0: + errors.append("Angle must be positive") + errors = ', '.join(errors) + print (errors) + return errors == "" + + def bilinear_interpolation(self, x, y, points): + '''http://stackoverflow.com/questions/8661537/how-to-perform-bilinear-interpolation-in-python + Interpolate (x,y) from values associated with four points. + + The four points are a list of four triplets: (x, y, value). + The four points can be in any order. They should form a rectangle. + + >>> bilinear_interpolation(12, 5.5, + ... [(10, 4, 100), + ... (20, 4, 200), + ... (10, 6, 150), + ... (20, 6, 300)]) + 165.0 + + ''' + # See formula at: http://en.wikipedia.org/wiki/Bilinear_interpolation + + points = sorted(points) # order points by x, then by y + (x1, y1, q11), (_x1, y2, q12), (x2, _y1, q21), (_x2, _y2, q22) = points + + return (q11 * (x2 - x) * (y2 - y) + + q21 * (x - x1) * (y2 - y) + + q12 * (x2 - x) * (y - y1) + + q22 * (x - x1) * (y - y1) + ) / ((x2 - x1) * (y2 - y1) + 0.0) + + def OptimalMiter(self, w, h, angle): + """Calculate optimal miter by interpolating from table. + https://awrcorp.com/download/faq/english/docs/Elements/MBENDA.htm + """ + wh = w/h + whs = [0.5, 1.0, 2.0] + angles = [0, 30, 60, 90, 120] + table = [ + [0, 12, 45, 75, 98], + [0, 19, 41, 63, 92], + [0, 7, 31, 56, 79] + ] + for i, x in enumerate(whs): + if x > wh: + break + for j, y in enumerate(angles): + if y > angle: + break + i = min(i-1,1) + j = min(j-1,3) + px = lambda ii,jj: (whs[ii],angles[jj],table[ii][jj]) + x1 = px(i,j) + x2 = px(i+1,j) + y1 = px(i,j+1) + y2 = px(i+1,j+1) + return self.bilinear_interpolation(wh, angle, [x1,x2,y1,y2])/100.0 + + # build the footprint from parameters + #def BuildThisFootprint(self): + def BuildFootprint(self): + + if hasattr(pcbnew, 'MODULE'): + module = MODULE(None) # create a new module + else: + module = FOOTPRINT(None) # create a new module + #module = self.module + self.module = module + self.buildmessages = "" + + if not self.CheckParameters(): + return + + p = self.parameters + width = p["Corner"]["width"] + height = p["Corner"]["height"] + angle_deg = float(p["Corner"]["*angle"]) + angle = angle_deg*0.0174532925 #To radians + sold_clear = p["Corner"]['solder_clearance'] + #reference and value + #text_size = self.GetTextSize() # IPC nominal + + textposy = width + FromMM(1) + size_text = wxSize( FromMM( 0.6), FromMM( 0.5) ) + + module.name = "'uwm_{0:.2f}_{1:0.2f}_{2:.0f}'".format(ToMM(width),ToMM(height),angle_deg) + + #module.SetReference("uwm_{0:.2f}_{1:0.2f}_{2:.0f}".format(ToMM(width),ToMM(height),angle_deg)) + module.SetReference("uwM***") # give it a default value + module.Reference().SetPos0(wxPoint(0, textposy)) + module.Reference().SetPosition(module.Reference().GetPos0()) + module.Reference().SetTextSize( size_text ) + if hasattr(module.Reference(), 'SetThickness'): + module.Reference().SetThickness(FromMM(0.125)) + else: + module.Reference().SetTextThickness(FromMM(0.125)) + module.Reference().SetVisible(True) + + textposy = textposy + FromMM(1) + #module.SetValue("Val***") # give it a default value + module.SetValue("uwM_{0:.2f}_{1:0.2f}_{2:.0f}".format(ToMM(width),ToMM(height),angle_deg)) + module.Value().SetPos0( wxPoint(0, textposy) ) + module.Value().SetPosition(module.Value().GetPos0()) + module.Value().SetTextSize( size_text ) + module.Value().SetVisible(False) #0) + + # fpid = FPID(self.module.GetReference()) #the name in library + # module.SetFPID( fpid ) + + #Calculate the miter + w = width + + #Width of the corner from edge of the corner to inside corner + corner_width = ToMM(w)/math.cos(angle/2) + + #Get proportion of width to cut + cut = self.OptimalMiter(width, height, angle_deg) + cut_pc = cut + print ("Cut: {0:.2f}%".format(cut*100)) + + #Distance from uncut outside corner point to point 7 + cut = FromMM(cut*corner_width/math.cos((math.pi-angle)/2)) + + #Distance between points 2 and 3 and points 3 and 4 + #Minimum of w/2 to satisfy DRC, otherwise pads are too close + #and track connected to other pad overlaps the other one. + #Rounded trace end can also stick out of the cut area + #if a is too small. + a = max(cut-width*math.tan(angle/2),w/2) + + #Distance between points 3 and 4 + x34 = a*math.sin(angle) + y34 = a*math.cos(angle) + #Distance between points 4 and 5 + x45 = width*math.cos(angle) + y45 = width*math.sin(angle) + + # 1 2 + #8 +--+ + # | |3 + #7 \ --+ 4 + # \ | + # \--+ 5 + # 6 + + # maui extension of polygon + #points = [ + # (0,0-w/2), + # (w,0-w/2), + # (w,a), + # (w+x34+w/2*math.sin(angle),a+y34+w/2*math.cos(angle)), + # (w+x34-x45+w/2*math.sin(angle),a+y34+y45+w/2*math.cos(angle)), + # (cut*math.sin(angle),a+width*math.tan(angle/2)+cut*math.cos(angle)), + # (0,a+width*math.tan(angle/2)-cut), + # (0,0-w/2)] + points = [ + (0-w/2,0-w/2+w/2), + (w-w/2,0-w/2+w/2), + (w-w/2,a+w/2), + (w+x34+w/2*math.sin(angle)-w/2,a+y34+w/2*math.cos(angle)+w/2), + (w+x34-x45+w/2*math.sin(angle)-w/2,a+y34+y45+w/2*math.cos(angle)+w/2), + (cut*math.sin(angle)-w/2,a+width*math.tan(angle/2)+cut*math.cos(angle)+w/2), + (0-w/2,a+width*math.tan(angle/2)-cut+w/2), + (0-w/2,0-w/2+w/2)] + + #Last two points can be equal + if points[-2] == points[-1]: + points = points[:-1] + + points = [wxPoint(*point) for point in points] + vpoints = wxPoint_Vector(points) + #self.Polygon(points, F_Cu) + + #Create pads + pad_l = width/2 #10 allowing big track to join the fp + size_pad = wxSize(width,pad_l) + + #module.Add(self.smdRectPad(module, size_pad, wxPoint(width/2,-pad_l/2), "1", 0)) + layer = F_Cu; # sold_clear = 0 + module.Add(self.smdCustomPolyPad(module, size_pad, wxPoint(width/2,-pad_l/2), "1", vpoints, layer,sold_clear)) + # smdCustomPolyPad(self, module, size, pos, name, points, layer, solder_clearance): + size_pad = wxSize(pad_l,width) + + #Halfway between points 4 and 5 + posx = ((w+x34) + (w+x34-x45))/2 + posy = ((a+y34) + (a+y34+y45))/2 + + #Position pad so that pad edge touches polygon edge + posx += (pad_l/2)*math.sin(angle) + posy += (pad_l/2)*math.cos(angle)+w/4 + size_pad = wxSize(pad_l, width) + #solder clearance added only to polygon + module.Add(self.smdRectPad(module, size_pad, wxPoint(posx,posy), "1", (angle_deg-90)*10,layer,0.0)) + # moving anchor to center of first pad + module.MoveAnchorPosition(wxPoint(-width/2,pad_l/2)) + # set SMD attribute + # set SMD attribute + if hasattr(pcbnew, 'MOD_VIRTUAL'): + module.SetAttributes(pcbnew.MOD_VIRTUAL) + else: + module.SetAttributes(pcbnew.FP_EXCLUDE_FROM_BOM | pcbnew.FP_EXCLUDE_FROM_POS_FILES) + self.buildmessages = ( + "Building new {name} footprint with the following parameters:\n\n" + .format(name=module.name)) + self.buildmessages += ("Track Width: {0:.4f}mm\n".format(ToMM(width))) + self.buildmessages += ("PCB Height: {0:.4f}mm\n".format(ToMM(height))) + self.buildmessages += ("Angle: {:.1f}deg\n\n".format(angle_deg)) + self.buildmessages += ("Cut: {0:.2f}%\n".format(cut_pc*100)) + __version__ = 1.6 + self.buildmessages += ("version: {:.1f}".format(__version__)) + + +# create our footprint wizard +uwmiter_wizard = UWMiterFootprintWizard() + +# register it into pcbnew +uwmiter_wizard.register() diff --git a/kicad_plugins/rf_tools_wizards/uwTaper_wizard.py b/kicad_plugins/rf_tools_wizards/uwTaper_wizard.py new file mode 100644 index 00000000..ba679976 --- /dev/null +++ b/kicad_plugins/rf_tools_wizards/uwTaper_wizard.py @@ -0,0 +1,210 @@ +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +# This python script wizard creates an arc track for microwave applications +# Author easyw +# taskkill -im pcbnew.exe /f & C:\KiCad-v5-nightly\bin\pcbnew + +from __future__ import division + +import math, cmath + +from pcbnew import * +import pcbnew +import FootprintWizardBase + + +class uwTaper_wizard(FootprintWizardBase.FootprintWizard): + + def GetName(self): + return "uW Taper Pad" + + def GetDescription(self): + return "uW Taper Pad Footprint Wizard" + + def GenerateParameterList(self): + + self.AddParam("Taper", "P1 width", self.uMM, 0.5, min_value=0, hint="Pad 1 width") + self.AddParam("Taper", "P1 height", self.uMM, 0.5, min_value=0, hint="Pad 1 height") + self.AddParam("Taper", "P2 width", self.uMM, 1.0, min_value=0, hint="Pad 2 width") + self.AddParam("Taper", "P2 height", self.uMM, 1.0, min_value=0, hint="Pad 2 height") + self.AddParam("Taper", "P2 vert offset", self.uMM, 0.0, hint="Pad 2 vertical offset") + self.AddParam("Taper", "length", self.uMM, 3.0, min_value=0, hint="length") + self.AddParam("Taper", "solder_clearance", self.uMM, 0.0, min_value=0, hint="Solder Clearance") + + def CheckParameters(self): + + pads = self.parameters['Taper'] + + + def GetValue(self): + name = "{0:.2f}_{1:0.2f}_{2:.2f}_{3:.2f}_{4:.2f}".format(pcbnew.ToMM(self.parameters["Taper"]["P1 width"]),\ + pcbnew.ToMM(self.parameters["Taper"]["P1 height"]),pcbnew.ToMM(self.parameters["Taper"]["P2 width"]),\ + pcbnew.ToMM(self.parameters["Taper"]["P2 height"]),pcbnew.ToMM(self.parameters["Taper"]["length"])) + return "uwT" + "%s" % name + + def GetReferencePrefix(self): + return "uwT" + "***" + + # build a custom pad + def smdCustomPolyPad(self, module, size, pos, name, vpoints, layer, solder_clearance): + if hasattr(pcbnew, 'D_PAD'): + pad = D_PAD(module) + else: + pad = PAD(module) + #pad = PAD(module) + ## NB pads must be the same size and have the same center + pad.SetSize(size) + #pad.SetSize(pcbnew.wxSize(size[0]/5,size[1]/5)) + pad.SetShape(PAD_SHAPE_CUSTOM) #PAD_RECT) + pad.SetAttribute(PAD_ATTRIB_SMD) #PAD_SMD) + #pad.SetDrillSize (0.) + #Set only the copper layer without mask + #since nothing is mounted on these pads + #pad.SetPos0(wxPoint(0,0)) #pos) + #pad.SetPosition(wxPoint(0,0)) #pos) + pad.SetPos0(pos) + pad.SetPosition(pos) + #pad.SetOffset(pos) + pad.SetPadName(name) + #pad.Rotate(pos, angle) + pad.SetAnchorPadShape(PAD_SHAPE_RECT) #PAD_SHAPE_CIRCLE) #PAD_SHAPE_RECT) + if solder_clearance > 0: + pad.SetLocalSolderMaskMargin(solder_clearance) + pad.SetLayerSet(pad.ConnSMDMask()) + else: + pad.SetLayerSet( LSET(layer) ) + + if hasattr(pcbnew, 'D_PAD'): + pad.AddPrimitive(vpoints,0) # (size[0])) + else: + pad.AddPrimitivePoly(vpoints, 0, True) # (size[0])) + return pad + + def smdPad(self,module,size,pos,name,ptype,angle_D,layer,solder_clearance,offs=None): + if hasattr(pcbnew, 'D_PAD'): + pad = D_PAD(module) + else: + pad = PAD(module) + pad.SetSize(size) + pad.SetShape(ptype) #PAD_SHAPE_RECT PAD_SHAPE_OVAL PAD_SHAPE_TRAPEZOID PAD_SHAPE_CIRCLE + # PAD_ATTRIB_CONN PAD_ATTRIB_SMD + pad.SetAttribute(PAD_ATTRIB_SMD) + if solder_clearance > 0: + pad.SetLocalSolderMaskMargin(solder_clearance) + pad.SetLayerSet(pad.ConnSMDMask()) + else: + pad.SetLayerSet( LSET(layer) ) + #pad.SetDrillSize (0.) + #pad.SetLayerSet(pad.ConnSMDMask()) + pad.SetPos0(pos) + pad.SetPosition(pos) + #pad.SetOrientationDegrees(90-angle_D/10) + pad.SetOrientationDegrees(angle_D) + if offs is not None: + pad.SetOffset(offs) + pad.SetName(name) + return pad + + def Polygon(self, points, layer): + """ + Draw a polygon through specified points + """ + import pcbnew + + polygon = pcbnew.EDGE_MODULE(self.module) + polygon.SetWidth(0) #Disables outline + + polygon.SetLayer(layer) + polygon.SetShape(pcbnew.S_POLYGON) + + polygon.SetPolyPoints(points) + + self.module.Add(polygon) + + def BuildThisFootprint(self): + + pads = self.parameters['Taper'] + + width1 = pads['P1 width'] + width2 = pads['P2 width'] + height1 = pads['P1 height'] + height2 = pads['P2 height'] + length = pads['length'] + p2vof = pads['P2 vert offset'] + sold_clear = pads['solder_clearance'] + w1=width1;w2=width2; + h1=height1;h2=height2; + + pos = pcbnew.wxPoint(0,0) + offset1 = pcbnew.wxPoint(0,0) + #offset2 = pcbnew.wxPoint(length+w1/2,0) + offset2 = pcbnew.wxPoint(0,0) + module = self.module + # 1 2 3 4 + # +--+ + # / | + # / | + #9 +---+ | + # | + + | + #8 +---+ | + # \ | + # \ | + # +--+ + # 7 6 5 + points = [ + (-w1/2,-h1/2), + (w1/2,-h1/2), + (w1/2+length-w2/2,-h2/2-p2vof), + (w1/2+length+w2/2,-h2/2-p2vof), + (w1/2+length+w2/2,h2/2-p2vof), + (w1/2+length-w2/2,h2/2-p2vof), + (w1/2,h1/2), + (-w1/2,h1/2), + ] + #Last two points can be equal + if points[-2] == points[-1]: + points = points[:-1] + points = [wxPoint(*point) for point in points] + vpoints = wxPoint_Vector(points) + # self.Polygon(points, F_Cu) + + size_pad = pcbnew.wxSize(width1, height1) + #module.Add(self.smdPad(module, size_pad, pcbnew.wxPoint(0,0), "1", PAD_SHAPE_RECT,0,F_Cu,sold_clear,offset1)) + module.Add(self.smdCustomPolyPad(module, size_pad, wxPoint(0,0), "1", vpoints,F_Cu,sold_clear)) + + size_pad = pcbnew.wxSize(width2, height2) + #solder clearance added only to polygon + module.Add(self.smdPad(module, size_pad, pcbnew.wxPoint(length+w1/2,0-p2vof), "1", PAD_SHAPE_RECT,0,F_Cu,0.0,offset2)) + + # Text size + text_size = self.GetTextSize() # IPC nominal + thickness = self.GetTextThickness() + textposy = self.draw.GetLineThickness()/2 + self.GetTextSize()/2 + thickness #+ outline['margin'] + height = max(height1,height2) + self.draw.Reference( 0+length/2, -textposy-height/2, text_size ) + self.draw.Value( 0+length/2, textposy+height/2+text_size/2, text_size ) + # set SMD attribute + if hasattr(pcbnew, 'MOD_VIRTUAL'): + module.SetAttributes(pcbnew.MOD_VIRTUAL) + else: + module.SetAttributes(pcbnew.FP_EXCLUDE_FROM_BOM | pcbnew.FP_EXCLUDE_FROM_POS_FILES) + # module.SetAttributes(pcbnew.MOD_VIRTUAL) + # module.SetAttributes(pcbnew.FP_EXCLUDE_FROM_BOM | pcbnew.FP_EXCLUDE_FROM_POS_FILES) + __version__ = 1.5 + self.buildmessages += ("version: {:.1f}".format(__version__)) + +uwTaper_wizard().register() diff --git a/kicad_plugins/round_tracks/RoundTrackDlg.py b/kicad_plugins/round_tracks/RoundTrackDlg.py new file mode 100644 index 00000000..53b893ca --- /dev/null +++ b/kicad_plugins/round_tracks/RoundTrackDlg.py @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version Oct 26 2018) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + +########################################################################### +## Class RoundTrackDlg +########################################################################### + +class RoundTrackDlg ( wx.Dialog ): + + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Round Track parameters", pos = wx.DefaultPosition, size = wx.Size( 432,532 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) + + bSizer3 = wx.BoxSizer( wx.VERTICAL ) + + self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Select Two angled Tracks\n", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_comment.Wrap( -1 ) + + bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 ) + + bSizer31 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, u"Distance from Intersection (mm)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText3.Wrap( -1 ) + + bSizer31.Add( self.m_staticText3, 1, wx.ALL|wx.EXPAND, 5 ) + + self.m_distanceMM = wx.TextCtrl( self, wx.ID_ANY, u"5", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_distanceMM.SetMinSize( wx.Size( 1000,-1 ) ) + + bSizer31.Add( self.m_distanceMM, 1, wx.ALL|wx.EXPAND, 5 ) + + + bSizer3.Add( bSizer31, 0, 0, 5 ) + + bSizer311 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText31 = wx.StaticText( self, wx.ID_ANY, u"Number of segments .. (1-32)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText31.Wrap( -1 ) + + bSizer311.Add( self.m_staticText31, 1, wx.ALL|wx.EXPAND, 5 ) + + self.m_segments = wx.TextCtrl( self, wx.ID_ANY, u"16", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_segments.SetMinSize( wx.Size( 1000,-1 ) ) + + bSizer311.Add( self.m_segments, 1, wx.ALL, 5 ) + + + bSizer3.Add( bSizer311, 1, wx.EXPAND, 5 ) + + self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer3.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 ) + + bSizer12 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText1013 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText1013.Wrap( -1 ) + + bSizer12.Add( self.m_staticText1013, 1, wx.ALL, 5 ) + + self.m_bitmap1 = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.Size( 180,100 ), 0 ) + bSizer12.Add( self.m_bitmap1, 1, wx.EXPAND, 5 ) + + + bSizer3.Add( bSizer12, 1, wx.EXPAND, 5 ) + + bSizer1 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_buttonRound = wx.Button( self, wx.ID_OK, u"Round", wx.DefaultPosition, wx.DefaultSize, 0 ) + + self.m_buttonRound.SetDefault() + bSizer1.Add( self.m_buttonRound, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.m_buttonCancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1.Add( self.m_buttonCancel, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + + bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 ) + + sbSizer1 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Reconnecting" ), wx.VERTICAL ) + + bSizer611 = wx.BoxSizer( wx.VERTICAL ) + + self.m_staticText81 = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"Select a Track to delete round segments", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText81.Wrap( -1 ) + + bSizer611.Add( self.m_staticText81, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND, 5 ) + + self.m_buttonDelete = wx.Button( sbSizer1.GetStaticBox(), wx.ID_OK, u"Delete", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer611.Add( self.m_buttonDelete, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.m_staticline2 = wx.StaticLine( sbSizer1.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer611.Add( self.m_staticline2, 0, wx.EXPAND |wx.ALL, 5 ) + + + sbSizer1.Add( bSizer611, 1, wx.EXPAND, 5 ) + + bSizer111 = wx.BoxSizer( wx.HORIZONTAL ) + + bSizer8 = wx.BoxSizer( wx.VERTICAL ) + + self.m_buttonReconnect = wx.Button( sbSizer1.GetStaticBox(), wx.ID_OK, u"Connect", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer8.Add( self.m_buttonReconnect, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.m_checkBoxDelete = wx.CheckBox( sbSizer1.GetStaticBox(), wx.ID_ANY, u"clean path", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer8.Add( self.m_checkBoxDelete, 0, wx.ALL, 5 ) + + + bSizer111.Add( bSizer8, 1, wx.EXPAND, 5 ) + + self.m_staticText10111 = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"Select tracks including one round corner to be straighten", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText10111.Wrap( -1 ) + + bSizer111.Add( self.m_staticText10111, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 ) + + + sbSizer1.Add( bSizer111, 1, wx.EXPAND, 5 ) + + + bSizer3.Add( sbSizer1, 1, wx.EXPAND, 5 ) + + + self.SetSizer( bSizer3 ) + self.Layout() + + self.Centre( wx.BOTH ) + + def __del__( self ): + pass + + diff --git a/kicad_plugins/round_tracks/Track_Rounder.fbp b/kicad_plugins/round_tracks/Track_Rounder.fbp new file mode 100644 index 00000000..2f80eacd --- /dev/null +++ b/kicad_plugins/round_tracks/Track_Rounder.fbp @@ -0,0 +1,1175 @@ + + + + + + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + RoundTrackDlg + 1000 + none + + 0 + RoundTrackDlg + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + RoundTrackDlg + + 432,532 + wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Round Track parameters + + + + + + + bSizer3 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Select Two angled Tracks + 0 + + 0 + + + 0 + + 1 + m_comment + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + + 0 + + + bSizer31 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Distance from Intersection (mm) + 0 + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + 1000,-1 + 1 + m_distanceMM + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxTextValidator + + 5 + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer311 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Number of segments .. (1-32) + 0 + + 0 + + + 0 + + 1 + m_staticText31 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + 1000,-1 + 1 + m_segments + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxTextValidator + + 16 + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer12 + wxHORIZONTAL + none + + 5 + wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + + 0 + + 1 + m_staticText1013 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + -1,-1 + + 0 + -1,-1 + 1 + m_bitmap1 + 1 + + + protected + 1 + + Resizable + 1 + 180,100 + ; ; forward_declare + 0 + + + + + + + + + + 5 + wxALIGN_RIGHT|wxEXPAND + 0 + + + bSizer1 + wxHORIZONTAL + none + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 1 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + Round + + 0 + + 0 + + + 0 + + 1 + m_buttonRound + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + 0 + + + 0 + + 1 + m_buttonCancel + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 1 + + wxID_ANY + Reconnecting + + sbSizer1 + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + -1,-1 + bSizer611 + wxVERTICAL + none + + 5 + wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Select a Track to delete round segments + 0 + + 0 + + + 0 + + 1 + m_staticText81 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + Delete + + 0 + + 0 + + + 0 + + 1 + m_buttonDelete + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline2 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer111 + wxHORIZONTAL + none + + 5 + wxEXPAND + 1 + + + bSizer8 + wxVERTICAL + none + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + Connect + + 0 + + 0 + + + 0 + + 1 + m_buttonReconnect + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + clean path + + 0 + + + 0 + + 1 + m_checkBoxDelete + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Select tracks including one round corner to be straighten + 0 + + 0 + + + 0 + + 1 + m_staticText10111 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + + + + + + + diff --git a/kicad_plugins/round_tracks/__init__.py b/kicad_plugins/round_tracks/__init__.py new file mode 100644 index 00000000..c51efd7e --- /dev/null +++ b/kicad_plugins/round_tracks/__init__.py @@ -0,0 +1,2 @@ +from .round_trk import Tracks_Rounder +Tracks_Rounder().register() diff --git a/kicad_plugins/round_tracks/round_track.png b/kicad_plugins/round_tracks/round_track.png new file mode 100644 index 00000000..d5abe07b Binary files /dev/null and b/kicad_plugins/round_tracks/round_track.png differ diff --git a/kicad_plugins/round_tracks/round_track.svg b/kicad_plugins/round_tracks/round_track.svg new file mode 100644 index 00000000..6d479a32 --- /dev/null +++ b/kicad_plugins/round_tracks/round_track.svg @@ -0,0 +1,108 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/kicad_plugins/round_tracks/round_track_help.png b/kicad_plugins/round_tracks/round_track_help.png new file mode 100644 index 00000000..92216f13 Binary files /dev/null and b/kicad_plugins/round_tracks/round_track_help.png differ diff --git a/kicad_plugins/round_tracks/round_track_help.svg b/kicad_plugins/round_tracks/round_track_help.svg new file mode 100644 index 00000000..e370a96d --- /dev/null +++ b/kicad_plugins/round_tracks/round_track_help.svg @@ -0,0 +1,196 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + d + + + + + r + diff --git a/kicad_plugins/round_tracks/round_trk.py b/kicad_plugins/round_tracks/round_trk.py new file mode 100755 index 00000000..1dee8dc2 --- /dev/null +++ b/kicad_plugins/round_tracks/round_trk.py @@ -0,0 +1,813 @@ +#!/usr/bin/env python + +# Copyright 2019 Maurice https://github.com/easyw/ + +# some source tips @ +# https://github.com/bpkempke/kicad-scripts +# https://github.com/MitjaNemec/Kicad_action_plugins +# https://github.com/jsreynaud/kicad-action-scripts + +# GNU GENERAL PUBLIC LICENSE +# Version 3, 29 June 2007 +# +# Copyright (C) 2007 Free Software Foundation, Inc. +# Everyone is permitted to copy and distribute verbatim copies +# of this license document, but changing it is not allowed. +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +# import round_trk; reload(round_trk) + +## todo: +# 1) insert check drc for rounding & fencing +# 2) add radius as text to rounded curve +# 3) add selected track lenght + +import sys +import os +from pcbnew import * +import wx +import pcbnew +import math +import cmath + +#from .RoundTrackDlg import RoundTrackDlg +from . import RoundTrackDlg + + +ToUnits=pcbnew.ToMM #ToMils +FromUnits=pcbnew.FromMM #Mils + +debug = False #True +debug2 = False +show_points = False +show_points2 = False + +global delete_before_connect +delete_before_connect = False + +# N_SEGMENTS = 32 #4#32 +# distI = FromMM(10) + +# import pcbnew; print (pcbnew.PLUGIN_DIRECTORIES_SEARCH) + +# Python plugin stuff + +class RoundTrack_Dlg(RoundTrackDlg.RoundTrackDlg): + # from https://github.com/MitjaNemec/Kicad_action_plugins + # hack for new wxFormBuilder generating code incompatible with old wxPython + # noinspection PyMethodOverriding + def SetSizeHints(self, sz1, sz2): + if wx.__version__ < '4.0': + self.SetSizeHintsSz(sz1, sz2) + else: + super(RoundTrack_Dlg, self).SetSizeHints(sz1, sz2) + + def onDeleteClick(self, event): + return self.EndModal(wx.ID_DELETE) + + def onConnectClick(self, event): + return self.EndModal(wx.ID_REVERT) + + def __init__(self, parent): + global delete_before_connect + import wx + RoundTrackDlg.RoundTrackDlg.__init__(self, parent) + #self.GetSizer().Fit(self) + self.SetMinSize(self.GetSize()) + self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) + self.m_buttonReconnect.Bind(wx.EVT_BUTTON, self.onConnectClick) + if wx.__version__ < '4.0': + self.m_buttonReconnect.SetToolTipString( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + self.m_buttonRound.SetToolTipString( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + else: + self.m_buttonReconnect.SetToolTip( u"Select two converging Tracks to re-connect them\nor Select tracks including one round corner to be straighten" ) + self.m_buttonRound.SetToolTip( u"Select two connected Tracks to round the corner\nThen choose distance from intersection and the number of segments" ) + if self.m_checkBoxDelete.IsChecked(): + delete_before_connect = True + +# +class Tracks_Rounder(pcbnew.ActionPlugin): + + def defaults(self): + self.name = "Rounder for Tracks\n version 2.5" + self.category = "Modify PCB" + self.description = "Rounder for selected Traces on the PCB" + self.icon_file_name = os.path.join(os.path.dirname(__file__), "./round_track.png") + self.show_toolbar_button = True + + def Warn(self, message, caption='Warning!'): + dlg = wx.MessageDialog( + None, message, caption, wx.OK | wx.ICON_WARNING) + dlg.ShowModal() + dlg.Destroy() + + def CheckDistanceInput(self, value, data): + val = None + try: + val = float(value.replace(',','.')) + if val <= 0: + raise Exception("Invalid") + except: + self.Warn( + "Invalid parameter for %s: Must be a positive number" % data) + val = None + return val + + def CheckSegmentsInput(self, value, data): + val = None + try: + val = int(value) + if (val < 2) or (val >32): + raise Exception("Invalid") + except: + self.Warn( + "Invalid parameter for %s: Must be bigger than 2" % data) + val = None + return val + + def Run(self): + global delete_before_connect + #self.pcb = GetBoard() + # net_name = "GND" + pcb = pcbnew.GetBoard() + + #from https://github.com/MitjaNemec/Kicad_action_plugins + #hack wxFormBuilder py2/py3 + # _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] + _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetName() == 'PcbFrame'][0] + #aParameters = RoundTrackDlg(None) + aParameters = RoundTrack_Dlg(_pcbnew_frame) + if hasattr (pcb, 'm_Uuid'): + aParameters.m_buttonDelete.Disable() + aParameters.m_checkBoxDelete.Disable() + #aParameters = RoundTrack_DlgEx(_pcbnew_frame) + aParameters.Show() + #end hack + aParameters.m_distanceMM.SetValue("5") + aParameters.m_segments.SetValue("16") + aParameters.m_bitmap1.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "round_track_help.png") ) ) + modal_result = aParameters.ShowModal() + segments = self.CheckSegmentsInput( + aParameters.m_segments.GetValue(), "number of segments") + distI = FromMM(self.CheckDistanceInput(aParameters.m_distanceMM.GetValue(), "distance from intersection")) + if aParameters.m_checkBoxDelete.IsChecked(): + delete_before_connect = True + else: + delete_before_connect = False + if segments is not None and distI is not None: + if modal_result == wx.ID_OK: + Round_Selection(pcb, distI, segments) + pcbnew.Refresh() + elif modal_result == wx.ID_DELETE: + Delete_Segments(pcb) + #wx.LogMessage('Round Segments on Track Net Deleted') + elif modal_result == wx.ID_REVERT: + wxLogDebug('Connecting Tracks',debug) + Connect_Segments(pcb) + else: + None # Cancel + #pcbnew.Refresh() + else: + None # Invalid input + aParameters.Destroy() + + #Round_Selection(pcb) +# + + +def wxLogDebug(msg,show): + """printing messages only if show is omitted or True""" + if show: + wx.LogMessage(msg) +# +def distance (p1,p2): + return math.hypot(p1.y-p2.y,p1.x-p2.x) +# +#gets the angle of a track +def getTrackAngle(t1,center): + #use atan2 so the correct quadrant is returned + if t1.GetStart().x == center.x and t1.GetStart().y == center.y: + wxLogDebug("Start = Center",debug) + return math.atan2((t1.GetEnd().y - t1.GetStart().y), (t1.GetEnd().x - t1.GetStart().x)) + else: + wxLogDebug("End = Center",debug) + return math.atan2((t1.GetStart().y - t1.GetEnd().y), (t1.GetStart().x - t1.GetEnd().x)); +# +#track length +def GetTrackLength(t1): + return t1.GetLength() +# +def create_Track(pcb,p1,p2,lyr=None,w=None,Nn=None,Ts=None): + #draw segment to test + #new_line = pcbnew.DRAWSEGMENT(pcb) + if hasattr(pcbnew,'TRACK'): + new_line = pcbnew.TRACK(pcb) + else: + new_shape = PCB_SHAPE() + new_line = PCB_TRACK(new_shape) + new_line.SetStart(p1) + new_line.SetEnd(p2) + if w is None: + new_line.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width))) + else: + new_line.SetWidth(FromUnits(w)) + if lyr is None: + lyr = F_SilkS + if Nn is not None: + new_line.SetNet(Nn) + #new_line.SetNetname(Nn) + new_line.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer)) + if Ts is not None: + tsc = 0 + Nname = new_line.GetNetname() + for c in Nname: + tsc = tsc + ord(c) + if hasattr(new_line, 'SetTimeStamp'): + new_line.SetTimeStamp(tsc) # adding a unique number (this netname) as timestamp to mark this segment as generated by this script on this netname + pcb.Add(new_line) + return new_line +# +def create_Arc(pcb,p1,p2,mp,lyr=None,w=None,Nn=None,Ts=None): + #import pcbnew + #from pcbnew import * + #b = pcbnew.GetBoard() + #new_shape = PCB_SHAPE() + #new_arc = PCB_ARC(new_shape) + #p1= wxPoint(203200000, 127000000) + #md= wxPoint(221160512, 134439488) + #p2= wxPoint(228600000, 152400000) + #new_arc.SetStart(p1) + #new_arc.SetMid(md) + #new_arc.SetEnd(p2) + #new_arc.SetWidth(250000) + #new_arc.SetLayer(pcbnew.B_Cu) + #b.Add(new_arc) + #pcbnew.Refresh() + + #draw segment to test + #new_line = pcbnew.DRAWSEGMENT(pcb) + if hasattr(pcbnew,'TRACK'): + new_arc = pcbnew.TRACK(pcb) + else: + #new_shape = PCB_SHAPE() + #new_arc = PCB_ARC(new_shape) + new_trk = PCB_TRACK(pcb) + new_arc = PCB_ARC(new_trk) + new_arc.SetStart(p1) + new_arc.SetEnd(p2) + new_arc.SetMid(mp) + if w is None: + new_arc.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width))) + else: + new_arc.SetWidth(FromUnits(w)) + if lyr is None: + lyr = F_SilkS + if Nn is not None: + new_arc.SetNet(Nn) + #new_arc.SetNetname(Nn) + new_arc.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer)) + if Ts is not None: + tsc = 0 + Nname = new_arc.GetNetname() + for c in Nname: + tsc = tsc + ord(c) + if hasattr(new_arc, 'SetTimeStamp'): + new_arc.SetTimeStamp(tsc) # adding a unique number (this netname) as timestamp to mark this segment as generated by this script on this netname + pcb.Add(new_arc) + return new_arc +# + +def create_Draw(pcb,p1,p2,lyr=None,w=None): + #draw segment to test + if hasattr(pcbnew,'DRAWSEGMENT'): + new_line = pcbnew.DRAWSEGMENT(pcb) + else: + new_line = PCB_SHAPE() + #new_line = pcbnew.TRACK(pcb) + new_line.SetStart(p1) + new_line.SetEnd(p2) + if w is None: + new_line.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width))) + else: + new_line.SetWidth(FromUnits(w)) + if lyr is None: + lyr = F_SilkS + new_line.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer)) + pcb.Add(new_line) + return new_line +# +def create_Text(pcb, txt, p, w, lyr): + if hasattr(pcbnew,'TEXTE_PCB'): + mytxt = pcbnew.TEXTE_PCB(pcb) + else: + mytxt = pcbnew.PCB_TEXT(EDA_TEXT) #Cast_to_PCB_TEXT(EDA_TEXT) + mytxt.SetText(txt) + mytxt.SetLayer(lyr) + mytxt.SetPosition(p) + mytxt.SetHorizJustify(pcbnew.GR_TEXT_HJUSTIFY_CENTER) + mytxt.SetTextSize(pcbnew.wxSize(w,w)) + if hasattr(mytext, 'SetThickness'): + mytxt.SetThickness(int(w/4)) + else: + mytxt.SetTextThickness(int(w/4)) + pcb.Add(mytxt) +# + +def getAngleRadians(p1,p2): + #return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x))) + return (math.atan2((p1.y-p2.y),(p1.x-p2.x))) +# + +def rotatePoint(r,sa,da,c): + # sa, da in radians + x = c.x - math.cos(sa+da) * r + y = c.y - math.sin(sa+da) * r + return wxPoint(x,y) + +def create_round_segments(pcb,sp,a1,ep,a2,cntr,rad,layer,width,Nn,N_SEGMENTS): + start_point = sp + end_point = ep + pos = sp + next_pos = ep + a1 = getAngleRadians(cntr,sp) + a2 = getAngleRadians(cntr,ep) + wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug) + if (a2-a1) > 0 and abs(a2-a1) > math.radians(180): + deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS + wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug) + elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180): + deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS + wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug) + else: + deltaA = (a2-a1)/N_SEGMENTS + delta=deltaA + wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug) + points = [] + #import round_trk; import importlib; importlib.reload(round_trk) + for ii in range (N_SEGMENTS+1): #+1): + points.append(pos) + #t = create_Track(pos,pos) + prv_pos = pos + #pos = pos + fraction_delta + #posPolar = cmath.polar(pos) + #(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi. + #pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y) + pos = rotatePoint(rad,a1,delta,cntr) + delta=delta+deltaA + wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug) + if hasattr(pcbnew,'TRACK'): + for i, p in enumerate(points): + #if i < len (points)-1: + if i < len (points)-2: + t = create_Track(pcb,p,points[i+1],layer,width,Nn,True) #adding ts code to segments + t = create_Track(pcb,points[-2],ep,layer,width,Nn,True) #avoiding rounding on last segment + else: + # for i, p in enumerate(points): + # #if i < len (points)-1: + # if i < len (points)-2: + # t = create_Arc(pcb,p,points[i+1],layer,width,Nn,True) #adding ts code to segments + #t = create_Track(pcb,points[-2],ep,layer,width,Nn,True) #avoiding rounding on last segment + p1 = points[0] + p2 = points[-1] + mp = mid_point(points[0],points[-1],(a2-a1)) + + # #t = create_Arc(pcb,points[0],points[-1],mp,layer,width,Nn,True) + #p1= wxPoint(203200000, 127000000) + #mp= wxPoint(221160512, 134439488) + #p2= wxPoint(228600000, 152400000) + #mp = mid_point(p1,p2,math.pi/2) + #wx.LogMessage(str(mp)) + t = create_Arc(pcb,p1,p2,mp,layer,width,Nn,True) + #t = create_Arc(pcb,points[-2],ep,layer,width,Nn,True) + return points[-1] +# +def mid_point(p1,p2,angle): #wxpoints,angle in radians + """mid_point(prev_vertex,vertex,angle)-> mid_vertex + returns mid point on arc of angle between prev_vertex and vertex""" + #angle=math.radians(angle/2) + angle=(angle/2) + basic_angle=math.atan2(p2.y-p1.y,p2.x-p1.x)-math.pi/2 + shift=(1-math.cos(angle))*math.hypot(p2.y-p1.y,p2.x-p1.x)/2/math.sin(angle) + midpoint=wxPoint((p2.x+p1.x)/2+shift*math.cos(basic_angle),(p2.y+p1.y)/2+shift*math.sin(basic_angle)) + return midpoint +### +def create_round_points(pcb,sp,a1,ep,a2,cntr,rad,N_SEGMENTS): + #TODO: Put some error checking in here... + #Re-order the two converging tracks if we're selecting the startpoint + start_point = sp + end_point = ep + pos = sp + next_pos = ep + wxLogDebug('sp:'+str(ToMM(sp))+';ep:'+str(ToMM(ep))+';cntr:'+str(ToMM(cntr)),debug) + a1 = getAngleRadians(cntr,sp) + a2 = getAngleRadians(cntr,ep) + wxLogDebug('sp:'+str(ToMM(sp))+';ep:'+str(ToMM(ep))+';cntr:'+str(ToMM(cntr)),debug) + wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug) + #if a1 < 0: + # a1 = math.radians(180) -a1 + #if a2 < 0: + # a2 = math.radians(180) -a2 + if (a2-a1) > 0 and abs(a2-a1) > math.radians(180): + deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS + wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug) + elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180): + deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS + wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug) + else: + deltaA = (a2-a1)/N_SEGMENTS + delta=deltaA + wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug) + points = [] + #import round_trk; import importlib; importlib.reload(round_trk) + for ii in range (N_SEGMENTS+1): + points.append(pos) + #t = create_Track(pos,pos) + prv_pos = pos + #pos = pos + fraction_delta + #posPolar = cmath.polar(pos) + #(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi. + #pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y) + pos = rotatePoint(rad,a1,delta,cntr) + delta=delta+deltaA + wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug) + for i, p in enumerate(points): + if i < len (points): + t = create_Draw(pcb,p,p,B_CrtYd,0.5+i*0.05) +# +def not_eq(a,b): + if abs(a-b) >= 1: #1nm + return True + else: + return False +# + +def getCircleCenterRadius(sp,ep,ip): + #center + # NB add always set float even if values are pcb internal Units!!! + x1 = float(sp.x); y1 = float(sp.y) + x2 = float(ep.x); y2 = float(ep.y) + xi = float(ip.x); yi = float(ip.y) + # mg formula + cxN = (y2-y1)*(yi-y1)*(yi-y2)-(xi-x1)*x1*(yi-y2)+(xi-x2)*x2*(yi-y1) + cxD = -x2*yi-xi*y1+x2*y1+xi*y2+x1*yi-x1*y2 + if cxD != 0: + Cx = cxN/cxD + else: + #stop + Cx= FromMM(100) + wxLogDebug(str(ToMM(y1))+':'+str(ToMM(yi))+':'+str(ToMM(y2)),debug) + wxLogDebug(str(ToMM(x1))+':'+str(ToMM(xi))+':'+str(ToMM(x2)),debug) + if not_eq(yi,y1): + Cy = y1 - (xi-x1)/(yi-y1)*(Cx-x1) + elif yi==y1 and (yi!=y2): + Cx = x1 + Cy = y2 - (xi-x2)/(yi-y2)*(Cx-x2) + elif yi==y2 and (yi!=y1): + Cx = x2 + Cy = y1 - (xi-x1)/(yi-y1)*(Cx-x1) + else: + Cy = FromMM(100) + # import round_trk; reload(round_trk) + # import round_trk; import importlib; importlib.reload(round_trk) + + radius = math.hypot(Cx-sp.x,Cy-sp.y) + return wxPoint(Cx,Cy), radius +# +def deleteSelectedTracks(pcb): + tracks = pcb.GetTracks() + tracks_cp = list(tracks) + l = len (tracks_cp) + if hasattr(pcbnew,'TRACK'): + track_item = pcbnew.TRACK + else: + track_item = pcbnew.PCB_TRACK + for i in range(l): + if type(tracks_cp[i]) is track_item and tracks_cp[i].IsSelected(): #item.GetNetname() == net_name: + pcb.RemoveNative(tracks_cp[i]) + #for item in pcb.GetTracks(): + # if type(item) is TRACK and item.IsSelected(): #item.GetNetname() == net_name: + # pcb.RemoveNative(item) + # #pcb.Delete(item) +# +def deleteListTracks(pcb,tracks): + tracksToDel_cp = list(tracks) + l = len (tracksToDel_cp) + if hasattr(pcbnew,'TRACK'): + track_item = pcbnew.TRACK + else: + track_item = pcbnew.PCB_TRACK + for i in range(l): + if type(tracksToDel_cp[i]) is track_item: #item.GetNetname() == net_name: + pcb.RemoveNative(tracksToDel_cp[i]) + #for item in tracks: + # if type(item) is TRACK: #item.GetNetname() == net_name: + # pcb.RemoveNative(item) + # #pcb.Delete(item) +# +def selectListTracks(pcb,tracks): + if hasattr(pcbnew,'TRACK'): + track_item = pcbnew.TRACK + else: + track_item = pcbnew.PCB_TRACK + for item in tracks: + if type(item) is track_item: + item.SetSelected() +# + +def getSelTracksLength(pcb): + ln = 0. + if hasattr(pcbnew,'TRACK'): + track_item = pcbnew.TRACK + else: + track_item = pcbnew.PCB_TRACK + for item in pcb.GetTracks(): + if type(item) is track_item and item.IsSelected(): + ln+=(item.GetLength()) + return(ln) + #print(pcbnew.ToMM(ln)) +# +## def HitTest(self, *args): for Tracks and Vias + +##----------------------------------------------------------------------------------------------------- +def Round_Selection(pcb,distI,segments): + global delete_before_connect + tracks = [] + #print ("TRACKS WHICH MATCH CRITERIA:") + if hasattr(pcbnew,'TRACK'): + track_item = pcbnew.TRACK + else: + track_item = pcbnew.PCB_TRACK + for item in pcb.GetTracks(): + if type(item) is track_item and item.IsSelected(): #item.GetNetname() == net_name: + tracks.append(item) + wxLogDebug(str(len(tracks)),debug) + + if len (tracks) == 2: + #add all the possible intersections to a unique set, for iterating over later + intersections = set(); + for t1 in range(len(tracks)): + for t2 in range(t1+1, len(tracks)): + #check if these two tracks share an endpoint + # reduce it to a 2-part tuple so there are not multiple objects of the same point in the set + if(tracks[t1].IsPointOnEnds(tracks[t2].GetStart())): + intersections.add((tracks[t2].GetStart().x, tracks[t2].GetStart().y)) + if(tracks[t1].IsPointOnEnds(tracks[t2].GetEnd())): + intersections.add((tracks[t2].GetEnd().x, tracks[t2].GetEnd().y)) + if len(intersections)==1: + for ip in intersections: + (x,y) = ip + wxLogDebug("intersections: "+str(ToUnits(x))+":"+str(ToUnits(y)),debug) + #wx.LogMessage(str(tracks[0].GetStart())) + intersection = wxPoint(x,y) + if tracks[0].GetStart() == pcbnew.wxPoint(x,y): + first_trk_extNode = tracks[0].GetEnd() + #wx.LogMessage("tracks[0] external node="+str(ToUnits(tracks[0].GetEnd().x))+";"+str(ToUnits(tracks[0].GetEnd().y))) + else: + first_trk_extNode = tracks[0].GetStart() + #wx.LogMessage("tracks[0] external node="+str(ToUnits(tracks[0].GetStart().x))+";"+str(ToUnits(tracks[0].GetStart().y))) + if tracks[1].GetStart() == pcbnew.wxPoint(x,y): + last_trk_extNode = tracks[1].GetEnd() + #wx.LogMessage("tracks[1] external node="+str(ToUnits(tracks[1].GetEnd().x))+";"+str(ToUnits(tracks[1].GetEnd().y))) + else: + last_trk_extNode = tracks[1].GetStart() + #wx.LogMessage("tracks[1] external node="+str(ToUnits(tracks[1].GetStart().x))+";"+str(ToUnits(tracks[1].GetStart().y))) + angle1 = math.degrees((getTrackAngle(tracks[0],intersection))) + angle2 = math.degrees((getTrackAngle(tracks[1],intersection))) + end_coord1 = (distI) * cmath.exp(math.radians(angle1)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi. + end_coord2 = (distI) * cmath.exp(math.radians(angle2)*1j) + startP = wxPoint(end_coord1.real+x,end_coord1.imag+y) + endP = wxPoint(end_coord2.real+x,end_coord2.imag+y) + layer = tracks[0].GetLayer() + width = ToMM(tracks[0].GetWidth()) + Nname = tracks[0].GetNet() #.GetNetname() + wxLogDebug("offset1 = "+str(ToUnits(startP)),debug) #+":"+str(ToUnits(endP)),debug) + wxLogDebug("offset2 = "+str(ToUnits(endP)),debug) #end_coord2.real+x))+":"+str(ToUnits(end_coord2.imag+y))) + center,radius = getCircleCenterRadius( startP,endP,intersection ) + #rad = math.hypot(center.x-startP.x,center.y-startP.y) + wxLogDebug('radius'+str(ToMM(radius)),debug) + wxLogDebug('center'+str(ToMM(center)),debug) + # import round_trk; import importlib; importlib.reload(round_trk) + lenT1 = GetTrackLength(tracks[0]) + dist1 = math.hypot(startP.y-intersection.y,startP.x-intersection.x) + lenT2 = GetTrackLength(tracks[1]) + dist2 = math.hypot(endP.y-intersection.y,endP.x-intersection.x) + wxLogDebug('Len T1 {0:.3f} mm, dist1 {1:.3f} mm, LenT2 {2:.3f} mm, dist2 {3:.3f} mm'.format(ToMM(lenT1),ToMM(dist1),ToMM(lenT2),ToMM(dist2)),debug) + if show_points: + create_Draw(pcb,startP,startP,F_Mask,0.2) + create_Draw(pcb,intersection,intersection,Eco1_User,1.5) + create_Draw(pcb,endP,endP,B_Mask,0.2) + create_Draw(pcb,center,center,F_SilkS,2.) + create_round_points(pcb,startP,angle1,endP,angle2,center,radius,segments) + pcbnew.Refresh() + selectListTracks(pcb,tracks) + if (lenT1 < dist1) or (lenT2 < dist2): + wxLogDebug('Segments too short compared to selected distance {0:.3f} mm'.format(ToMM(distI)),True) + else: + #create_Track(pcb,first_trk_extNode,startP,layer,width,Nname) #B_Cu,0.2) + #if delete_before_connect: + deleteListTracks(pcb,tracks) + create_Track(pcb,startP,first_trk_extNode,layer,width,Nname) #B_Cu,0.2) + #create_Draw(pcb,startP,startP,F_Mask,1.5) + newEP = create_round_segments(pcb,startP,angle1,endP,angle2,center,radius,layer,width,Nname,segments) #B_Cu,0.2) + #wxLogDebug(str(newEP)+':'+str(endP),True) + #create_Draw(pcb,endP,endP,B_Mask,1.9) + create_Track(pcb,endP,last_trk_extNode,layer,width,Nname) # B_Cu,0.2) + #create_Track(pcb,last_trk_extNode,endP,layer,width,Nname) # B_Cu,0.2) + #deleteSelectedTracks(pcb) + #selectListTracks(pcb,tracks) + w3 = 3*float(width) + rad = float(ToMM(radius)) + wxLogDebug(str(w3),debug) + msg = u'Corner Radius: {0:.3f} mm'.format(rad) + msg+= u'\nAngle between tracks: {0:.1f} deg'.format(angle1-angle2) + if rad < w3: + msg += u'\n\u2718 ALERT: Radius < 3 *(track width) !!!\n[{0:.3f}mm < 3*{1:.3f}mm]'.format(rad,width) + #else: + # #msg = u'\n\u2714 Radius > 3 * (track width)' + # msg = u'\u2714 Corner Radius: {0:.3f} mm'.format(rad) + wxLogDebug(msg,True) + pcbnew.Refresh() + # import round_trk; reload(round_trk) + # import round_trk; import importlib; importlib.reload(round_trk) + else: + wxLogDebug("you must select two tracks (only)",not debug) +# +def Delete_Segments(pcb, track=None): + global delete_before_connect + tracks = [] + tracksToKeep = [] + if track is None: + if hasattr(pcbnew,'TRACK'): + track_item = pcbnew.TRACK + else: + track_item = pcbnew.PCB_TRACK + for item in pcb.GetTracks(): + if type(item) is track_item and item.IsSelected(): + tracks.append(item) + wxLogDebug('tracks selected: '+str(len(tracks)),debug2) + else: + tracks.append(track) + if len (tracks) == 1 and delete_before_connect: + Netname = tracks[0].GetNetname() + tsc = 0 + for c in Netname: + tsc = tsc + ord(c) + nseg = 0 + tracksToDel = [] + for track in pcb.GetTracks(): + if hasattr(track,'GetTimeStamp'): + tsd = track.GetTimeStamp() + else: + tsd = track.m_Uuid.AsLegacyTimestamp() + wxLogDebug('tracks ts: '+str(tsc)+';'+str(tsd),debug2) + if tsd == tsc and tsd != 0: + tracksToDel.append(track) + #pcb.RemoveNative(track) + nseg+=1 + if nseg > 0: + tracksToDel_cp = list(tracksToDel) + l = len (tracksToDel_cp) + #for track in tracksToDel: + for i in range(l): + pcb.RemoveNative(tracksToDel_cp[i]) + wxLogDebug(u'\u2714 Round Segments on Track Net Deleted',True) + else: + Netname = tracks[0].GetNetname() + tsc = 0 + for c in Netname: + tsc = tsc + ord(c) + nseg = 0 + tracksToDel = [] + if hasattr(pcbnew,'TRACK'): + track_item = pcbnew.TRACK + else: + track_item = pcbnew.PCB_TRACK + for track in pcb.GetTracks(): + if type(track) is track_item and track.IsSelected(): + if hasattr(track,'GetTimeStamp'): + tsd = track.GetTimeStamp() + else: + tsd = track.m_Uuid.AsLegacyTimestamp() + wxLogDebug('tracks ts: '+str(tsc)+';'+str(tsd),debug2) + if tsd == tsc and tsd != 0: + tracksToDel.append(track) + #pcb.RemoveNative(track) + nseg+=1 + else: + tracksToKeep.append(track) + if nseg > 0: + tracksToDel_cp = list(tracksToDel) + l = len (tracksToDel_cp) + for i in range(l): + pcb.RemoveNative(tracksToDel_cp[i]) + #for track in tracksToDel: + # pcb.RemoveNative(track) + wxLogDebug(u'\u2714 Round Segments on Selected Track deleted',True) + elif delete_before_connect: + wxLogDebug(u'\u2718 you must select One track only',not debug) + return tracksToKeep +# +def Connect_Segments(pcb): + tracks = [] + tracksToKeep = [] + if hasattr(pcbnew,'TRACK'): + track_item = pcbnew.TRACK + else: + track_item = pcbnew.PCB_TRACK + for item in pcb.GetTracks(): + if type(item) is track_item and item.IsSelected(): + tracks.append(item) + wxLogDebug(str(len(tracks)),debug) + + if len (tracks) >= 2: + pi_exists = True + if len (tracks) > 2: + tracksToKeep = Delete_Segments(pcb) + if len (tracksToKeep) == 2: + tracks[0] = tracksToKeep[0] + tracks[1] = tracksToKeep[1] + else: + wxLogDebug(u'\u2718 wrong selection (error)\nselect Only one corner to be straighten',not debug) + else: + Delete_Segments(pcb,tracks[0]) + #getting points + if tracks[0].GetStart().x < tracks[0].GetEnd().x: + first_trk_startP = tracks[0].GetStart() + first_trk_endP = tracks[0].GetEnd() + else: + first_trk_startP = tracks[0].GetEnd() + first_trk_endP = tracks[0].GetStart() + if tracks[1].GetStart().x < tracks[1].GetEnd().x: + last_trk_startP = tracks[1].GetStart() + last_trk_endP = tracks[1].GetEnd() + else: + last_trk_startP = tracks[1].GetEnd() + last_trk_endP = tracks[1].GetStart() + wxLogDebug('sp1:'+str(first_trk_startP)+';'+str(first_trk_endP),debug2) + wxLogDebug('sp2:'+str(last_trk_startP)+';'+str(last_trk_endP),debug2) + x1 = float(first_trk_startP.x); y1 = float(first_trk_startP.y) + x3 = float(first_trk_endP.x); y3 = float(first_trk_endP.y) + x2 = float(last_trk_startP.x); y2 = float(last_trk_startP.y) + x4 = float(last_trk_endP.x); y4 = float(last_trk_endP.y) + if (x3!=x1) and (x4!=x2): + N = y2-y1-x2*(y4-y2)/(x4-x2)+x1*(y3-y1)/(x3-x1) + D = (y3-y1)/(x3-x1)-(y4-y2)/(x4-x2) + xi = N/D + yi = y1+(y3-y1)/(x3-x1)*(xi-x1) + elif (x3==x1): + xi = x1 + yi = y2+(y4-y2)/(x4-x2)*(x1-x2) + elif (x4 == x2): + xi = x2 + yi = y1 + (y3-y1)/(x3-x1)*(x2-x1) + else: + pi_exists = False + wxLogDebug(u'\u2718 intersection point doesn\'t exist',not debug) + if pi_exists: + wxLogDebug('pi:'+str(wxPoint(xi,yi)),debug2) #xi)+';'+str(yi),debug1) + wxLogDebug('sp1:('+str(ToMM(x1))+','+str(ToMM(y1))+')'+\ + ';('+str(ToMM(x2))+','+str(ToMM(y2))+')',debug2) + wxLogDebug('sp2:('+str(ToMM(x3))+','+str(ToMM(y3))+')'+\ + ';('+str(ToMM(x4))+','+str(ToMM(y4))+')',debug2) + wxLogDebug('pi:('+str(ToMM(xi))+','+str(ToMM(yi))+')',debug2) + pi = wxPoint(xi,yi) + if show_points2: + #create_Text(pcb, txt, p, w) + create_Text(pcb,'1',wxPoint(x1,y1),FromMM(1.0),pcbnew.F_SilkS) + create_Text(pcb,'2',wxPoint(x2,y2),FromMM(1.0),pcbnew.F_SilkS) + create_Text(pcb,'3',wxPoint(x3,y3),FromMM(1.0),pcbnew.F_SilkS) + create_Text(pcb,'4',wxPoint(x4,y4),FromMM(1.0),pcbnew.F_SilkS) + create_Text(pcb,'C',wxPoint(xi,yi),FromMM(2.0),pcbnew.B_SilkS) + wxLogDebug('dp1,pi)'+str(distance(wxPoint(x1,y1),pi)),debug2) + wxLogDebug('dp3,pi)'+str(distance(wxPoint(x3,y3),pi)),debug2) + if distance(wxPoint(x1,y1),pi) > distance(wxPoint(x3,y3),pi): + tracks[0].SetStart(wxPoint(x1,y1)) + tracks[0].SetEnd(pi) + else: + tracks[0].SetStart(wxPoint(x3,y3)) + tracks[0].SetEnd(pi) + wxLogDebug('dp2,pi)'+str(distance(wxPoint(x2,y2),pi)),debug2) + wxLogDebug('dp4,pi)'+str(distance(wxPoint(x4,y4),pi)),debug2) + if distance(wxPoint(x2,y2),pi) > distance(wxPoint(x4,y4),pi): + tracks[1].SetStart(wxPoint(x2,y2)) + tracks[1].SetEnd(pi) + else: + tracks[1].SetStart(wxPoint(x4,y4)) + tracks[1].SetEnd(pi) + pcbnew.Refresh() + else: + wxLogDebug(u'\u2718 you must select two tracks only',not debug) +# diff --git a/kicad_plugins/trace_clearance/TraceClearanceDlg.py b/kicad_plugins/trace_clearance/TraceClearanceDlg.py new file mode 100644 index 00000000..5bb03293 --- /dev/null +++ b/kicad_plugins/trace_clearance/TraceClearanceDlg.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version Oct 26 2018) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + +########################################################################### +## Class TraceClearanceDlg +########################################################################### + +class TraceClearanceDlg ( wx.Dialog ): + + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 373,480 ), style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + + self.SetSizeHints( wx.Size( 373,580 ), wx.DefaultSize ) + + bSizer2 = wx.BoxSizer( wx.VERTICAL ) + + self.m_staticText4 = wx.StaticText( self, wx.ID_ANY, u"Add copper pour keepout\nto selected traces.", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText4.Wrap( -1 ) + + bSizer2.Add( self.m_staticText4, 0, wx.ALL, 5 ) + + bSizer5 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_bitmap = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer5.Add( self.m_bitmap, 0, wx.ALL, 5 ) + + + bSizer2.Add( bSizer5, 1, wx.EXPAND, 5 ) + + bSizer3 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText5 = wx.StaticText( self, wx.ID_ANY, u"Zone clearance (mm)", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText5.Wrap( -1 ) + + bSizer3.Add( self.m_staticText5, 0, wx.ALL, 5 ) + + self.m_clearance = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer3.Add( self.m_clearance, 0, wx.ALL, 5 ) + + + bSizer2.Add( bSizer3, 1, wx.EXPAND, 5 ) + + bSizer4 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_button_ok = wx.Button( self, wx.ID_OK, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer4.Add( self.m_button_ok, 0, wx.ALL, 5 ) + + self.m_button_cancel = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer4.Add( self.m_button_cancel, 0, wx.ALL, 5 ) + + + bSizer2.Add( bSizer4, 1, wx.EXPAND, 5 ) + + + self.SetSizer( bSizer2 ) + self.Layout() + + self.Centre( wx.BOTH ) + + def __del__( self ): + pass + + diff --git a/kicad_plugins/trace_clearance/__init__.py b/kicad_plugins/trace_clearance/__init__.py new file mode 100644 index 00000000..68713f4a --- /dev/null +++ b/kicad_plugins/trace_clearance/__init__.py @@ -0,0 +1,2 @@ +from .trace_clearance import TraceClearance +TraceClearance().register() diff --git a/kicad_plugins/trace_clearance/trace_clearance.fbp b/kicad_plugins/trace_clearance/trace_clearance.fbp new file mode 100644 index 00000000..c1053ab6 --- /dev/null +++ b/kicad_plugins/trace_clearance/trace_clearance.fbp @@ -0,0 +1,485 @@ + + + + + ; + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + TraceClearanceDlg + 1000 + none + + 0 + TraceClearanceDlg + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + 373,580 + TraceClearanceDlg + + 373,580 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + ; ; forward_declare + + + + + + + + bSizer2 + wxVERTICAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Add copper pour keepout to selected traces. + 0 + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + + bSizer5 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_bitmap + 1 + + + protected + 1 + + Resizable + 1 + + ; ; forward_declare + 0 + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer3 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Zone clearance (mm) + 0 + + 0 + + + 0 + + 1 + m_staticText5 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + m_clearance + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer4 + wxHORIZONTAL + none + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + OK + + 0 + + 0 + + + 0 + + 1 + m_button_ok + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + 0 + + + 0 + + 1 + m_button_cancel + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + diff --git a/kicad_plugins/trace_clearance/trace_clearance.png b/kicad_plugins/trace_clearance/trace_clearance.png new file mode 100644 index 00000000..17d6fee4 Binary files /dev/null and b/kicad_plugins/trace_clearance/trace_clearance.png differ diff --git a/kicad_plugins/trace_clearance/trace_clearance.py b/kicad_plugins/trace_clearance/trace_clearance.py new file mode 100755 index 00000000..73909685 --- /dev/null +++ b/kicad_plugins/trace_clearance/trace_clearance.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python + +# Copyright 2019 Maurice https://github.com/easyw/ +# Copyright 2020 Matt Huszagh https://github.com/matthuszagh + +# GNU GENERAL PUBLIC LICENSE +# Version 3, 29 June 2007 +# +# Copyright (C) 2007 Free Software Foundation, Inc. +# Everyone is permitted to copy and distribute verbatim copies +# of this license document, but changing it is not allowed. +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import os +import pcbnew +import wx +# import numpy as np +from . import TraceClearanceDlg +import math + +class TraceClearance_Dlg(TraceClearanceDlg.TraceClearanceDlg): + """ + """ + + def SetSizeHints(self, sz1, sz2): + if wx.__version__ < '4.0': + self.SetSizeHintsSz(sz1, sz2) + else: + super(TraceClearance_Dlg, self).SetSizeHints(sz1, sz2) + + def __init__(self, parent): + """ + """ + TraceClearanceDlg.TraceClearanceDlg.__init__(self, parent) + self.SetMinSize(self.GetSize()) + + +class TraceClearance(pcbnew.ActionPlugin): + """ + """ + + def defaults(self): + """ + """ + self.name = "Trace Clearance Generator\n version 1.4" + self.category = "" + self.description = ( + "Generate a copper pour keepout for a selected trace." + ) + self.show_toolbar_button = True + self.icon_file_name = os.path.join( + os.path.dirname(__file__), "./trace_clearance.png" + ) + + def Run(self): + """ + """ + _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetName() == 'PcbFrame'][0] + # _pcbnew_frame = [ + # x + # for x in wx.GetTopLevelWindows() + # if x.GetTitle().lower().startswith("pcbnew") + # ][0] + wx_params = TraceClearance_Dlg(_pcbnew_frame) + wx_params.m_clearance.SetValue("0.2") + wx_params.m_bitmap.SetBitmap( + wx.Bitmap( + os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "trace_clearance_dialog.png", + ) + ) + ) + modal_res = wx_params.ShowModal() + clearance = pcbnew.FromMM( + self.InputValid(wx_params.m_clearance.GetValue()) + ) + if clearance is not None: + pcb = pcbnew.GetBoard() + if modal_res == wx.ID_OK: + tracks = selected_tracks(pcb) + if len(tracks) > 0: + set_keepouts(pcb, tracks, clearance) + else: + self.Warn("At least one track must be selected.") + elif modal_res == wx.ID_CANCEL: + wx_params.Destroy() + + def Warn(self, message, caption="Warning!"): + """ + """ + dlg = wx.MessageDialog(None, message, caption, wx.OK | wx.ICON_WARNING) + dlg.ShowModal() + dlg.Destroy() + + def InputValid(self, value): + """ + """ + try: + float_val = float(value) + except: + self.Warn("Clearance must be a floating point number.") + + if float_val <= 0: + self.Warn("Clearance must be positive.") + + return float_val + + +def selected_tracks(pcb): + """ + TODO should we use a common import with solder expander to avoid + redundant functionality? + """ + tracks = [] + if hasattr(pcbnew,'TRACK'): + track_item = pcbnew.TRACK + else: + track_item = pcbnew.PCB_TRACK + for item in pcb.GetTracks(): + if type(item) is track_item and item.IsSelected(): + tracks.append(item) + return tracks + + +def set_keepouts(pcb, tracks, clearance): + """ + """ + for track in tracks: + track_start = track.GetStart() + track_end = track.GetEnd() + if track_start.x == track_end.x and track_start.y == track_end.y: + continue + track_width = track.GetWidth() + layer = track.GetLayerSet() + + if hasattr(pcbnew,'ZONE_CONTAINER'): + keepout = pcbnew.ZONE_CONTAINER(pcb) + pts = poly_points(track_start, track_end, track_width, clearance) + keepout.AddPolygon(pts) + keepout.SetIsKeepout(True) + keepout.SetDoNotAllowCopperPour(True) + keepout.SetDoNotAllowVias(False) + keepout.SetDoNotAllowTracks(False) + keepout.SetLayerSet(layer) + else: + keepout = pcbnew.ZONE(pcb) + pts = poly_points(track_start, track_end, track_width, clearance) + # wx.LogMessage(str(pts)) + keepout.AddPolygon(pts) + #keepout.SetIsKeepout(True) + keepout.SetIsRuleArea(True) # was SetIsKeepout + keepout.SetDoNotAllowCopperPour(True) + keepout.SetDoNotAllowVias(False) + keepout.SetDoNotAllowTracks(False) + keepout.SetLayerSet(layer) + pcb.Add(keepout) + + pcbnew.Refresh() + + +def poly_points(track_start, track_end, track_width, clearance): + """ + """ + delta = track_width / 2 + clearance + dx = track_end.x - track_start.x + dy = track_end.y - track_start.y + # theta = np.arctan2(dy, dx) + theta = math.atan2(dy, dx) + # len = np.sqrt(np.power(dx, 2) + np.power(dy, 2)) + len = math.sqrt(math.pow(dx, 2) + math.pow(dy, 2)) + dx_norm = dx / len + dy_norm = dy / len + + delta_x = delta * -dy_norm + delta_y = delta * dx_norm + pt_delta = pcbnew.wxPoint(delta_x, delta_y) + + pts = [] + pts.append(track_start + pt_delta) + for pt in semicircle_points(track_start, delta, theta, True): + pts.append(pt) + pts.append(track_start - pt_delta) + pts.append(track_end - pt_delta) + for pt in semicircle_points(track_end, delta, theta, False): + pts.append(pt) + pts.append(track_end + pt_delta) + return pcbnew.wxPoint_Vector(pts) + + +def semicircle_points(circle_center, radius, angle_norm, is_start=True): + """ + """ + num_points = 20 + + # angles = np.linspace( + # angle_norm + np.pi / 2, angle_norm + 3 * np.pi / 2, num_points + 2 + # ) + start = angle_norm + math.pi / 2 + stop = angle_norm + 3 * math.pi / 2 + num_vals = num_points + delta = (stop-start)/(num_vals-1) + evenly_spaced = [start + i * delta for i in range(num_vals)] + # print(evenly_spaced) + angles = evenly_spaced + # wx.LogMessage(str(angles)) + angles = angles[1:-1] + # wx.LogMessage(str(angles)+'1') + if not is_start: + # angles = np.add(angles, np.pi) + angles.append(math.pi) + pts = [] + for ang in angles: + # pts.append( + # circle_center + # + pcbnew.wxPoint(radius * np.cos(ang), radius * np.sin(ang)) + # ) + pts.append( + circle_center + + pcbnew.wxPoint(radius * math.cos(ang), radius * math.sin(ang)) + ) + return pcbnew.wxPoint_Vector(pts) diff --git a/kicad_plugins/trace_clearance/trace_clearance.svg b/kicad_plugins/trace_clearance/trace_clearance.svg new file mode 100644 index 00000000..341ae134 --- /dev/null +++ b/kicad_plugins/trace_clearance/trace_clearance.svg @@ -0,0 +1,105 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/kicad_plugins/trace_clearance/trace_clearance_dialog.png b/kicad_plugins/trace_clearance/trace_clearance_dialog.png new file mode 100644 index 00000000..c8d9bb41 Binary files /dev/null and b/kicad_plugins/trace_clearance/trace_clearance_dialog.png differ diff --git a/kicad_plugins/trace_clearance/trace_clearance_dialog.svg b/kicad_plugins/trace_clearance/trace_clearance_dialog.svg new file mode 100644 index 00000000..4d00fa29 --- /dev/null +++ b/kicad_plugins/trace_clearance/trace_clearance_dialog.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kicad_plugins/trace_solder_expander/SolderExpanderDlg.py b/kicad_plugins/trace_solder_expander/SolderExpanderDlg.py new file mode 100644 index 00000000..e8022a74 --- /dev/null +++ b/kicad_plugins/trace_solder_expander/SolderExpanderDlg.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version Oct 26 2018) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + +########################################################################### +## Class SolderExpanderDlg +########################################################################### + +class SolderExpanderDlg ( wx.Dialog ): + + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Solder Mask Expansion", pos = wx.DefaultPosition, size = wx.Size( 579,761 ), style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER ) + + self.SetSizeHints( wx.DefaultSize, wx.DefaultSize ) + + bSizer3 = wx.BoxSizer( wx.VERTICAL ) + + self.m_comment = wx.StaticText( self, wx.ID_ANY, u"Select Tracks to add\na Solder Mask clearance expansion\nor One Pad to apply Solder Mask clearance\nexpansion to connected tracks\n", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_comment.Wrap( -1 ) + + bSizer3.Add( self.m_comment, 0, wx.ALL|wx.EXPAND, 5 ) + + bSizer4 = wx.BoxSizer( wx.VERTICAL ) + + + bSizer4.Add( ( 0, 1), 1, wx.EXPAND, 5 ) + + self.m_bitmap1 = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.Size( 177,102 ), 0 ) + bSizer4.Add( self.m_bitmap1, 0, wx.EXPAND, 5 ) + + self.m_staticText4 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText4.Wrap( -1 ) + + bSizer4.Add( self.m_staticText4, 0, wx.EXPAND, 5 ) + + + bSizer3.Add( bSizer4, 1, wx.EXPAND, 5 ) + + bSizer31 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, u"Solder Mask width (mm)\nto Add to Track's width", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText3.Wrap( -1 ) + + bSizer31.Add( self.m_staticText3, 1, wx.ALL|wx.EXPAND, 5 ) + + self.m_clearanceMM = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_clearanceMM.SetMinSize( wx.Size( 1000,-1 ) ) + + bSizer31.Add( self.m_clearanceMM, 1, wx.ALL|wx.EXPAND, 5 ) + + + bSizer3.Add( bSizer31, 0, 0, 5 ) + + bSizer1 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText101 = wx.StaticText( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText101.Wrap( -1 ) + + bSizer1.Add( self.m_staticText101, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.m_button1 = wx.Button( self, wx.ID_OK, u"OK", wx.DefaultPosition, wx.DefaultSize, 0 ) + + self.m_button1.SetDefault() + bSizer1.Add( self.m_button1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.m_button2 = wx.Button( self, wx.ID_CANCEL, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer1.Add( self.m_button2, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + + bSizer3.Add( bSizer1, 0, wx.ALIGN_RIGHT|wx.EXPAND, 5 ) + + self.m_staticline1 = wx.StaticLine( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ) + bSizer3.Add( self.m_staticline1, 0, wx.EXPAND |wx.ALL, 5 ) + + bSizer11 = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText1011 = wx.StaticText( self, wx.ID_ANY, u"Select a Mask segment to delete the Mask path", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText1011.Wrap( -1 ) + + bSizer11.Add( self.m_staticText1011, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.m_buttonDelete = wx.Button( self, wx.ID_OK, u"Delete", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer11.Add( self.m_buttonDelete, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + + bSizer3.Add( bSizer11, 1, wx.EXPAND, 5 ) + + bSizerSet = wx.BoxSizer( wx.HORIZONTAL ) + + self.m_staticText10111 = wx.StaticText( self, wx.ID_ANY, u"check this to discretize arcs", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText10111.Wrap( -1 ) + + bSizerSet.Add( self.m_staticText10111, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.m_checkBoxD = wx.CheckBox( self, wx.ID_ANY, u"segments", wx.DefaultPosition, wx.DefaultSize, 0 ) + # self.m_checkBoxD.SetToolTip( u"check this to discretize arcs with segments" ) + + bSizerSet.Add( self.m_checkBoxD, 0, wx.ALL, 5 ) + + + bSizer3.Add( bSizerSet, 1, wx.EXPAND, 5 ) + + + self.SetSizer( bSizer3 ) + self.Layout() + + self.Centre( wx.BOTH ) + + def __del__( self ): + pass + + diff --git a/kicad_plugins/trace_solder_expander/__init__.py b/kicad_plugins/trace_solder_expander/__init__.py new file mode 100644 index 00000000..1d263e73 --- /dev/null +++ b/kicad_plugins/trace_solder_expander/__init__.py @@ -0,0 +1,2 @@ +from .trace_solder_expander import Solder_Expander +Solder_Expander().register() diff --git a/kicad_plugins/trace_solder_expander/solderExpander.fbp b/kicad_plugins/trace_solder_expander/solderExpander.fbp new file mode 100644 index 00000000..771517df --- /dev/null +++ b/kicad_plugins/trace_solder_expander/solderExpander.fbp @@ -0,0 +1,954 @@ + + + + + + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + SolderExpanderDlg + 1000 + none + + 0 + SolderExpanderDlg + + . + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + + SolderExpanderDlg + + 579,761 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + + Solder Mask Expansion + + + + + + + bSizer3 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Select Tracks to add a Solder Mask clearance expansion or One Pad to apply Solder Mask clearance expansion to connected tracks + 0 + + 0 + + + 0 + + 1 + m_comment + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxEXPAND + 1 + + + bSizer4 + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + 1 + protected + 0 + + + + 5 + wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_bitmap1 + 1 + + + protected + 1 + + Resizable + 1 + 177,102 + ; ; forward_declare + 0 + + + + + + + + 5 + wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + + 0 + + 1 + m_staticText4 + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + + + 5 + + 0 + + + bSizer31 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Solder Mask width (mm) to Add to Track's width + 0 + + 0 + + + 0 + + 1 + m_staticText3 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + 1000,-1 + 1 + m_clearanceMM + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxTextValidator + + + + + + + + + + + 5 + wxALIGN_RIGHT|wxEXPAND + 0 + + + bSizer1 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + + 0 + + 1 + m_staticText101 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 1 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + OK + + 0 + + 0 + + + 0 + + 1 + m_button1 + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_CANCEL + Cancel + + 0 + + 0 + + + 0 + + 1 + m_button2 + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND | wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + m_staticline1 + 1 + + + protected + 1 + + Resizable + 1 + + wxLI_HORIZONTAL + ; ; forward_declare + 0 + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer11 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Select a Mask segment to delete the Mask path + 0 + + 0 + + + 0 + + 1 + m_staticText1011 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 0 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_OK + Delete + + 0 + + 0 + + + 0 + + 1 + m_buttonDelete + 1 + + + protected + 1 + + + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizerSet + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + check this to discretize arcs + 0 + + 0 + + + 0 + + 1 + m_staticText10111 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + segments + + 0 + + + 0 + + 1 + m_checkBoxD + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + diff --git a/kicad_plugins/trace_solder_expander/soldermask_clearance.png b/kicad_plugins/trace_solder_expander/soldermask_clearance.png new file mode 100644 index 00000000..31082fcc Binary files /dev/null and b/kicad_plugins/trace_solder_expander/soldermask_clearance.png differ diff --git a/kicad_plugins/trace_solder_expander/soldermask_clearance.svg b/kicad_plugins/trace_solder_expander/soldermask_clearance.svg new file mode 100644 index 00000000..bf46da01 --- /dev/null +++ b/kicad_plugins/trace_solder_expander/soldermask_clearance.svg @@ -0,0 +1,149 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kicad_plugins/trace_solder_expander/soldermask_clearance_help.png b/kicad_plugins/trace_solder_expander/soldermask_clearance_help.png new file mode 100644 index 00000000..f4c31645 Binary files /dev/null and b/kicad_plugins/trace_solder_expander/soldermask_clearance_help.png differ diff --git a/kicad_plugins/trace_solder_expander/soldermask_clearance_help.svg b/kicad_plugins/trace_solder_expander/soldermask_clearance_help.svg new file mode 100644 index 00000000..f311a284 --- /dev/null +++ b/kicad_plugins/trace_solder_expander/soldermask_clearance_help.svg @@ -0,0 +1,199 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + exp + + + + diff --git a/kicad_plugins/trace_solder_expander/trace_solder_expander.py b/kicad_plugins/trace_solder_expander/trace_solder_expander.py new file mode 100755 index 00000000..43c4cc92 --- /dev/null +++ b/kicad_plugins/trace_solder_expander/trace_solder_expander.py @@ -0,0 +1,666 @@ +#!/usr/bin/env python + +# Copyright 2019 Maurice https://github.com/easyw/ + +# some source tips @ +# https://github.com/bpkempke/kicad-scripts +# https://github.com/MitjaNemec/Kicad_action_plugins +# https://github.com/jsreynaud/kicad-action-scripts + +# GNU GENERAL PUBLIC LICENSE +# Version 3, 29 June 2007 +# +# Copyright (C) 2007 Free Software Foundation, Inc. +# Everyone is permitted to copy and distribute verbatim copies +# of this license document, but changing it is not allowed. +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + + +# some source tips @ +# https://github.com/bpkempke/kicad-scripts +# https://github.com/MitjaNemec/Kicad_action_plugins +# https://github.com/jsreynaud/kicad-action-scripts + +# import trace_solder_expansion; reload(trace_solder_expansion) + +import sys +import os +from pcbnew import * +import wx +import pcbnew +import math +import uuid + +debug = False #True +def wxLogDebug(msg,show): + """printing messages only if show is omitted or True""" + if show: + wx.LogMessage(msg) +# +def find_pcbnew_w(): + windows = wx.GetTopLevelWindows() + pcbneww = [w for w in windows if "pcbnew" in w.GetTitle().lower()] + if len(pcbneww) != 1: + return None + return pcbneww[0] +# + +#if (sys.version[0]) == '2': +# from .SolderExpanderDlg import SolderExpanderDlg +#else: +# from .SolderExpanderDlg_py3 import SolderExpanderDlg_y3 +#from .SolderExpanderDlg import SolderExpanderDlg +from . import SolderExpanderDlg + +ToUnits=pcbnew.ToMM #ToMils +FromUnits=pcbnew.FromMM #Mils + +global discretize +discretize = False +# import trace_solder_expansion; reload(trace_solder_expansion) + +# Python plugin stuff + +class SolderExpander_Dlg(SolderExpanderDlg.SolderExpanderDlg): + # from https://github.com/MitjaNemec/Kicad_action_plugins + # hack for new wxFormBuilder generating code incompatible with old wxPython + # noinspection PyMethodOverriding + def SetSizeHints(self, sz1, sz2): + if sys.version_info[0] == 2: + # wxPython 2 + self.SetSizeHintsSz(sz1, sz2) + else: + # wxPython 3 + super(SolderExpander_Dlg, self).SetSizeHints(sz1, sz2) + + def onDeleteClick(self, event): + return self.EndModal(wx.ID_DELETE) + + def __init__(self, parent): + global discretize + SolderExpanderDlg.SolderExpanderDlg.__init__(self, parent) + self.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) + self.SetMinSize(self.GetSize()) + #if self.m_checkBoxD.IsChecked(): + # discretize = True + # #wx.LogMessage(str(discretize) + ' 0') + #else: + # discretize = False + +# + +class Solder_Expander(pcbnew.ActionPlugin): + def defaults(self): + self.name = "Solder Mask Expander for Tracks\n version 2.3" + self.category = "Modify PCB" + self.description = "Solder Mask Expander for selected Tracks on the PCB" + self.icon_file_name = os.path.join(os.path.dirname(__file__), "./soldermask_clearance.png") + self.show_toolbar_button = True + + def Warn(self, message, caption='Warning!'): + dlg = wx.MessageDialog( + None, message, caption, wx.OK | wx.ICON_WARNING) + dlg.ShowModal() + dlg.Destroy() + + def CheckInput(self, value, data): + val = None + try: + val = float(value.replace(',','.')) + if val <= 0: + raise Exception("Invalid") + except: + self.Warn( + "Invalid parameter for %s: Must be a positive number" % data) + val = None + return val + + def Run(self): + #import pcbnew + #pcb = pcbnew.GetBoard() + # net_name = "GND" + #aParameters = SolderExpanderDlg(None) + # _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetTitle().lower().startswith('pcbnew')][0] + global discretize + + # _pcbnew_frame = [x for x in wx.GetTopLevelWindows() if x.GetName() == 'PcbFrame'][0] + pcbnew_window = find_pcbnew_w() + aParameters = SolderExpander_Dlg(pcbnew_window) + aParameters.m_clearanceMM.SetValue("0.2") + aParameters.m_bitmap1.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "soldermask_clearance_help.png") ) ) + pcb = pcbnew.GetBoard() + if not(hasattr(pcbnew,'DRAWSEGMENT')): + #if hasattr(pcb, 'm_Uuid'): + aParameters.m_buttonDelete.Disable() + aParameters.m_buttonDelete.Hide() + aParameters.m_staticText1011.Hide() + aParameters.m_checkBoxD.SetToolTip( u"check this to discretize arcs with segments" ) + #if aParameters.m_checkBoxD.IsChecked(): + # discretize = True + # wx.LogMessage(str(discretize) + ' 1') + #else: + # discretize = False + else: + aParameters.m_checkBoxD.Hide() + aParameters.m_staticText10111.Hide() + modal_result = aParameters.ShowModal() + clearance = FromMM(self.CheckInput(aParameters.m_clearanceMM.GetValue(), "extra clearance from track width")) + + if not(hasattr(pcbnew,'DRAWSEGMENT')): + #if hasattr(pcb, 'm_Uuid'): + aParameters.m_buttonDelete.Disable() + aParameters.m_buttonDelete.Hide() + aParameters.m_staticText1011.Hide() + discretize = aParameters.m_checkBoxD.GetValue() + #if aParameters.m_checkBoxD.IsChecked(): + # discretize = True + # wx.LogMessage(str(discretize) + ' 1') + #else: + # discretize = False + + if clearance is not None: + if modal_result == wx.ID_OK: + #pcb = pcbnew.GetBoard() + tracks=getSelTracks(pcb) + arcs=getSelArcs(pcb) + if len(tracks) >0 or len(arcs) >0 : #selected tracks >0 + solderExpander(pcb,tracks,clearance) + solderExpander(pcb,arcs,clearance) + else: + pads=[] + for item in pcb.GetPads(): + if item.IsSelected(): + pads.append(item) + if len(pads) == 1: + tracks=[] + tracks = find_Tracks_inNet_Pad(pcb,pads[0]) + c_tracks = get_contiguous_tracks(pcb,tracks,pads[0]) + solderExpander(pcb,c_tracks,clearance) + solderExpander(pcb,arcs,clearance) + else: + wx.LogMessage("Solder Mask Expander:\nSelect Tracks\nor One Pad to select connected Tracks") + + #solderExpander(clearance) + elif modal_result == wx.ID_DELETE: + Delete_Segments(pcb) + #wx.LogMessage('Solder Mask Segments on Track Net Deleted') + else: + None # Cancel + else: + None # Invalid input + aParameters.Destroy() +# +def selectListTracks(pcb,tracks): + for item in tracks: + if type(item) is TRACK: + item.SetSelected() +# +# +#def getSelTracksLength(pcb): +# ln = 0. +# for item in pcb.GetTracks(): +# if type(item) is pcbnew.TRACK and item.IsSelected(): +# ln+=(item.GetLength()) +# return(ln) +# #print(pcbnew.ToMM(ln)) +# +def get_contiguous_tracks(pcb,trks,pad): + LinePoints = [] + LineSegments=[] + + #start_point = ToMM(pad.GetPosition()) + startp = (pad.GetPosition()) + start_point = ((startp.x),(startp.y)) + for t in (trks): + LinePoints.append((t.GetStart().x,t.GetStart().y)) + LinePoints.append((t.GetEnd().x, t.GetEnd().y)) + wxLogDebug('Points '+str(LinePoints),debug) + l= len(LinePoints) + for i in range(0,l,2): + LineSegments.append((LinePoints[i],LinePoints[i+1])) + wxLogDebug(str(LineSegments),debug) + + #segments = [(1, 2), (2, 3), (4, 5), (6, 5), (7, 6)] + #start_point=(4,5) + #segments_start=segments + + segments = LineSegments + groups=[] + found=False + for s in segments: + found=False + for g in groups: + for sCmp in g: + wxLogDebug('sCmp: '+(str(sCmp)),debug) + wxLogDebug('s: '+(str(s)),debug) + if isConn(sCmp,s): #confronto start e end + g.append(s) + found=True + break; + if (found): + break; + if(not found): + groups.append([s]) + wxLogDebug('groups: '+(str(groups)),debug) + wxLogDebug('len groups: '+(str(len(groups))),debug) + l = 0 + lens = [] + for g in groups: + lens.append(len(g)) + if l= 1: #1nm + return True + else: + return False +# +# Function to find the circle on +# which the given three points lie +def getCircleCenterRadius(sp,ep,ip): + # findCircle(x1, y1, x2, y2, x3, y3) : + # NB add always set float even if values are pcb internal Units!!! + x1 = float(sp.x); y1 = float(sp.y) + x2 = float(ep.x); y2 = float(ep.y) + x3 = float(ip.x); y3 = float(ip.y) + + x12 = x1 - x2; + x13 = x1 - x3; + y12 = y1 - y2; + y13 = y1 - y3; + y31 = y3 - y1; + y21 = y2 - y1; + x31 = x3 - x1; + x21 = x2 - x1; + + # x1^2 - x3^2 + sx13 = math.pow(x1, 2) - math.pow(x3, 2); + # y1^2 - y3^2 + sy13 = math.pow(y1, 2) - math.pow(y3, 2); + sx21 = math.pow(x2, 2) - math.pow(x1, 2); + sy21 = math.pow(y2, 2) - math.pow(y1, 2); + + f = (((sx13) * (x12) + (sy13) * + (x12) + (sx21) * (x13) + + (sy21) * (x13)) // (2 * + ((y31) * (x12) - (y21) * (x13)))); + + g = (((sx13) * (y12) + (sy13) * (y12) + + (sx21) * (y13) + (sy21) * (y13)) // + (2 * ((x31) * (y12) - (x21) * (y13)))); + + c = (-math.pow(x1, 2) - math.pow(y1, 2) - 2 * g * x1 - 2 * f * y1); + + # eqn of circle be x^2 + y^2 + 2*g*x + 2*f*y + c = 0 + # where centre is (h = -g, k = -f) and + # radius r as r^2 = h^2 + k^2 - c + h = -g; + k = -f; + sqr_of_r = h * h + k * k - c; + # r is the radius + r = round(math.sqrt(sqr_of_r), 5); + Cx = h + Cy = k + radius = r + return wxPoint(Cx,Cy), radius +# +def create_Solder(pcb,p1,p2,lyr=None,w=None,Nn=None,Ts=None,pcbG=None): + #draw segment to test or from Arc + #new_line = pcbnew.DRAWSEGMENT(pcb) + if hasattr(pcbnew,'TRACK'): + new_line = pcbnew.TRACK(pcb) + else: + #new_shape = pcbnew.S_SEGMENT() + new_line = PCB_SHAPE() + # new_shape = pcbnew.PCB_SHAPE() + # new_line = pcbnew.Cast_to_PCB_SHAPE(new_shape) + #new_soldermask_shape = PCB_SHAPE() + #new_soldermask_line = pcbnew.Cast_to_PCB_SHAPE(new_soldermask_shape) + #new_line = PCB_TRACK(new_shape) + + new_line.SetStart(p1) + new_line.SetEnd(p2) + if w is None: + new_line.SetWidth(FromUnits(1.5)) #FromUnits(int(mask_width))) + else: + #wx.LogMessage(str(w)) + new_line.SetWidth(w) #FromUnits(w)) + if lyr is None: + lyr = F_SilkS + elif lyr is pcbnew.F_Cu: + lyr is pcbnew.F_Mask + elif lyr is pcbnew.B_Cu: + lyr is pcbnew.B_Mask + # if Nn is not None: + # new_line.SetNet(Nn) + # #new_line.SetNetname(Nn) + new_line.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer)) + if Ts is not None and hasattr(pcbnew,'TRACK'): + tsc = 0 + Nname = new_line.GetNetname() + for c in Nname: + tsc = tsc + ord(c) + if hasattr(new_line, 'SetTimeStamp'): + new_line.SetTimeStamp(tsc) # adding a unique number (this netname) as timestamp to mark this segment as generated by this script on this netname + pcb.Add(new_line) + if pcbG is not None: + pcbG.AddItem(new_line) + + return new_line +# +def solderExpander(pcb,tracks,clearance): + global discretize + # wx.LogMessage(str(discretize) + ' 2') + mask_width = clearance #FromMM(.5) # msk espansion value each side + #mask_layer = pcbnew.F_Mask + + # pcb = LoadBoard(in_filename) + #pcb = pcbnew.GetBoard() + + #ToUnits=pcbnew.ToMM #ToMils + #FromUnits=pcbnew.FromMM #Mils + + for item in tracks: + start = item.GetStart() + end = item.GetEnd() + width = item.GetWidth() + layerId = item.GetLayer() + layer = item.GetLayerSet() + layerN = item.GetLayerName() + layer = pcb.GetLayerID(layerN) + track_net_name = item.GetNetname() + ts = 0 + for c in track_net_name: + ts = ts + ord(c) + #wx.LogMessage("LayerName"+str(layer)) + + if layerId == pcbnew.F_Cu: + mask_layer = pcbnew.F_Mask + elif layerId == pcbnew.B_Cu: #'B_Cu': + mask_layer = pcbnew.B_Mask + else: #we shouldn't arrive here + mask_layer = pcbnew.F_Mask + wxLogDebug(" * Track: %s to %s, width %f mask_width %f" % (ToUnits(start),ToUnits(end),ToUnits(width), ToUnits(mask_width)),debug) + #print (" * Track: %s to %s, width %f mask_width %f" % (ToUnits(start),ToUnits(end),ToUnits(width), ToUnits(mask_width))) + if hasattr(pcbnew,'DRAWSEGMENT'): + new_soldermask_line = pcbnew.DRAWSEGMENT(pcb) + new_soldermask_line.SetStart(start) + new_soldermask_line.SetEnd(end) + new_soldermask_line.SetWidth(width+2*mask_width) #FromUnits(int(mask_width))) + new_soldermask_line.SetLayer(mask_layer) #pcbnew.F_Mask) #pcb.GetLayerID(mask_layer)) + # again possible to mark via as own since no timestamp_t binding kicad v5.1.4 + if hasattr(new_soldermask_line, 'SetTimeStamp'): + new_soldermask_line.SetTimeStamp(ts) # adding a unique number (this netname) as timestamp to mark this via as generated by this script on this netname + pcb.Add(new_soldermask_line) + elif type(item) is pcbnew.PCB_TRACK: #kicad 5.99 + #new_soldermask_shape = PCB_SHAPE() + #new_soldermask_line = pcbnew.Cast_to_PCB_SHAPE(new_soldermask_shape) + new_soldermask_line = PCB_SHAPE() + new_soldermask_line.SetStart(start) + new_soldermask_line.SetEnd(end) + new_soldermask_line.SetWidth(width+2*mask_width) + new_soldermask_line.SetLayer(mask_layer) #pcbnew.F_Mask) #pcb.GetLayerID(mask_layer)) + # again possible to mark via as own since no timestamp_t binding kicad v5.1.4 + if hasattr(new_soldermask_line, 'SetTimeStamp'): + new_soldermask_line.SetTimeStamp(ts) # adding a unique number (this netname) as timestamp to mark this via as generated by this script on this netname + pcb.Add(new_soldermask_line) + else: #PCB_ARC kicad 5.99 + #new_soldermask_line = PCB_ARC(PCB_SHAPE()) + #new_soldermask_line.SetMid(item.GetMid()) + #wxLogDebug(str(item.GetMid())+' mid',True) + md = item.GetMid() + #wxLogDebug(str(cnt)+' center, radius '+str(rad),True) + netName = None + width_new = width +2*mask_width + cnt, rad = getCircleCenterRadius(start,end,md) + if discretize: + segNBR = 16 + groupName = uuid.uuid4() #randomword(5) + pcb_group = pcbnew.PCB_GROUP(None) + pcb_group.SetName(groupName) + pcb.Add(pcb_group) + create_round_segs(pcb,start,end,cnt,rad,mask_layer,width_new,netName,segNBR,pcb_group) + else: + createDwgArc(pcb,start,end,md,cnt,mask_layer,width_new,netName) + #break; + pcbnew.Refresh() +# +def createDwgArc(pcb,p1,p2,mp,cn,lyr=None,w=None,Nn=None,Ts=None): + # new_arc = pcbnew.PCB_SHAPE() + # new_arc = pcbnew.Cast_to_PCB_SHAPE(new_arc) + # new_arc.SetShape(pcbnew.SHAPE_T_ARC) + # new_arc.SetStart(p1) + # new_arc.SetMid(md) + # new_arc.SetEnd(p2) + # new_arc.SetWidth(w) #250000) + + new_arc=pcbnew.PCB_SHAPE() + new_arc.SetShape(pcbnew.SHAPE_T_ARC) + use_geo=True + if use_geo: + # new_arc.SetArcGeometry(aStart: 'wxPoint', aMid: 'wxPoint', aEnd: 'wxPoint') + new_arc.SetArcGeometry(p1,mp,p2) + else: + new_arc.SetArcStart(p1) + new_arc.SetArcEnd(p2) + new_arc.SetCenter(cn) + new_arc.SetWidth(w) + if lyr is None: + lyr = F_SilkS + new_arc.SetLayer(lyr) #pcbnew.F_SilkS) #pcb.GetLayerID(mask_layer)) + pcb.Add(new_arc) + return new_arc +# +def getAngleRadians(p1,p2): + #return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x))) + return (math.atan2((p1.y-p2.y),(p1.x-p2.x))) +# + +def rotatePoint(r,sa,da,c): + # sa, da in radians + x = c.x - math.cos(sa+da) * r + y = c.y - math.sin(sa+da) * r + return wxPoint(x,y) +# +def create_round_segs(pcb,sp,ep,cntr,rad,layer,width,Nn,N_SEGMENTS,pcbGroup=None): + start_point = sp + end_point = ep + pos = sp + next_pos = ep + a1 = getAngleRadians(cntr,sp) + a2 = getAngleRadians(cntr,ep) + wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug) + if (a2-a1) > 0 and abs(a2-a1) > math.radians(180): + deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS + wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug) + elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180): + deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS + wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug) + else: + deltaA = (a2-a1)/N_SEGMENTS + delta=deltaA + wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug) + points = [] + #import round_trk; import importlib; importlib.reload(round_trk) + for ii in range (N_SEGMENTS+1): #+1): + points.append(pos) + #t = create_Track(pos,pos) + prv_pos = pos + #pos = pos + fraction_delta + #posPolar = cmath.polar(pos) + #(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi. + #pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y) + pos = rotatePoint(rad,a1,delta,cntr) + delta=delta+deltaA + #wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug) + for i, p in enumerate(points): + #if i < len (points)-1: + if i < len (points)-2: + t = create_Solder(pcb,p,points[i+1],layer,width,Nn,True,pcbGroup) #adding ts code to segments + t = create_Solder(pcb,points[-2],ep,layer,width,Nn,True,pcbGroup) #avoiding rounding on last segment +# +def Delete_Segments(pcb): + draws = [] + #print ("TRACKS WHICH MATCH CRITERIA:") + for item in pcb.GetDrawings(): + #for item in pcb.GetTracks(): + if type(item) is DRAWSEGMENT and item.IsSelected(): #item.GetNetname() == net_name: + draws.append(item) + wxLogDebug(str(len(draws)),debug) + + if len (draws) == 1: + tsd = draws[0].GetTimeStamp() + wxLogDebug(str(tsd),debug) + if tsd != 0: + target_draws = filter(lambda x: (x.GetTimeStamp() == tsd), pcb.GetDrawings()) + #wx.LogMessage(str(len(target_tracks))) + target_draws_cp = list(target_draws) + for i in range(l): + pcb.RemoveNative(target_draws_cp[i]) + #for draw in target_draws: + # #if via.GetTimeStamp() == 55: + # pcb.RemoveNative(draw) + #wx.LogMessage('removing via') + #pcbnew.Refresh() + wxLogDebug(u'\u2714 Mask Segments Deleted',True) + else: + wxLogDebug(u'\u2718 you must select only Mask segment\n generated by this tool',not debug) + else: + #msg = u'\n\u2714 Radius > 3 * (track width)' + wxLogDebug(u'\u2718 you must select One Mask segment only',not debug) +# +#Solder_Expander().register() + diff --git a/kicad_plugins/tracks_length/__init__.py b/kicad_plugins/tracks_length/__init__.py new file mode 100644 index 00000000..e032c744 --- /dev/null +++ b/kicad_plugins/tracks_length/__init__.py @@ -0,0 +1,2 @@ +from .trace_length import SelectedTracesLenght +SelectedTracesLenght().register() diff --git a/kicad_plugins/tracks_length/trace_length.png b/kicad_plugins/tracks_length/trace_length.png new file mode 100644 index 00000000..fe5c410e Binary files /dev/null and b/kicad_plugins/tracks_length/trace_length.png differ diff --git a/kicad_plugins/tracks_length/trace_length.py b/kicad_plugins/tracks_length/trace_length.py new file mode 100644 index 00000000..41de5a7b --- /dev/null +++ b/kicad_plugins/tracks_length/trace_length.py @@ -0,0 +1,337 @@ +#!/usr/bin/env python + +# some source tips @ +# https://github.com/bpkempke/kicad-scripts +# https://github.com/MitjaNemec/Kicad_action_plugins +# https://github.com/jsreynaud/kicad-action-scripts + + +# import trace_length; reload(trace_length) + +import sys +import os +from pcbnew import * +import wx +import pcbnew +import math +#import threading + +debug = False +def wxLogDebug(msg,dbg): + """printing messages only if show is omitted or True""" + if dbg == True: + wx.LogMessage(msg) +# + +def getSelTracksLength(pcb): + ln = 0. + for item in pcb.GetTracks(): + if not hasattr(pcbnew,'TRACK'): + item = pcbnew.Cast_to_PCB_TRACK(item) + trktp = pcbnew.PCB_TRACK + else: + trktp = pcbnew.TRACK + if type(item) is trktp and item.IsSelected(): + ln+=(item.GetLength()) + return(ln) + #print(pcbnew.ToMM(ln)) +# +def getSelTracks(pcb): + tracks=[] + for item in pcb.GetTracks(): + if not hasattr(pcbnew,'TRACK'): + item = pcbnew.Cast_to_PCB_TRACK(item) + trktp = pcbnew.PCB_TRACK + else: + trktp = pcbnew.TRACK + if type(item) is trktp and item.IsSelected(): + tracks.append(item) + return tracks +# +def find_Tracks_between_Pads(pcb,pad1,pad2): + track_list = [] + # get list of all selected pads + #selected_pads = [pad1, pad2] + # get the net the pins are on + net = pad1.GetNetname() + # find all tracks + tracks = pcb.GetTracks() + # find all tracks on net + tracks_on_net = [] + for track in tracks: + track_net_name = track.GetNetname() + if track_net_name == net: + tracks_on_net.append(track) + return tracks_on_net +# + +def getTracksListLength(pcb,tracks): + ln = 0. + for item in tracks: + ln+=(item.GetLength()) + return(ln) +# +def selectListTracks(pcb,tracks): + for item in tracks: + if not hasattr(pcbnew,'TRACK'): + item = pcbnew.Cast_to_PCB_TRACK(item) + trktp = pcbnew.PCB_TRACK + else: + trktp = pcbnew.TRACK + if type(item) is trktp: + item.SetSelected() +# +def getTrackAngleRadians(track): + #return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x))) + return (math.atan2((track.GetEnd().y - track.GetStart().y), (track.GetEnd().x - track.GetStart().x))) +# + +# Python plugin stuff +class SelectedTracesLenght(pcbnew.ActionPlugin): + def defaults(self): + self.name = "Measure Length for Selected Tracks\n version 1.3" + self.category = "Modify PCB" + self.description = "Measure Length for Selected Tracks" + self.icon_file_name = os.path.join(os.path.dirname(__file__), "./trace_length.png") + self.show_toolbar_button = True + + def Run(self): + #self.pcb = GetBoard() + pcb = pcbnew.GetBoard() + ln=0. + pads=[] + tracks=getSelTracks(pcb) + if len(tracks) >0: #selected tracks >0 + for item in tracks: + ln+=(item.GetLength()) + else: + for item in pcb.GetPads(): + if item.IsSelected(): + pads.append(item) + if len(pads) == 1: + tracks=[] + tracks = find_Tracks_inNet_Pad(pcb,pads[0]) + c_tracks = get_contiguous_tracks(pcb,tracks,pads[0]) + tracks=c_tracks + # selectListTracks(pcb,tracks) # this seems not to allow deselecting + ln = getTracksListLength(pcb,tracks) + selectListTracks(pcb,tracks) + pcbnew.Refresh() + + #else: + # wx.LogMessage("Solder Mask Expander:\nSelect Tracks\nor One Pad to select connected Tracks") + if ln > 0: + #wx.LogMessage('Selected Traces Length: {0:.3f} mm'.format(ToMM(ln))) + wxLogDebug('showing Selected Tracks',debug) + #wx.LogMessage('debug'+str(debug)) + msg = u"Selected Tracks Length:\n{0:.3f} mm \u2714".format(ToMM(ln)) + if len(tracks) == 1: + angle = (math.degrees(getTrackAngleRadians(tracks[0]))) + msg+=u"\nTrack Angle: {0:.1f} deg \u2714".format(angle) + #selectListTracks(pcb,tracks) + #pcbnew.Refresh() + wdlg = wx.MessageDialog(None, msg,'Info message',wx.OK | wx.ICON_INFORMATION) + result = wdlg.ShowModal() + if result == wx.ID_OK: + pass + clearListTracks(pcb,tracks,True) + #timer = threading.Timer(1000, clearListTracks(pcb,tracks,True)) + #timer.start() + #blocking dialogw + #wx.MessageBox("showing selection", 'Info', wx.OK | wx.ICON_INFORMATION) + #clearListTracks(pcb,tracks) + elif len(pads) != 1: + wx.LogMessage('Select Tracks to calculate the Length\nor One Pad to select connected Tracks') +# + + +def selectListTracks(pcb,tracks): + for item in tracks: + if not hasattr(pcbnew,'TRACK'): + item = pcbnew.Cast_to_PCB_TRACK(item) + trktp = pcbnew.PCB_TRACK + else: + trktp = pcbnew.TRACK + if type(item) is trktp: + item.SetSelected() + +def clearListTracks(pcb,tracks,refresh=None): + wxLogDebug('deSelecting Tracks',debug) + for trk in tracks: + if trk.IsSelected(): + trk.ClearSelected() + if refresh: + pcbnew.Refresh() +# +# +#def getSelTracksLength(pcb): +# ln = 0. +# for item in pcb.GetTracks(): +# if type(item) is pcbnew.TRACK and item.IsSelected(): +# ln+=(item.GetLength()) +# return(ln) +# #print(pcbnew.ToMM(ln)) +# +def get_contiguous_tracks(pcb,trks,pad): + LinePoints = [] + LineSegments=[] + + #start_point = ToMM(pad.GetPosition()) + startp = (pad.GetPosition()) + start_point = ((startp.x),(startp.y)) + for t in (trks): + LinePoints.append((t.GetStart().x,t.GetStart().y)) + LinePoints.append((t.GetEnd().x, t.GetEnd().y)) + wxLogDebug('Points '+str(LinePoints),debug) + l= len(LinePoints) + for i in range(0,l,2): + LineSegments.append((LinePoints[i],LinePoints[i+1])) + wxLogDebug(str(LineSegments),debug) + + #segments = [(1, 2), (2, 3), (4, 5), (6, 5), (7, 6)] + #start_point=(4,5) + #segments_start=segments + + segments = LineSegments + groups=[] + found=False + for s in segments: + found=False + for g in groups: + for sCmp in g: + wxLogDebug('sCmp: '+(str(sCmp)),debug) + wxLogDebug('s: '+(str(s)),debug) + if isConn(sCmp,s): #confronto start e end + g.append(s) + found=True + break; + if (found): + break; + if(not found): + groups.append([s]) + wxLogDebug('groups: '+(str(groups)),debug) + wxLogDebug('len groups: '+(str(len(groups))),debug) + l = 0 + lens = [] + for g in groups: + lens.append(len(g)) + if l= 1: #1nm + return True + else: + return False +# +def isConn(s1,s2): + #if s1[0] == s2[0] or s1[1] == s2[1]: + if isEq(s1[0],s2[0]) or isEq(s1[1],s2[1]): + return True + #elif s1[0] == s2[1] or s1[1] == s2[0]: + elif isEq(s1[0],s2[1]) or isEq(s1[1],s2[0]): + return True + return False +# + +def getSelTracks(pcb): + tracks=[] + for item in pcb.GetTracks(): + if not hasattr(pcbnew,'TRACK'): + item = pcbnew.Cast_to_PCB_TRACK(item) + trktp = pcbnew.PCB_TRACK + else: + trktp = pcbnew.TRACK + if type(item) is trktp and item.IsSelected(): + tracks.append(item) + return tracks +# +def find_Tracks_inNet_Pad(pcb,pad): + track_list = [] + # get list of all selected pads + #selected_pads = [pad1, pad2] + # get the net the pins are on + net = pad.GetNetname() + # find all tracks + tracks = pcb.GetTracks() + # find all tracks on net + tracks_on_net = [] + for track in tracks: + track_net_name = track.GetNetname() + if track_net_name == net: + tracks_on_net.append(track) + return tracks_on_net +# + +#Solder_Expander().register() + diff --git a/kicad_plugins/tracks_length/trace_length.svg b/kicad_plugins/tracks_length/trace_length.svg new file mode 100644 index 00000000..edde25cd --- /dev/null +++ b/kicad_plugins/tracks_length/trace_length.svg @@ -0,0 +1,182 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kicad_plugins/via_fence_generator/__init__.py b/kicad_plugins/via_fence_generator/__init__.py new file mode 100644 index 00000000..7a2429ac --- /dev/null +++ b/kicad_plugins/via_fence_generator/__init__.py @@ -0,0 +1,9 @@ +# pcbnew loads this folder as a package using import +# thus __init__.py (this file) is executed +# We import the plugin class here and register it to pcbnew + +from .viafence_action import ViaFenceAction +ViaFenceAction().register() + + + diff --git a/kicad_plugins/via_fence_generator/__main__.py b/kicad_plugins/via_fence_generator/__main__.py new file mode 100644 index 00000000..719749bf --- /dev/null +++ b/kicad_plugins/via_fence_generator/__main__.py @@ -0,0 +1,120 @@ +from .viafence import * +from .viafence_dialogs import * + +import os +import argparse +import json +import numpy as np +import matplotlib.pyplot as plt +import wx +import copy + +argParser = argparse.ArgumentParser() +argParser.add_argument("--dialog", dest="dialog", metavar="DIALOGNAME", help="Show Dialog with ") +argParser.add_argument("--runtests", dest="runtests", action="store_true", default=0, help="Execute testing all json test files in 'tests' subdirectory") +argParser.add_argument("--test", dest="test", metavar="TESTNAME", help="Loads from 'tests' directory, runs it and shows/stores the result into the test file") +argParser.add_argument("--store", dest="store", action="store_true", default=0, help="When running a test, stores the result as known-good") +argParser.add_argument("--verbose", dest="verbose", action="store_true", default=0, help="Verbose plotting the inner workings of the algorithm") +args = argParser.parse_args() + +def compareTests(testDict, refDict): + testPts = testDict['viaPoints'] + refPts = refDict['viaPoints'] + matchedPts = [point for point in testPts if point in refPts] + return True if len(testPts) == len(refPts) == len(matchedPts) else False + +def loadTest(testFilename): + with open(testFilename, 'r') as file: + return json.load(file) + +def storeTest(testFilename, testDict): + with open(testFilename, 'w') as file: + json.dump(testDict, file, indent=4, sort_keys=True) + +def runTest(testDict, verboseFunc): + viaOffset = testDict['viaOffset'] + viaPitch = testDict['viaPitch'] + pathList = testDict['pathList'] + + newDict = copy.deepcopy(testDict) + newDict['viaPoints'] = generateViaFence(pathList, viaOffset, viaPitch, verboseFunc) + + return newDict + +def printTestResult(testName, refDict, testDict): + print("{}: {} (Ref/Test Vias: {}/{})".format( + testName, "PASSED" if compareTests(refDict, testDict) else "FAILED", + len(refDict['viaPoints']), len(testDict['viaPoints']) )) + +def verbosePlot(object, isPoints = False, isPaths = False, isPolygons = False): + import numpy as np + import matplotlib.pyplot as plt + for child in object: + data = np.array(child) + if isPolygons: + plt.fill(data.T[0], data.T[1], facecolor='grey', alpha=0.3, linestyle='--', linewidth=1) + elif isPaths: + plt.plot(data.T[0], data.T[1], linestyle='-', linewidth=3) + elif isPoints: + plt.plot(data.T[0], data.T[1], linestyle='', marker='x', markersize=10, mew=3) + +def main(): + testDir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'tests') + verboseFunc = verbosePlot if args.verbose else lambda *args,**kwargs:None + + if (args.dialog): + # Load and show dialog +# os.chdir(os.path.dirname(os.path.realpath(__file__))) + app = wx.App() + className = globals()[args.dialog] + className(None).Show() + print("Starting wxApp Now. Exit using Ctrl+C") + app.MainLoop() + + elif (args.test): + # Load a test file, run the algorithm and show/store the result for later testing + testFile = os.path.join(testDir, args.test) + ".json" + ref = loadTest(testFile) + test = runTest(ref, verboseFunc) + + printTestResult(args.test, ref, test) + + if (args.store): storeTest(testFile, test) + + for path in test['pathList']: + plt.plot(np.array(path).T[0], np.array(path).T[1], linewidth=5) + + for via in test['viaPoints']: + plt.plot(via[0], via[1], 'o', markersize=10) + + plt.axes().set_aspect('equal','box') + plt.ylim(plt.ylim()[::-1]) + plt.savefig(os.path.join(testDir, args.test) + '.png') + plt.show() + elif (args.runtests): + # Run all tests in 'tests' subdirectory + scriptDir = os.path.dirname(os.path.realpath(__file__)) + testDir = scriptDir + "/" + 'tests' + testsPassed = 0 + testsTotal = 0 + + for file in os.listdir(testDir): + if file.endswith(".json"): + testName = os.path.basename(file) + ref = loadTest(os.path.join(testDir, file)) + test = runTest(ref, verboseFunc) + + printTestResult(testName, ref, test) + + if compareTests(ref, test): testsPassed += 1 + testsTotal += 1 + + print("----\n{}/{} tests PASSED".format(testsPassed, testsTotal)) + + assert testsPassed == testsTotal + + if testsPassed == testsTotal: exit(0) + else: exit(1) + + +main() diff --git a/kicad_plugins/via_fence_generator/python-pyclipper/py2-7-linux-64/pyclipper.so b/kicad_plugins/via_fence_generator/python-pyclipper/py2-7-linux-64/pyclipper.so new file mode 100755 index 00000000..f468b6fc Binary files /dev/null and b/kicad_plugins/via_fence_generator/python-pyclipper/py2-7-linux-64/pyclipper.so differ diff --git a/kicad_plugins/via_fence_generator/python-pyclipper/py2-7-mac-64/pyclipper.so b/kicad_plugins/via_fence_generator/python-pyclipper/py2-7-mac-64/pyclipper.so new file mode 100644 index 00000000..722a6332 Binary files /dev/null and b/kicad_plugins/via_fence_generator/python-pyclipper/py2-7-mac-64/pyclipper.so differ diff --git a/kicad_plugins/via_fence_generator/python-pyclipper/py2-7-win-64/pyclipper.pyd b/kicad_plugins/via_fence_generator/python-pyclipper/py2-7-win-64/pyclipper.pyd new file mode 100644 index 00000000..5eb36836 Binary files /dev/null and b/kicad_plugins/via_fence_generator/python-pyclipper/py2-7-win-64/pyclipper.pyd differ diff --git a/kicad_plugins/via_fence_generator/python-pyclipper/py3-6-linux-64/pyclipper.cpython-36m-x86_64-linux-gnu.so b/kicad_plugins/via_fence_generator/python-pyclipper/py3-6-linux-64/pyclipper.cpython-36m-x86_64-linux-gnu.so new file mode 100755 index 00000000..0cb64597 Binary files /dev/null and b/kicad_plugins/via_fence_generator/python-pyclipper/py3-6-linux-64/pyclipper.cpython-36m-x86_64-linux-gnu.so differ diff --git a/kicad_plugins/via_fence_generator/resources/fencing-vias.png b/kicad_plugins/via_fence_generator/resources/fencing-vias.png new file mode 100644 index 00000000..2b954c4b Binary files /dev/null and b/kicad_plugins/via_fence_generator/resources/fencing-vias.png differ diff --git a/kicad_plugins/via_fence_generator/resources/fencing-vias.svg b/kicad_plugins/via_fence_generator/resources/fencing-vias.svg new file mode 100644 index 00000000..4a495fa7 --- /dev/null +++ b/kicad_plugins/via_fence_generator/resources/fencing-vias.svg @@ -0,0 +1,204 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/kicad_plugins/via_fence_generator/resources/viafence.png b/kicad_plugins/via_fence_generator/resources/viafence.png new file mode 100644 index 00000000..56e603e8 Binary files /dev/null and b/kicad_plugins/via_fence_generator/resources/viafence.png differ diff --git a/kicad_plugins/via_fence_generator/resources/viafence.svg b/kicad_plugins/via_fence_generator/resources/viafence.svg new file mode 100644 index 00000000..50e27f7c --- /dev/null +++ b/kicad_plugins/via_fence_generator/resources/viafence.svg @@ -0,0 +1,536 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + +   + Offset + + + + + + + + + + Pitch + Via Size + + + Via Drill + + + + diff --git a/kicad_plugins/via_fence_generator/resources/viafence_dialogs.fbp b/kicad_plugins/via_fence_generator/resources/viafence_dialogs.fbp new file mode 100644 index 00000000..824981f4 --- /dev/null +++ b/kicad_plugins/via_fence_generator/resources/viafence_dialogs.fbp @@ -0,0 +1,1623 @@ + + + + + + Python + 1 + source_name + 0 + 0 + res + UTF-8 + connect + viafence_basedialogs + 1000 + none + + 0 + viafence_basedialogs + + .. + + 1 + 1 + 1 + 1 + UI + 0 + 0 + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + -1,-1 + -1,-1 + MainDialogBase + + 503,567 + wxCAPTION|wxCLOSE_BOX|wxRESIZE_BORDER + + Via Fence Generator + + + + + OnInitDialog + + + mainSizer + wxVERTICAL + none + + 5 + wxEXPAND + 1 + + + wxBOTH + 0 + + 0 + + gbSizer4 + wxFLEX_GROWMODE_SPECIFIED + none + 0 + + 5 + 1 + 0 + wxEXPAND + 0 + 1 + + + bSizer23 + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + wxID_ANY + Via Settings + + sbSizer2 + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + 2 + wxBOTH + 1 + + 0 + + fgSizer4 + wxFLEX_GROWMODE_SPECIFIED + none + 8 + 0 + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Offset (mm): + 0 + + 0 + + + 0 + + 1 + m_staticText11 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + -1,-1 + 1 + txtViaOffset + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER|wxTE_RIGHT + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Pitch (mm): + 0 + + 0 + + + 0 + + 1 + m_staticText21 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + txtViaPitch + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER|wxTE_RIGHT + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Via Drill (mm): + 0 + + 0 + + + 0 + + 1 + m_staticText13 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + txtViaDrill + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER|wxTE_RIGHT + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Via Size (mm): + 0 + + 0 + + + 0 + + 1 + m_staticText14 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxEXPAND|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + + 0 + + 1 + txtViaSize + 1 + + + protected + 1 + + Resizable + 1 + + wxTE_PROCESS_ENTER|wxTE_RIGHT + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Via Net: + 0 + + 0 + + + 0 + + 1 + m_staticText23 + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + + + -1 + + + + 5 + wxEXPAND|wxALL + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + lstViaNet + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + 5 + 1 + 1 + wxEXPAND|wxALL + 0 + 1 + + + bSizer21 + wxVERTICAL + none + + 5 + + 0 + + 9 + protected + 0 + + + + 5 + wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + bmpViafence + 1 + + + protected + 1 + + Resizable + 1 + + + 0 + + + + + + + + + + 5 + 1 + 0 + wxALL|wxEXPAND + 1 + 1 + + wxID_ANY + Input Tracks + + sbSizer411 + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 0 + + 1 + 0 + + gSizer4 + none + 3 + 0 + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Include Selected + + 0 + + + 0 + + 1 + chkIncludeSelection + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Include Drawing Lines + + 0 + + + 0 + + 1 + chkIncludeDrawing + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxEXPAND|wxALIGN_CENTER_VERTICAL + 1 + + 2 + wxHORIZONTAL + 1 + + 10 + + fgSizer311 + wxFLEX_GROWMODE_SPECIFIED + none + 1 + 0 + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Net(s): + + 0 + + + 0 + + 1 + chkNetFilter + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnNetFilterCheckBox + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + + 0 + -1,-1 + + 0 + + 1 + txtNetFilter + 1 + + + protected + 1 + + Resizable + -1 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + Combo! + + + + + + + + + 5 + wxEXPAND|wxALIGN_CENTER_VERTICAL + 1 + + 2 + wxHORIZONTAL + 1 + + 10 + + fgSizer31 + wxFLEX_GROWMODE_SPECIFIED + none + 1 + 0 + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Layer: + + 0 + + + 0 + + 1 + chkLayer + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + OnLayerCheckBox + + + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + + 1 + + 1 + 0 + Dock + 0 + Left + 0 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + + 0 + + 1 + lstLayer + 1 + + + protected + 1 + + Resizable + 0 + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + 5 + 1 + 1 + wxEXPAND|wxALL + 1 + 1 + + wxID_ANY + Output VIAs + + sbSizer4 + wxVERTICAL + 1 + none + + 5 + wxEXPAND + 1 + + 1 + 0 + + gSizer2 + none + 3 + 0 + + 5 + wxEXPAND|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Keep VIAs in Via Net zones only + + 0 + + + 0 + + 1 + chkSameNetZoneViasOnly + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Remove VIAs violating clearance rules + + 0 + + + 0 + + 1 + chkRemoveViasWithClearanceViolation + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxALIGN_CENTER|wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + + 1 + 0 + 1 + + 1 + + 0 + 0 + + Dock + 0 + Left + 1 + + 1 + + + 0 + 0 + wxID_ANY + Delete Vias + + 0 + + 0 + + + 0 + + 1 + m_buttonDelete + 1 + + + protected + 1 + + + + Resizable + 1 + + + ; ; forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + 5 + wxEXPAND + 0 + + + bSizer5 + wxHORIZONTAL + none + + 5 + wxALL|wxEXPAND + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Debug Dump + + 0 + + + 0 + + 1 + chkDebugDump + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + + + 5 + wxEXPAND|wxALL + 0 + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer1 + protected + + + + + + + + diff --git a/kicad_plugins/via_fence_generator/tests/diffms.json b/kicad_plugins/via_fence_generator/tests/diffms.json new file mode 100644 index 00000000..1ad34ce2 --- /dev/null +++ b/kicad_plugins/via_fence_generator/tests/diffms.json @@ -0,0 +1,140 @@ +{ + "pathList": [ + [ + [ + -2000, + 250 + ], + [ + 2000, + 250 + ] + ], + [ + [ + -2000, + -250 + ], + [ + 2000, + -250 + ] + ] + ], + "viaOffset": 1000, + "viaPitch": 300, + "viaPoints": [ + [ + -2000, + -1250 + ], + [ + 2000, + -1250 + ], + [ + -1692.3076923076924, + -1250.0 + ], + [ + -1384.6153846153848, + -1250.0 + ], + [ + -1076.923076923077, + -1250.0 + ], + [ + -769.2307692307693, + -1250.0 + ], + [ + -461.53846153846143, + -1250.0 + ], + [ + -153.8461538461538, + -1250.0 + ], + [ + 153.8461538461538, + -1250.0 + ], + [ + 461.53846153846143, + -1250.0 + ], + [ + 769.230769230769, + -1250.0 + ], + [ + 1076.9230769230771, + -1250.0 + ], + [ + 1384.6153846153848, + -1250.0 + ], + [ + 1692.3076923076924, + -1250.0 + ], + [ + 2000, + 1250 + ], + [ + -2000, + 1250 + ], + [ + 1692.3076923076924, + 1250.0 + ], + [ + 1384.6153846153848, + 1250.0 + ], + [ + 1076.923076923077, + 1250.0 + ], + [ + 769.2307692307693, + 1250.0 + ], + [ + 461.53846153846143, + 1250.0 + ], + [ + 153.8461538461538, + 1250.0 + ], + [ + -153.8461538461538, + 1250.0 + ], + [ + -461.53846153846143, + 1250.0 + ], + [ + -769.230769230769, + 1250.0 + ], + [ + -1076.9230769230771, + 1250.0 + ], + [ + -1384.6153846153848, + 1250.0 + ], + [ + -1692.3076923076924, + 1250.0 + ] + ] +} \ No newline at end of file diff --git a/kicad_plugins/via_fence_generator/tests/diffms.png b/kicad_plugins/via_fence_generator/tests/diffms.png new file mode 100644 index 00000000..f009c2cb Binary files /dev/null and b/kicad_plugins/via_fence_generator/tests/diffms.png differ diff --git a/kicad_plugins/via_fence_generator/tests/diffms2.json b/kicad_plugins/via_fence_generator/tests/diffms2.json new file mode 100644 index 00000000..dbf0ba23 --- /dev/null +++ b/kicad_plugins/via_fence_generator/tests/diffms2.json @@ -0,0 +1,140 @@ +{ + "pathList": [ + [ + [ + -2000, + 500 + ], + [ + 2000, + 500 + ] + ], + [ + [ + -2000, + -500 + ], + [ + 2000, + -500 + ] + ] + ], + "viaOffset": 500, + "viaPitch": 300, + "viaPoints": [ + [ + -2000, + -1000 + ], + [ + 2000, + -1000 + ], + [ + -1692.3076923076924, + -1000.0 + ], + [ + -1384.6153846153848, + -1000.0 + ], + [ + -1076.923076923077, + -1000.0 + ], + [ + -769.2307692307693, + -1000.0 + ], + [ + -461.53846153846143, + -1000.0 + ], + [ + -153.8461538461538, + -1000.0 + ], + [ + 153.8461538461538, + -1000.0 + ], + [ + 461.53846153846143, + -1000.0 + ], + [ + 769.230769230769, + -1000.0 + ], + [ + 1076.9230769230771, + -1000.0 + ], + [ + 1384.6153846153848, + -1000.0 + ], + [ + 1692.3076923076924, + -1000.0 + ], + [ + 2000, + 1000 + ], + [ + -2000, + 1000 + ], + [ + 1692.3076923076924, + 1000.0 + ], + [ + 1384.6153846153848, + 1000.0 + ], + [ + 1076.923076923077, + 1000.0 + ], + [ + 769.2307692307693, + 1000.0 + ], + [ + 461.53846153846143, + 1000.0 + ], + [ + 153.8461538461538, + 1000.0 + ], + [ + -153.8461538461538, + 1000.0 + ], + [ + -461.53846153846143, + 1000.0 + ], + [ + -769.230769230769, + 1000.0 + ], + [ + -1076.9230769230771, + 1000.0 + ], + [ + -1384.6153846153848, + 1000.0 + ], + [ + -1692.3076923076924, + 1000.0 + ] + ] +} \ No newline at end of file diff --git a/kicad_plugins/via_fence_generator/tests/diffms2.png b/kicad_plugins/via_fence_generator/tests/diffms2.png new file mode 100644 index 00000000..d025ad54 Binary files /dev/null and b/kicad_plugins/via_fence_generator/tests/diffms2.png differ diff --git a/kicad_plugins/via_fence_generator/tests/non-diffms.json b/kicad_plugins/via_fence_generator/tests/non-diffms.json new file mode 100644 index 00000000..800d4c0c --- /dev/null +++ b/kicad_plugins/via_fence_generator/tests/non-diffms.json @@ -0,0 +1,252 @@ +{ + "pathList": [ + [ + [ + -2000, + 501 + ], + [ + 2000, + 501 + ] + ], + [ + [ + -2000, + -501 + ], + [ + 2000, + -501 + ] + ] + ], + "viaOffset": 500, + "viaPitch": 300, + "viaPoints": [ + [ + -2000, + 1 + ], + [ + 2000, + 1 + ], + [ + -1692.3076923076924, + 1.0 + ], + [ + -1384.6153846153848, + 1.0 + ], + [ + -1076.923076923077, + 1.0 + ], + [ + -769.2307692307693, + 1.0 + ], + [ + -461.53846153846143, + 1.0 + ], + [ + -153.8461538461538, + 1.0 + ], + [ + 153.8461538461538, + 1.0 + ], + [ + 461.53846153846143, + 1.0 + ], + [ + 769.230769230769, + 1.0 + ], + [ + 1076.9230769230771, + 1.0 + ], + [ + 1384.6153846153848, + 1.0 + ], + [ + 1692.3076923076924, + 1.0 + ], + [ + 2000, + 1001 + ], + [ + -2000, + 1001 + ], + [ + 1692.3076923076924, + 1001.0 + ], + [ + 1384.6153846153848, + 1001.0 + ], + [ + 1076.923076923077, + 1001.0 + ], + [ + 769.2307692307693, + 1001.0 + ], + [ + 461.53846153846143, + 1001.0 + ], + [ + 153.8461538461538, + 1001.0 + ], + [ + -153.8461538461538, + 1001.0 + ], + [ + -461.53846153846143, + 1001.0 + ], + [ + -769.230769230769, + 1001.0 + ], + [ + -1076.9230769230771, + 1001.0 + ], + [ + -1384.6153846153848, + 1001.0 + ], + [ + -1692.3076923076924, + 1001.0 + ], + [ + -2000, + -1001 + ], + [ + 2000, + -1001 + ], + [ + -1692.3076923076924, + -1001.0 + ], + [ + -1384.6153846153848, + -1001.0 + ], + [ + -1076.923076923077, + -1001.0 + ], + [ + -769.2307692307693, + -1001.0 + ], + [ + -461.53846153846143, + -1001.0 + ], + [ + -153.8461538461538, + -1001.0 + ], + [ + 153.8461538461538, + -1001.0 + ], + [ + 461.53846153846143, + -1001.0 + ], + [ + 769.230769230769, + -1001.0 + ], + [ + 1076.9230769230771, + -1001.0 + ], + [ + 1384.6153846153848, + -1001.0 + ], + [ + 1692.3076923076924, + -1001.0 + ], + [ + 2000, + -1 + ], + [ + -2000, + -1 + ], + [ + 1692.3076923076924, + -1.0 + ], + [ + 1384.6153846153848, + -1.0 + ], + [ + 1076.923076923077, + -1.0 + ], + [ + 769.2307692307693, + -1.0 + ], + [ + 461.53846153846143, + -1.0 + ], + [ + 153.8461538461538, + -1.0 + ], + [ + -153.8461538461538, + -1.0 + ], + [ + -461.53846153846143, + -1.0 + ], + [ + -769.230769230769, + -1.0 + ], + [ + -1076.9230769230771, + -1.0 + ], + [ + -1384.6153846153848, + -1.0 + ], + [ + -1692.3076923076924, + -1.0 + ] + ] +} \ No newline at end of file diff --git a/kicad_plugins/via_fence_generator/tests/non-diffms.png b/kicad_plugins/via_fence_generator/tests/non-diffms.png new file mode 100644 index 00000000..9f1e6686 Binary files /dev/null and b/kicad_plugins/via_fence_generator/tests/non-diffms.png differ diff --git a/kicad_plugins/via_fence_generator/tests/simple-test.json b/kicad_plugins/via_fence_generator/tests/simple-test.json new file mode 100644 index 00000000..007c1e2d --- /dev/null +++ b/kicad_plugins/via_fence_generator/tests/simple-test.json @@ -0,0 +1,434 @@ +{ + "viaOffset": 500, + "viaPitch": 300, + "viaPoints": [ + [ + 2000, + 4500 + ], + [ + 1500, + 1792 + ], + [ + 1500, + 500 + ], + [ + 309, + 500 + ], + [ + -2000, + 2500 + ], + [ + 1694.7494045294795, + 4500.0 + ], + [ + 1389.498809058959, + 4500.0 + ], + [ + 1084.2482135884386, + 4500.0 + ], + [ + 778.9976181179181, + 4500.0 + ], + [ + 473.74702264739767, + 4500.0 + ], + [ + 168.4964271768772, + 4500.0 + ], + [ + -134.97345240050308, + 4481.007964279849 + ], + [ + -386.4640053423498, + 4316.612565323029 + ], + [ + -498.26181546785324, + 4037.810952514348 + ], + [ + -430.1165855145392, + 3745.243988758386 + ], + [ + -226.75812814749332, + 3518.758128147493 + ], + [ + -10.91336212905685, + 3302.9133621290566 + ], + [ + 204.93140388938002, + 3087.06859611062 + ], + [ + 420.7761699078168, + 2871.223830092183 + ], + [ + 636.6209359262533, + 2655.3790640737466 + ], + [ + 852.4657019446897, + 2439.5342980553105 + ], + [ + 1068.3104679631263, + 2223.689532036874 + ], + [ + 1284.1552339815635, + 2007.8447660184365 + ], + [ + 1500.0, + 1469.0 + ], + [ + 1500.0, + 1146.0 + ], + [ + 1500.0, + 823.0 + ], + [ + 1103.0, + 500.0 + ], + [ + 706.0, + 500.0 + ], + [ + 167.49497119958997, + 783.0100576008201 + ], + [ + 25.989942399179938, + 1066.0201152016402 + ], + [ + -115.51508640123012, + 1349.0301728024601 + ], + [ + -257.0201152016401, + 1632.0402304032802 + ], + [ + -398.5251440020502, + 1915.0502880041004 + ], + [ + -540.0301728024602, + 2198.0603456049203 + ], + [ + -746.9452985193672, + 2430.745362085551 + ], + [ + -1050.755409332653, + 2500.0 + ], + [ + -1367.1702728884356, + 2500.0 + ], + [ + -1683.5851364442178, + 2500.0 + ], + [ + -2000, + 1500 + ], + [ + -1309, + 1500 + ], + [ + -609, + 99 + ], + [ + -2354, + -1646 + ], + [ + -1654.5, + 1500.0 + ], + [ + -1169.0, + 1219.8 + ], + [ + -1029.0, + 939.6 + ], + [ + -889.0, + 659.4 + ], + [ + -749.0, + 379.20000000000005 + ], + [ + -827.125, + -119.125 + ], + [ + -1045.25, + -337.25 + ], + [ + -1263.375, + -555.375 + ], + [ + -1481.5, + -773.5 + ], + [ + -1699.625, + -991.625 + ], + [ + -1917.75, + -1209.75 + ], + [ + -2135.875, + -1427.8750000000002 + ], + [ + -1646, + -2354 + ], + [ + 208, + -500 + ], + [ + 1208, + 3500 + ], + [ + 2000, + 3500 + ], + [ + -1414.25, + -2122.25 + ], + [ + -1182.5, + -1890.5 + ], + [ + -950.75, + -1658.75 + ], + [ + -719.0, + -1427.0 + ], + [ + -487.25, + -1195.25 + ], + [ + -255.5, + -963.5 + ], + [ + -23.75, + -731.75 + ], + [ + 521.8262211985277, + -500.0 + ], + [ + 835.6524423970556, + -500.0 + ], + [ + 1149.4786635955834, + -500.0 + ], + [ + 1463.304884794111, + -500.0 + ], + [ + 1777.1311059926388, + -500.0 + ], + [ + 2090.442225924456, + -491.57383452831357 + ], + [ + 2361.7526198249857, + -344.44044291024215 + ], + [ + 2495.659716859078, + -66.30975547371793 + ], + [ + 2500.0, + 247.3274095922838 + ], + [ + 2500.0, + 561.1536307908112 + ], + [ + 2500.0, + 874.9798519893395 + ], + [ + 2500.0, + 1188.806073187867 + ], + [ + 2500.0, + 1502.632294386395 + ], + [ + 2500.0, + 1816.4585155849227 + ], + [ + 2482.8669417451197, + 2128.7768608496017 + ], + [ + 2317.5432456181425, + 2390.4567543818575 + ], + [ + 2095.6345964945144, + 2612.3654035054856 + ], + [ + 1873.7259473708855, + 2834.2740526291145 + ], + [ + 1651.817298247257, + 3056.182701752743 + ], + [ + 1429.908649123629, + 3278.091350876371 + ], + [ + 1604.0, + 3500.0 + ], + [ + 1000, + -2500 + ], + [ + 2000, + -2500 + ], + [ + 1333.3333333333333, + -2500.0 + ], + [ + 1666.6666666666665, + -2500.0 + ], + [ + 2000, + -1500 + ], + [ + 1000, + -1500 + ], + [ + 1666.6666666666667, + -1500.0 + ], + [ + 1333.3333333333335, + -1500.0 + ] + ], + "pathList": [ + [ + [ + -2000, + -2000 + ], + [ + 0, + 0 + ], + [ + 2000, + 0 + ], + [ + 2000, + 2000 + ], + [ + 0, + 4000 + ], + [ + 2000, + 4000 + ] + ], + [ + [ + 0, + 0 + ], + [ + -1000, + 2000 + ], + [ + -2000, + 2000 + ] + ], + [ + [ + 2000, + -2000 + ], + [ + 1000, + -2000 + ] + ] + ] +} \ No newline at end of file diff --git a/kicad_plugins/via_fence_generator/tests/simple-test.png b/kicad_plugins/via_fence_generator/tests/simple-test.png new file mode 100644 index 00000000..ea0af863 Binary files /dev/null and b/kicad_plugins/via_fence_generator/tests/simple-test.png differ diff --git a/kicad_plugins/via_fence_generator/viafence.py b/kicad_plugins/via_fence_generator/viafence.py new file mode 100644 index 00000000..dbc3decb --- /dev/null +++ b/kicad_plugins/via_fence_generator/viafence.py @@ -0,0 +1,386 @@ +#!/usr/bin/env python + +# Copyright 2017 Simon Kuppers https://github.com/skuep/ +# Copyright 2019 Maurice https://github.com/easyw/ + +# original plugin https://github.com/skuep/kicad-plugins +# some source tips @ +# https://github.com/MitjaNemec/Kicad_action_plugins +# https://github.com/jsreynaud/kicad-action-scripts + +# GNU GENERAL PUBLIC LICENSE +# Version 3, 29 June 2007 +# +# Copyright (C) 2007 Free Software Foundation, Inc. +# Everyone is permitted to copy and distribute verbatim copies +# of this license document, but changing it is not allowed. +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. + +import math +#import pyclipper +from bisect import bisect_left +import wx +import pcbnew + +def verbose(object, *args, **kwargs): + global verboseFunc + verboseFunc(object, *args, **kwargs) + +# Returns the slope of a line +def getLineSlope(line): + return math.atan2(line[0][1]-line[1][1], line[0][0]-line[1][0]) + +# Returns the length of a line +def getLineLength(line): + return math.hypot(line[0][0]-line[1][0], line[0][1]-line[1][1]) + +# Returns a sub path in a path with a path specification (startIdx, stopIdx) +def getSubPath(path, pathSpec): + listModulus = len(path) + if (pathSpec[1] < pathSpec[0]): pathSpec[1] += listModulus + return [path[i % listModulus] for i in range(pathSpec[0], pathSpec[1]+1)] + +# Returns a list of subpaths with a list of path specifications +def getSubPaths(path, pathSpecList): + return [getSubPath(path, pathSpec) for pathSpec in pathSpecList if (pathSpec[0] != pathSpec[1])] + +# Splits a path using a list of indices representing points on the path +def splitPathByPoints(path, splitList): + pathSpecList = [[splitList[item], splitList[item+1]] for item in range(0, len(splitList)-1)] + return getSubPaths(path, pathSpecList) + +# Splits a path around a list of list of indices representing a subpath within the original path +def splitPathByPaths(path, splitList): + pathSpecList = [[splitList[item][-1], splitList[(item+1)%len(splitList)][0]] for item in range(0, len(splitList))] + return getSubPaths(path, pathSpecList) + +# Return a cumulative distance vector representing the distance travelled along +# the path at each path vertex +def getPathCumDist(path): + cumDist = [0.0] + for vertexId in range(1, len(path)): + cumDist += [cumDist[-1] + getLineLength([path[vertexId], path[vertexId-1]])] + + return cumDist + +# Return a list of all vertex indices where the angle between +# the two lines connected to the vertex deviate from a straight +# path more by the tolerance angle in degrees +# This function is used to find bends that are larger than a certain angle +def getPathVertices(path, angleTolerance): + angleTolerance = angleTolerance * math.pi / 180 + vertices = [] + + # Look through all vertices except start and end vertex + # Calculate by how much the lines before and after the vertex + # deviate from a straight path. + # If the deviation angle exceeds the specification, store it + for vertexIdx in range(1, len(path)-1): + prevSlope = getLineSlope([path[vertexIdx+1], path[vertexIdx]]) + nextSlope = getLineSlope([path[vertexIdx-1], path[vertexIdx]]) + deviationAngle = abs(prevSlope - nextSlope) - math.pi + if (abs(deviationAngle) > angleTolerance): + vertices += [vertexIdx] + + return vertices + +# Uses the cross product to check if a point is on a line defined by two other points +def isPointOnLine(point, line): + cross = (line[1][1] - point[1]) * (line[0][0] - point[0]) - (line[1][0] - point[0]) * (line[0][1] - point[1]) + + if ( ((line[0][0] <= point[0] <= line[1][0]) or (line[1][0] <= point[0] <= line[0][0])) + and ((line[0][1] <= point[1] <= line[1][1]) or (line[1][1] <= point[1] <= line[0][1])) + and (cross == 0) ): + return True + return False + +# Returns a list of path indices touching any item in a list of points +def getPathsThroughPoints(path, pointList): + touchingPaths = [] + + for vertexIdx in range(0, len(path)): + fromIdx = vertexIdx + toIdx = (vertexIdx+1) % len(path) + + # If a point in the pointList is located on this line, store the line + for point in pointList: + if isPointOnLine(point, [ path[fromIdx], path[toIdx] ]): + touchingPaths += [[fromIdx, toIdx]] + break + + return touchingPaths + +# A small linear interpolation class so we don't rely on scipy or numpy here +class LinearInterpolator(object): + def __init__(self, x_list, y_list): + self.x_list, self.y_list = x_list, y_list + intervals = zip(x_list, x_list[1:], y_list, y_list[1:]) + self.slopes = [(y2 - y1)/(x2 - x1) for x1, x2, y1, y2 in intervals] + def __call__(self, x): + i = bisect_left(self.x_list, x) - 1 + return self.y_list[i] + self.slopes[i] * (x - self.x_list[i]) + +# Interpolate a path with (x,y) vertices using a third parameter t +class PathInterpolator: + def __init__(self, t, path): + # Quick and dirty transpose path so we get two list with x and y coords + # And set up two separate interpolators for them + x = [vertex[0] for vertex in path] + y = [vertex[1] for vertex in path] + self.xInterp = LinearInterpolator(t, x) + self.yInterp = LinearInterpolator(t, y) + def __call__(self, t): + # Return interpolated coordinates on the original path + return [self.xInterp(t), self.yInterp(t)] + +# A small pyclipper wrapper class to expand a line to a polygon with a given offset +def expandPathsToPolygons(pathList, offset): + import pyclipper + # Use PyclipperOffset to generate polygons that surround the original + # paths with a constant offset all around + co = pyclipper.PyclipperOffset() + for path in pathList: co.AddPath(path, pyclipper.JT_ROUND, pyclipper.ET_OPENROUND) + return co.Execute(offset) + +# A small pyclipper wrapper to trim parts of a polygon using another polygon +def clipPolygonWithPolygons(path, clipPathList): + import pyclipper + pc = pyclipper.Pyclipper() + pc.AddPath(path, pyclipper.PT_SUBJECT, True) + for clipPath in clipPathList: pc.AddPath(clipPath, pyclipper.PT_CLIP, True) + return pc.Execute(pyclipper.CT_DIFFERENCE) + +def unionPolygons(pathList): + import pyclipper + pc = pyclipper.Pyclipper() + for path in pathList: pc.AddPath(path, pyclipper.PT_SUBJECT, True) + return pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_NONZERO) + +def isPointInPolygon(point, path): + import pyclipper + return True if (pyclipper.PointInPolygon(point, path) == 1) else False + +def getPathsInsidePolygon(pathList, polygon): + filteredPathList = [] + + for path in pathList: + allVerticesInside = True + for vertex in path: + if not isPointInPolygon(vertex, polygon): + allVerticesInside = False + break + if (allVerticesInside): filteredPathList += [path] + + return filteredPathList + +# Distribute Points along a path with equal spacing to each other +# When the path length is not evenly dividable by the minimumSpacing, +# the actual spacing will be larger, but still smaller than 2*minimumSpacing +# The function does not return the start and end vertex of the path +def distributeAlongPath(path, minimumSpacing): + # Get cumulated distance vector for the path + # and determine the number of points that can fit to the path + distList = getPathCumDist(path) + nPoints = int(math.floor(distList[-1] / minimumSpacing)) + ptInterp = PathInterpolator(distList, path) + return [ptInterp(ptIdx * distList[-1]/nPoints) for ptIdx in range(1, nPoints)] + +# Find the leaf vertices in a list of paths, +# additionally it calculates the slope of the line connected to the leaf vertex +def getLeafVertices(pathList): + allVertices = [vertex for path in pathList for vertex in path] + leafVertices = [] + leafVertexSlopes = [] + + for path in pathList: + for vertexIdx in [0,-1]: + if (allVertices.count(path[vertexIdx]) == 1): + # vertex appears only once in entire path list, store away + # Get neighbour vertex and also calculate the slope + leafVertex = path[vertexIdx] + neighbourVertex = path[ [1,-2][vertexIdx] ] + leafVertices += [leafVertex] + leafVertexSlopes += [getLineSlope([neighbourVertex, leafVertex])] + + return leafVertices, leafVertexSlopes + +# Rotate and Translate a list of vertices using a given angle and offset +def transformVertices(vertexList, offset, angle): + return [ [ round(offset[0] + math.cos(angle) * vertex[0] - math.sin(angle) * vertex[1]), + round(offset[1] + math.sin(angle) * vertex[0] + math.cos(angle) * vertex[1]) ] + for vertex in vertexList] + +# Trims a polygon flush around the given vertices +def trimFlushPolygonAtVertices(path, vertexList, vertexSlopes, radius): + const = 0.414 + trimPoly = [ [0, -radius], [0, 0], [0, radius], [-const*radius, radius], [-radius, const*radius], + [-radius, -const*radius], [-const*radius, -radius] ] + trimPolys = [transformVertices(trimPoly, vertexPos, vertexSlope) + for vertexPos, vertexSlope in zip(vertexList, vertexSlopes)] + + trimPolys = unionPolygons(trimPolys) + + verbose(trimPolys, isPolygons=True) + + return clipPolygonWithPolygons(path, trimPolys) + +###################### +def generateViaFence(pathList, viaOffset, viaPitch, vFunc = lambda *args,**kwargs:None): + global verboseFunc + verboseFunc = vFunc + viaPoints = [] + + # Remove zero length tracks + pathList = [path for path in pathList if getLineLength(path) > 0] + + # Expand the paths given as a parameter into one or more polygons + # using the offset parameter + for offsetPoly in expandPathsToPolygons(pathList, viaOffset): + verbose([offsetPoly], isPolygons=True) + # Filter the input path to only include paths inside this polygon + # Find all leaf vertices and use them to trim the expanded polygon + # around the leaf vertices so that we get a flush, flat end + # These butt lines are then found using the leaf vertices + # and used to split open the polygon into multiple separate open + # paths that envelop the original path + localPathList = getPathsInsidePolygon(pathList, offsetPoly) + if len(localPathList) == 0: continue # This might happen with very bad input paths + + leafVertexList, leafVertexAngles = getLeafVertices(localPathList) + offsetPoly = trimFlushPolygonAtVertices(offsetPoly, leafVertexList, leafVertexAngles, 1.1*viaOffset)[0] + buttLineIdxList = getPathsThroughPoints(offsetPoly, leafVertexList) + fencePaths = splitPathByPaths(offsetPoly, buttLineIdxList) + + verbose([offsetPoly], isPolygons=True) + verbose([leafVertexList], isPoints=True) + verbose(fencePaths, isPaths=True) + + # With the now separated open paths we perform via placement on each one of them + for fencePath in fencePaths: + # For a nice via fence placement, we identify vertices that differ from a straight + # line by more than 10 degrees so we find all non-arc edges + # We combine these points with the start and end point of the path and use + # them to place fixed vias on their positions + tolerance_degree = 10 + fixPointIdxList = [0] + getPathVertices(fencePath, tolerance_degree) + [-1] + fixPointList = [fencePath[idx] for idx in fixPointIdxList] + verbose(fixPointList, isPoints=True) + + viaPoints += fixPointList + # Then we autoplace vias between the fixed via locations by satisfying the + # minimum via pitch given by the user + for subPath in splitPathByPoints(fencePath, fixPointIdxList): + viaPoints += distributeAlongPath(subPath, viaPitch) + + return viaPoints + +def create_round_pts(sp,ep,cntr,rad,layer,width,Nn,N_SEGMENTS): + start_point = sp + end_point = ep + pos = sp + next_pos = ep + a1 = getAngleRadians(cntr,sp) + a2 = getAngleRadians(cntr,ep) + #wxLogDebug('a1:'+str(math.degrees(a1))+' a2:'+str(math.degrees(a2))+' a2-a1:'+str(math.degrees(a2-a1)),debug) + if (a2-a1) > 0 and abs(a2-a1) > math.radians(180): + deltaA = -(math.radians(360)-(a2-a1))/N_SEGMENTS + #wxLogDebug('deltaA reviewed:'+str(math.degrees(deltaA)),debug) + elif (a2-a1) < 0 and abs(a2-a1) > math.radians(180): + deltaA = (math.radians(360)-abs(a2-a1))/N_SEGMENTS + #wxLogDebug('deltaA reviewed2:'+str(math.degrees(deltaA)),debug) + else: + deltaA = (a2-a1)/N_SEGMENTS + delta=deltaA + #wxLogDebug('delta:'+str(math.degrees(deltaA))+' radius:'+str(ToMM(rad)),debug) + points = [] + #import round_trk; import importlib; importlib.reload(round_trk) + for ii in range (N_SEGMENTS+1): #+1): + points.append(pos) + #t = create_Track(pos,pos) + prv_pos = pos + #pos = pos + fraction_delta + #posPolar = cmath.polar(pos) + #(rad) * cmath.exp(math.radians(deltaA)*1j) #cmath.rect(r, phi) : Return the complex number x with polar coordinates r and phi. + #pos = wxPoint(posPolar.real+sp.x,posPolar.imag+sp.y) + pos = rotatePoint(rad,a1,delta,cntr) + delta=delta+deltaA + #wxLogDebug("pos:"+str(ToUnits(prv_pos.x))+":"+str(ToUnits(prv_pos.y))+";"+str(ToUnits(pos.x))+":"+str(ToUnits(pos.y)),debug) + return points + #if 0: + # for i, p in enumerate(points): + # #if i < len (points)-1: + # if i < len (points)-2: + # t = create_Solder(pcb,p,points[i+1],layer,width,Nn,True,pcbGroup) #adding ts code to segments + # t = create_Solder(pcb,points[-2],ep,layer,width,Nn,True,pcbGroup) #avoiding rounding on last segment +# +# Function to find the circle on +# which the given three points lie +def getCircleCenterRadius(sp,ep,ip): + # findCircle(x1, y1, x2, y2, x3, y3) : + # NB add always set float even if values are pcb internal Units!!! + x1 = float(sp.x); y1 = float(sp.y) + x2 = float(ep.x); y2 = float(ep.y) + x3 = float(ip.x); y3 = float(ip.y) + + x12 = x1 - x2; + x13 = x1 - x3; + y12 = y1 - y2; + y13 = y1 - y3; + y31 = y3 - y1; + y21 = y2 - y1; + x31 = x3 - x1; + x21 = x2 - x1; + + # x1^2 - x3^2 + sx13 = math.pow(x1, 2) - math.pow(x3, 2); + # y1^2 - y3^2 + sy13 = math.pow(y1, 2) - math.pow(y3, 2); + sx21 = math.pow(x2, 2) - math.pow(x1, 2); + sy21 = math.pow(y2, 2) - math.pow(y1, 2); + + f = (((sx13) * (x12) + (sy13) * + (x12) + (sx21) * (x13) + + (sy21) * (x13)) // (2 * + ((y31) * (x12) - (y21) * (x13)))); + + g = (((sx13) * (y12) + (sy13) * (y12) + + (sx21) * (y13) + (sy21) * (y13)) // + (2 * ((x31) * (y12) - (x21) * (y13)))); + + c = (-math.pow(x1, 2) - math.pow(y1, 2) - 2 * g * x1 - 2 * f * y1); + + # eqn of circle be x^2 + y^2 + 2*g*x + 2*f*y + c = 0 + # where centre is (h = -g, k = -f) and + # radius r as r^2 = h^2 + k^2 - c + h = -g; + k = -f; + sqr_of_r = h * h + k * k - c; + # r is the radius + r = round(math.sqrt(sqr_of_r), 5); + Cx = h + Cy = k + radius = r + return wx.Point(Cx,Cy), radius +# +def getAngleRadians(p1,p2): + #return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x))) + return (math.atan2((p1.y-p2.y),(p1.x-p2.x))) +# +def rotatePoint(r,sa,da,c): + # sa, da in radians + x = c.x - math.cos(sa+da) * r + y = c.y - math.sin(sa+da) * r + return wx.Point(x,y) \ No newline at end of file diff --git a/kicad_plugins/via_fence_generator/viafence_action.py b/kicad_plugins/via_fence_generator/viafence_action.py new file mode 100755 index 00000000..248c1337 --- /dev/null +++ b/kicad_plugins/via_fence_generator/viafence_action.py @@ -0,0 +1,639 @@ +#!/usr/bin/env python + +# Implementation of the action plugin derived from pcbnew.ActionPlugin +import pcbnew +import os +import sys +import re +import time +import json +import math +import wx +import uuid + +from collections import OrderedDict +from .viafence import * +from .viafence_dialogs import * + +debug = False +temporary_fix = True + +def wxLogDebug(msg,show): + """printing messages only if show is omitted or True""" + if show: + wx.LogMessage(msg) +# +def getTrackAngleRadians(track): + #return math.degrees(math.atan2((p1.y-p2.y),(p1.x-p2.x))) + return (math.atan2((track.GetEnd().y - track.GetStart().y), (track.GetEnd().x - track.GetStart().x))) +# + +def distance (p1,p2): + return math.hypot(p1.y-p2.y,p1.x-p2.x) + +class ViaFenceAction(pcbnew.ActionPlugin): + # ActionPlugin descriptive information + def defaults(self): + self.name = "Via Fence Generator\nversion 2.8" + self.category = "Modify PCB" + self.description = "Add a via fence to nets or tracks on the board" + self.icon_file_name = os.path.join(os.path.dirname(__file__), "resources/fencing-vias.png") + self.show_toolbar_button = True + + def dumpJSON(self, file): + dict = { + 'pathList': self.pathList, + 'viaOffset': self.viaOffset, + 'viaPitch': self.viaPitch, + 'viaPoints': self.viaPoints if hasattr(self, 'viaPoints') else [] + } + with open(file, 'w') as file: + json.dump(dict, file, indent=4, sort_keys=True) + + # Return an ordered {layerId: layerName} dict of enabled layers + def getLayerMap(self): + layerMap = [] + for i in list(range(pcbnew.PCB_LAYER_ID_COUNT)): + if self.boardObj.IsLayerEnabled(i): + layerMap += [[i, self.boardObj.GetLayerName(i)]] + return OrderedDict(layerMap) + + # Return an ordered {netCode: netName} dict of nets in the board + def getNetMap(self): + netMap = OrderedDict(self.boardObj.GetNetsByNetcode()) + netMap.pop(0) # TODO: What is Net 0? + return netMap + + # Generates a list of net filter phrases using the local netMap + # Currently all nets are included as filter phrases + # Additionally, differential Nets get a special filter phrase + def createNetFilterSuggestions(self): + netFilterList = ['*'] + netList = [self.netMap[item].GetNetname() for item in self.netMap] + diffMap = {'+': '-', 'P': 'N', '-': '+', 'N': 'P'} + regexMap = {'+': '[+-]', '-': '[+-]', 'P': '[PN]', 'N': '[PN]'} + invertDiffNet = lambda netName : netName[0:-1] + diffMap[netName[-1]] + isDiffNet = lambda netName : True if netName[-1] in diffMap.keys() else False + + # Translate board nets into a filter list + for netName in netList: + if isDiffNet(netName) and invertDiffNet(netName) in netList: + # If we have a +/- or P/N pair, we insert a regex entry once into the filter list + filterText = netName[0:-1] + regexMap[netName[-1]] + if (filterText not in netFilterList): netFilterList += [filterText] + + # Append every net to the filter list + netFilterList += [netName] + + return netFilterList + + # Generates a RegEx string from a SimpleEx (which is a proprietary invention ;-)) + # The SimpleEx only supports [...] with single chars and * used as a wildcard + def regExFromSimpleEx(self, simpleEx): + # Escape the entire filter string. Unescape and remap specific characters that we want to allow + subsTable = {r'\[':'[', r'\]':']', r'\*':'.*'} + regEx = re.escape(simpleEx) + for subsFrom, subsTo in subsTable.items(): regEx = regEx.replace(subsFrom, subsTo) + return regEx + + def createVias(self, viaPoints, viaDrill, viaSize, netCode): + newVias = [] + for viaPoint in viaPoints: + if not(hasattr(pcbnew,'DRAWSEGMENT')): + newVia = pcbnew.PCB_VIA(self.boardObj) + else: + newVia = pcbnew.VIA(self.boardObj) + if hasattr(newVia, 'SetTimeStamp'): + ts = 55 + newVia.SetTimeStamp(ts) # adding a unique number as timestamp to mark this via as generated by this script + self.boardObj.Add(newVia) + + newVia.SetPosition(pcbnew.wxPoint(viaPoint[0], viaPoint[1])) + newVia.SetWidth(viaSize) + newVia.SetDrill(viaDrill) + if hasattr(pcbnew, 'VIA_THROUGH'): + newVia.SetViaType(pcbnew.VIA_THROUGH) + else: + newVia.SetViaType(pcbnew.VIATYPE_THROUGH) + newVia.SetNetCode(netCode) + newVias += [newVia] + + return newVias + + def onDeleteClick(self, event): + return self.mainDlg.EndModal(wx.ID_DELETE) + + def checkPads(self): + ##Check vias collisions with all pads => all pads on all layers + #wxPrint("Processing all pads...") + + if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: + self.clearance = 0 #TBF + else: + self.clearance = self.boardObj.GetDesignSettings().GetDefault().GetClearance() + #lboard = self.boardObj.ComputeBoundingBox(False) + #origin = lboard.GetPosition() + # Create an initial rectangle: all is set to "REASON_NO_SIGNAL" + # get a margin to avoid out of range + l_clearance = self.clearance + self.viaSize #+ self.size + #x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1 + #y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1 + viasToRemove = [] + removed = False + expansion = 1.6 # extra expansion to fix HitTest + for pad in self.boardObj.GetPads(): + #wx.LogMessage(str(self.viaPointsSafe)) + #wx.LogMessage(str(pad.GetPosition())) + #local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2) + if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: + pad_clr = 0 # FIXME + local_offset = max(pad_clr, self.clearance) + (self.viaSize / 2) + else: + local_offset = max(pad.GetClearance(), self.clearance) + (self.viaSize / 2) + max_size = max(pad.GetSize().x, pad.GetSize().y) + + #start_x = int(floor(((pad.GetPosition().x - (max_size / 2.0 + local_offset)) - origin.x) / l_clearance)) + #stop_x = int(ceil(((pad.GetPosition().x + (max_size / 2.0 + local_offset)) - origin.x) / l_clearance)) + + #start_y = int(floor(((pad.GetPosition().y - (max_size / 2.0 + local_offset)) - origin.y) / l_clearance)) + #stop_y = int(ceil(((pad.GetPosition().y + (max_size / 2.0 + local_offset)) - origin.y) / l_clearance)) + + #for x in range(start_x, stop_x + 1): + # for y in range(start_y, stop_y + 1): + for viaPos in self.viaPointsSafe: + if 1: #try: + #if isinstance(rectangle[x][y], ViaObject): + #start_rect = wxPoint(origin.x + (l_clearance * x) - local_offset, + # origin.y + (l_clearance * y) - local_offset) + #start_rect = pcbnew.wxPoint(viaPos[0] + (l_clearance * viaPos[0]) - local_offset, + # viaPos[1] + (l_clearance * viaPos[1]) - local_offset) + start_rect = pcbnew.wxPoint(viaPos[0] - local_offset*expansion, + viaPos[1] - local_offset*expansion) + size_rect = pcbnew.wxSize(2 * expansion * local_offset, 2 * expansion * local_offset) + wxLogDebug(str(pcbnew.ToMM(start_rect))+'::'+str(pcbnew.ToMM(size_rect)),debug) + if pad.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), False): + #rectangle[x][y] = self.REASON_PAD + wxLogDebug('Hit on Pad: viaPos:'+str(viaPos),debug) + #self.viaPointsSafe.pop(i) + #self.viaPointsSafe.remove(viaPos) + viasToRemove.append(viaPos) + removed = True + #else: + # viaPSafe.append(viaPos) + else: #except: + wx.LogMessage("exception on Processing all pads...") + #i+=1 + #self.viaPointSafe = viaPSafe + #wx.LogMessage(str(viasToRemove)) + newPoints = [p for p in self.viaPointsSafe if p not in viasToRemove] + #wx.LogMessage(str(newPoints)) + #wx.LogMessage(str(len(newPoints))) + self.viaPointsSafe = newPoints + return removed + + def checkTracks(self): + ##Check vias collisions with all tracks + if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: + self.clearance = 0 #TBF + else: + self.clearance = self.boardObj.GetDesignSettings().GetDefault().GetClearance() + #lboard = self.boardObj.ComputeBoundingBox(False) + #origin = lboard.GetPosition() + # Create an initial rectangle: all is set to "REASON_NO_SIGNAL" + # get a margin to avoid out of range + l_clearance = self.clearance + self.viaSize #+ self.size + #wxLogDebug(str(l_clearance),True) + #x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1 + #y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1 + viasToRemove = [] + removed = False + expansion = 2 # extra expansion to fix HitTest + for track in self.boardObj.GetTracks(): + #wx.LogMessage(str(self.viaPointsSafe)) + #wx.LogMessage(str(pad.GetPosition())) + #local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2) + if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: + trk_clr = 0 # FIXME + #trk_clr = track.GetClearance() + local_offset = max(trk_clr, self.clearance) + (self.viaSize / 2) + else: + local_offset = max(track.GetClearance(), self.clearance) + (self.viaSize / 2) + #wxLogDebug(str(max_size),True) + #max_size = max(pad.GetSize().x, pad.GetSize().y) + + #start_x = int(floor(((pad.GetPosition().x - (max_size / 2.0 + local_offset)) - origin.x) / l_clearance)) + #stop_x = int(ceil(((pad.GetPosition().x + (max_size / 2.0 + local_offset)) - origin.x) / l_clearance)) + + #start_y = int(floor(((pad.GetPosition().y - (max_size / 2.0 + local_offset)) - origin.y) / l_clearance)) + #stop_y = int(ceil(((pad.GetPosition().y + (max_size / 2.0 + local_offset)) - origin.y) / l_clearance)) + + #for x in range(start_x, stop_x + 1): + # for y in range(start_y, stop_y + 1): + #wx.LogMessage(str(getTrackAngleRadians(track))) + angle = abs(math.degrees(getTrackAngleRadians(track))) + if (angle > 15 and angle <75) or (angle > 105 and angle <165) or (angle > 195 and angle <255) or (angle > 285 and angle <345): + expansion = 1.4 # extra expansion to fix HitTest + #wx.LogMessage(str(angle)+'::'+str(expansion)) + else: + expansion = 2.0 # extra expansion to fix HitTest + #wx.LogMessage(str(angle)+'::'+str(expansion)) + for viaPos in self.viaPointsSafe: + if 1: #try: + #if isinstance(rectangle[x][y], ViaObject): + #start_rect = wxPoint(origin.x + (l_clearance * x) - local_offset, + # origin.y + (l_clearance * y) - local_offset) + #start_rect = pcbnew.wxPoint(viaPos[0] + (l_clearance * viaPos[0]) - local_offset, + # viaPos[1] + (l_clearance * viaPos[1]) - local_offset) + start_rect = pcbnew.wxPoint(viaPos[0] - local_offset*expansion, + viaPos[1] - local_offset*expansion) + size_rect = pcbnew.wxSize(2 * expansion * local_offset, 2 * expansion * local_offset) + wxLogDebug(str(pcbnew.ToMM(start_rect))+'::'+str(pcbnew.ToMM(size_rect)),debug) + #wxLogDebug(str(track.GetNetCode()),True) + #wxLogDebug(str(self.viaNetId),True) + #wxLogDebug(str(type(track)),True) + if (hasattr(pcbnew,'DRAWSEGMENT')): + trk_type = pcbnew.TRACK + else: + trk_type = pcbnew.PCB_TRACK + if track.GetNetCode() != self.viaNetId or type(track) != trk_type: #PCB_VIA_T: + #wxLogDebug('here',True) + #if track.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), False): + aContained=False;aAccuracy=0 + if track.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), aContained, aAccuracy): + #rectangle[x][y] = self.REASON_PAD + wxLogDebug('Hit on Track: viaPos:'+str(viaPos),debug) + #self.viaPointsSafe.pop(i) + #self.viaPointsSafe.remove(viaPos) + viasToRemove.append(viaPos) + removed = True + #else: + # viaPSafe.append(viaPos) + else: #except: + wx.LogMessage("exception on Processing all tracks...") + #i+=1 + #self.viaPointSafe = viaPSafe + #wx.LogMessage(str(viasToRemove)) + newPoints = [p for p in self.viaPointsSafe if p not in viasToRemove] + #wx.LogMessage(str(newPoints)) + #wx.LogMessage(str(len(newPoints))) + self.viaPointsSafe = newPoints + return removed +# ------------------------------------------------------------------------------------ + + def DoKeyPress(self, event): + if event.GetKeyCode() == wx.WXK_RETURN: + self.mainDlg.EndModal(wx.ID_OK) + else: + event.Skip() + + def selfToMainDialog(self): + self.mainDlg.lstLayer.SetItems(list(self.layerMap.values())) #maui + self.mainDlg.lstLayer.SetSelection(self.layerId) + self.mainDlg.txtNetFilter.SetItems(self.netFilterList) + self.mainDlg.txtNetFilter.SetSelection(self.netFilterList.index(self.netFilter)) + self.mainDlg.txtViaOffset.SetValue(str(pcbnew.ToMM(self.viaOffset))) + self.mainDlg.txtViaPitch.SetValue(str(pcbnew.ToMM(self.viaPitch))) + self.mainDlg.txtViaDrill.SetValue(str(pcbnew.ToMM(self.viaDrill))) + self.mainDlg.txtViaSize.SetValue(str(pcbnew.ToMM(self.viaSize))) + self.mainDlg.txtViaOffset.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress) + #self.mainDlg.txtViaOffset.Bind(wx.EVT_TEXT_ENTER, self.mainDlg.EndModal(wx.ID_OK)) + self.mainDlg.txtViaPitch.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress) + self.mainDlg.txtViaDrill.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress) + self.mainDlg.txtViaSize.Bind(wx.EVT_KEY_DOWN, self.DoKeyPress) + + self.mainDlg.lstViaNet.SetItems([item.GetNetname() for item in self.netMap.values()]) + for i, item in enumerate (self.netMap.values()): + if self.mainDlg.lstViaNet.GetString(i) in ["GND", "/GND"]: + self.mainDlg.lstViaNet.SetSelection(i) + break + if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: #temporary_fix!!! + self.mainDlg.chkNetFilter.Enable (False) + self.mainDlg.chkNetFilter.SetValue(self.isNetFilterChecked) + self.mainDlg.txtNetFilter.Enable(self.isNetFilterChecked) + self.mainDlg.chkLayer.SetValue(self.isLayerChecked) + self.mainDlg.lstLayer.Enable(self.isLayerChecked) + self.mainDlg.chkIncludeDrawing.SetValue(self.isIncludeDrawingChecked) + self.mainDlg.chkIncludeSelection.SetValue(self.isIncludeSelectionChecked) + self.mainDlg.chkDebugDump.SetValue(self.isDebugDumpChecked) + self.mainDlg.chkRemoveViasWithClearanceViolation.SetValue(self.isRemoveViasWithClearanceViolationChecked) + self.mainDlg.chkSameNetZoneViasOnly.SetValue(self.isSameNetZoneViasOnlyChecked) + self.mainDlg.m_buttonDelete.Bind(wx.EVT_BUTTON, self.onDeleteClick) + # hiding unimplemented controls + #self.mainDlg.chkRemoveViasWithClearanceViolation.Hide() + self.mainDlg.chkSameNetZoneViasOnly.Hide() + + def mainDialogToSelf(self): + self.netFilter = self.mainDlg.txtNetFilter.GetValue() + if len(list(self.layerMap.keys())) > 0: + self.layerId = list(self.layerMap.keys())[self.mainDlg.lstLayer.GetSelection()] #maui + self.viaOffset = pcbnew.FromMM(float(self.mainDlg.txtViaOffset.GetValue().replace(',','.'))) + self.viaPitch = pcbnew.FromMM(float(self.mainDlg.txtViaPitch.GetValue().replace(',','.'))) + self.viaDrill = pcbnew.FromMM(float(self.mainDlg.txtViaDrill.GetValue().replace(',','.'))) + self.viaSize = pcbnew.FromMM(float(self.mainDlg.txtViaSize.GetValue().replace(',','.'))) + if len(list(self.netMap.keys())) > 0: + self.viaNetId = list(self.netMap.keys())[self.mainDlg.lstViaNet.GetSelection()] #maui + self.isNetFilterChecked = self.mainDlg.chkNetFilter.GetValue() + self.isLayerChecked = self.mainDlg.chkLayer.GetValue() + self.isIncludeDrawingChecked = self.mainDlg.chkIncludeDrawing.GetValue() + self.isIncludeSelectionChecked = self.mainDlg.chkIncludeSelection.GetValue() + self.isDebugDumpChecked = self.mainDlg.chkDebugDump.GetValue() + self.isSameNetZoneViasOnlyChecked = self.mainDlg.chkSameNetZoneViasOnly.GetValue() + self.isRemoveViasWithClearanceViolationChecked = self.mainDlg.chkRemoveViasWithClearanceViolation.GetValue() + + def Run(self): + #check for pyclipper lib + pyclip = False + try: + import pyclipper + pyclip = True + # import pyclipper; pyclipper.__file__ + except: + #error exception if pyclipper lib is missing + import sys, os + from sys import platform as _platform + if sys.version_info.major == 2 and sys.version_info.minor == 7: + if _platform == "linux" or _platform == "linux2": + # linux + sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'python-pyclipper','py2-7-linux-64')) + elif _platform == "darwin": + #osx + sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'python-pyclipper','py2-7-mac-64')) + else: + #win + sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'python-pyclipper','py2-7-win-64')) + try: + import pyclipper + pyclip = True + except: + msg = u"\u2718 ERROR Missing KiCAD \'pyclipper\' python module:\nplease install it using pip\nin your KiCAD python environment.\n[You may need administrative rights]" + wdlg = wx.MessageDialog(None, msg,'ERROR message',wx.OK | wx.ICON_WARNING)# wx.ICON_ERROR) + result = wdlg.ShowModal() + if pyclip: + #import pyclipper + import os + #self.mainDlg = MainDialog(None) + #self.selfToMainDialog() + + self.boardObj = pcbnew.GetBoard() + self.boardDesignSettingsObj = self.boardObj.GetDesignSettings() + self.boardPath = os.path.dirname(os.path.realpath(self.boardObj.GetFileName())) + self.layerMap = self.getLayerMap() + if not(hasattr(pcbnew,'DRAWSEGMENT')) and temporary_fix: + self.highlightedNetId = -1 + # Nasty work around... GetHighLightNetCodes returns a swig object >_< + # hl_nets = filter(lambda x: x.IsSelected(), self.boardObj.GetTracks()) + # hl_net_codes = set(net.GetNetCode() for net in hl_nets) + # if len(hl_net_codes) == 1: + # self.highlightedNetId = hl_net_codes.pop() + # else: + # wdlg = wx.MessageDialog(None, u"\u2718 ERROR Please only select one net",'ERROR message',wx.OK | wx.ICON_WARNING)# wx.ICON_ERROR) + # result = wdlg.ShowModal() + # return + else: + self.highlightedNetId = self.boardObj.GetHighLightNetCode() + self.netMap = self.getNetMap() + self.netFilterList = self.createNetFilterSuggestions() + self.netFilter = self.netMap[self.highlightedNetId].GetNetname() if self.highlightedNetId != -1 else self.netFilterList[0] + self.viaSize = self.boardDesignSettingsObj.GetCurrentViaSize() + self.layerId = 0 #TODO: How to get currently selected layer? + self.viaDrill = self.boardDesignSettingsObj.GetCurrentViaDrill() + self.viaPitch = pcbnew.FromMM(1.3) + self.viaOffset = pcbnew.FromMM(1.3) + self.viaNetId = 0 #TODO: Maybe a better init value here. Try to find "GND" maybe? + self.isNetFilterChecked = 1 if self.highlightedNetId != -1 else 0 + #if len(list(self.netMap.keys())) > 0: + # self.viaNetId = list(self.netMap.keys())[self.mainDlg.lstViaNet.GetSelection()] #maui + + self.isLayerChecked = 0 + self.isIncludeDrawingChecked = 0 + self.isIncludeSelectionChecked = 1 + self.isDebugDumpChecked = 0 + self.isRemoveViasWithClearanceViolationChecked = 1 + self.isSameNetZoneViasOnlyChecked = 0 + + self.mainDlg = MainDialog(None) + self.selfToMainDialog() + if hasattr(self.boardObj, 'm_Uuid'): + self.mainDlg.m_buttonDelete.Disable() + self.mainDlg.m_buttonDelete.SetToolTip( u"fencing vias are placed in a group,\nto delete fencing vias, just delete the group" ) + reply = self.mainDlg.ShowModal() + if (reply == wx.ID_OK): + # User pressed OK. + # Assemble a list of pcbnew.BOARD_ITEMs derived objects that support GetStart/GetEnd and IsOnLayer + self.mainDialogToSelf() + lineObjects = [] + arcObjects = [] + + # creating a unique group for vias + if not(hasattr(pcbnew,'DRAWSEGMENT')): #creating a group of fencing vias + groupName = uuid.uuid4() #randomword(5) + pcb_group = pcbnew.PCB_GROUP(None) + pcb_group.SetName(groupName) + self.boardObj.Add(pcb_group) + + + # Do we want to include net tracks? + if (self.isNetFilterChecked): + # Find nets that match the generated regular expression and add their tracks to the list + netRegex = self.regExFromSimpleEx(self.netFilter) + for netId in self.netMap: + if re.match(netRegex, self.netMap[netId].GetNetname()): + for trackObject in self.boardObj.TracksInNet(netId): + #wx.LogMessage('type '+str(trackObject.GetStart())) + #wx.LogMessage('type '+str(trackObject.GetMid())) + if (hasattr(pcbnew,'DRAWSEGMENT')): + trk_type = pcbnew.TRACK + else: + trk_type = pcbnew.PCB_TRACK + trk_arc = pcbnew.PCB_ARC + if hasattr(trackObject,'GetMid()'): + arcObjects += [trackObject] + elif type(trackObject) is trk_type: + lineObjects += [trackObject] + + # wx.LogMessage('net selected '+str(lineObjects)) + # wx.LogMessage('net selected '+str(arcObjects)) + + # Do we want to include drawing segments? + if (self.isIncludeDrawingChecked): + boardItem = self.boardObj.GetDrawings().GetFirst() + while boardItem is not None: + if pcbnew.DRAWSEGMENT.ClassOf(boardItem): + # A drawing segment (not a text or something else) + drawingObject = boardItem.Cast() + if drawingObject.GetShape() == pcbnew.S_SEGMENT: + # A straight line + lineObjects += [drawingObject] + + boardItem = boardItem.Next() + + # Do we want to include track segments? + if (self.isIncludeSelectionChecked): + if (hasattr(pcbnew,'DRAWSEGMENT')): + trk_type = pcbnew.TRACK + else: + trk_type = pcbnew.PCB_TRACK + trk_arc = pcbnew.PCB_ARC + for item in self.boardObj.GetTracks(): + #wx.LogMessage('type track: %s' % str(type(item))) + if not (hasattr(pcbnew,'DRAWSEGMENT')): + if type(item) is trk_arc and item.IsSelected(): + wx.LogMessage('type track: %s' % str(type(item))) + arcObjects += [item] + if type(item) is trk_type and item.IsSelected(): + lineObjects += [item] + + # Do we want to filter the generated lines by layer? + if (self.isLayerChecked): + # Filter by layer + # TODO: Make layer selection also a regex + lineObjects = [lineObject for lineObject in lineObjects if lineObject.IsOnLayer(self.layerId)] + arcObjects = [arcObject for arcObject in arcObjects if arcObject.IsOnLayer(self.layerId)] + #wx.LogMessage('arcs: %s' % str(arcObjects)) + + for arc in arcObjects: + segNBR = 16 + start = arc.GetStart() + end = arc.GetEnd() + md = arc.GetMid() + width = arc.GetWidth() + layer = arc.GetLayerSet() + netName = None + cnt, rad = getCircleCenterRadius(start,end,md) + pts = create_round_pts(start,end,cnt,rad,layer,width,netName,segNBR) + self.pathListArcs = [[ [p.x, p.y], + [pts[i+1].x, pts[i+1].y] ] + for i,p in enumerate(pts[:-1])] + # Generate via fence + try: + viaPointsArcs = [] + if len (arcObjects) > 0: + viaPointsArcs = generateViaFence(self.pathListArcs, self.viaOffset, self.viaPitch) + viaObjListArcs = self.createVias(viaPointsArcs, self.viaDrill, self.viaSize, self.viaNetId) + for v in viaObjListArcs: + pcb_group.AddItem(v) + except Exception as exc: + wx.LogMessage('exception on via fence generation: %s' % str(exc)) + import traceback + wx.LogMessage(traceback.format_exc()) + viaPoints = [] + #wx.LogMessage('pL: %s' % str(self.pathListArcs)) + #wx.LogMessage('pts: %s' % str(pts)) + + # Generate a path list from the pcbnew.BOARD_ITEM objects + self.pathList = [[ [lineObject.GetStart()[0], lineObject.GetStart()[1]], + [lineObject.GetEnd()[0], lineObject.GetEnd()[1]] ] + for lineObject in lineObjects] + #wx.LogMessage('pL: %s' % str(self.pathList)) + + + # Generate via fence + try: + viaPointsArcs = [] + viaPoints = generateViaFence(self.pathList, self.viaOffset, self.viaPitch) + #if len (arcObjects) > 0: + # viaPointsArcs = generateViaFence(self.pathListArcs, self.viaOffset, self.viaPitch) + except Exception as exc: + wx.LogMessage('exception on via fence generation: %s' % str(exc)) + import traceback + wx.LogMessage(traceback.format_exc()) + viaPoints = [] + + if (self.isDebugDumpChecked): + self.viaPoints = viaPoints + self.dumpJSON(os.path.join(self.boardPath, time.strftime("viafence-%Y%m%d-%H%M%S.json"))) + + removed = False + if (self.isRemoveViasWithClearanceViolationChecked): + #if self.mainDlg.chkRemoveViasWithClearanceViolation.GetValue(): + # Remove Vias that violate clearance to other things + # Check against other tracks + #wx.LogMessage('hereIam') + # removing generated & colliding vias + viaPointsSafe = [] + for i,v in enumerate(viaPoints): + #clearance = v.GetClearance() + collision_found = False + tolerance = 1 + 0.2 + # This should be handled with Net Clearance + for j, vn in enumerate(viaPoints[i+1:]): + if distance (pcbnew.wxPoint(v[0], v[1]),pcbnew.wxPoint(vn[0], vn[1])) < int(self.viaSize*tolerance): # +clearance viasize+20%: + collision_found = True + if not collision_found: + viaPointsSafe.append(v) + self.viaPointsSafe = viaPointsSafe + #wx.LogMessage(str(len(self.viaPointsSafe))) + removed = self.checkPads() + remvd = self.checkTracks() + removed = removed or remvd + else: + self.viaPointsSafe = viaPoints + #wx.LogMessage(str(len(self.viaPointsSafe))) + #self.checkPads() + #wx.LogMessage(str(len(self.viaPointsSafe))) + viaObjList = self.createVias(self.viaPointsSafe, self.viaDrill, self.viaSize, self.viaNetId) + # viaObjListArcs = [] + # if len (arcObjects) > 0: + # viaObjListArcs = self.createVias(viaPointsArcs, self.viaDrill, self.viaSize, self.viaNetId) + if not(hasattr(pcbnew,'DRAWSEGMENT')): #creating a group of fencing vias + # groupName = uuid.uuid4() #randomword(5) + # pcb_group = pcbnew.PCB_GROUP(None) + # pcb_group.SetName(groupName) + # self.boardObj.Add(pcb_group) + for v in viaObjList: + pcb_group.AddItem(v) + #for v in viaObjListArcs: + # pcb_group.AddItem(v) + via_nbr = len(self.viaPointsSafe) + via_nbr += len(viaPointsArcs) + msg = u'Placed {0:} Fencing Vias.\n\u26A0 Please run a DRC check on your board.'.format(str(via_nbr)) + if removed: + msg += u'\n\u281B Removed DRC colliding vias.' + wx.LogMessage(msg) + #viaObjList = self.createVias(viaPoints, self.viaDrill, self.viaSize, self.viaNetId) + #via_nbr = len(viaPoints) + + + elif (reply == wx.ID_DELETE): + #user clicked ('Delete Fence Vias') + target_tracks = filter(lambda x: ((x.Type() == pcbnew.PCB_VIA_T)and (x.GetTimeStamp() == 55)), self.boardObj.GetTracks()) + #wx.LogMessage(str(len(target_tracks))) + target_tracks_cp = list(target_tracks) + l = len (target_tracks_cp) + for i in range(l): + #if type(target_tracks_cp[i]) is PCB_TRACK and target_tracks_cp[i].IsSelected(): #item.GetNetname() == net_name: + self.boardObj.RemoveNative(target_tracks_cp[i]) #removing via + #for via in target_tracks: + # #if via.GetTimeStamp() == 55: + # self.boardObj.RemoveNative(via) + # #wx.LogMessage('removing via') + #pcbnew.Refresh() + self.mainDlg.Destroy() #the Dlg needs to be destroyed to release pcbnew + +# TODO: Implement +# if (self.isRemoveViasWithClearanceViolationChecked): +# # Remove Vias that violate clearance to other things +# # Check against other tracks +# for viaObj in viaObjList: +# for track in self.boardObj.GetTracks(): +# clearance = track.GetClearance(viaObj) +# if track.HitTest(False, clearance): +# self.boardObj.RemoveNative(viaObj) + +# TODO: Implement +# if (self.isSameNetZoneViasOnlyChecked): +# # Keep via only if it is in a filled zone with the same net + +# import numpy as np +# import matplotlib.pyplot as plt + +# for path in self.pathList: +# plt.plot(np.array(path).T[0], np.array(path).T[1], linewidth=2) +# for via in viaPoints: +# plt.plot(via[0], via[1], 'o', markersize=10) + + +# plt.ylim(plt.ylim()[::-1]) +# plt.axes().set_aspect('equal','box') +# plt.show() + diff --git a/kicad_plugins/via_fence_generator/viafence_basedialogs.py b/kicad_plugins/via_fence_generator/viafence_basedialogs.py new file mode 100644 index 00000000..502cb1f0 --- /dev/null +++ b/kicad_plugins/via_fence_generator/viafence_basedialogs.py @@ -0,0 +1,226 @@ +# -*- coding: utf-8 -*- + +########################################################################### +## Python code generated with wxFormBuilder (version Oct 26 2018) +## http://www.wxformbuilder.org/ +## +## PLEASE DO *NOT* EDIT THIS FILE! +########################################################################### + +import wx +import wx.xrc + +########################################################################### +## Class MainDialogBase +########################################################################### + +class MainDialogBase ( wx.Dialog ): + + def __init__( self, parent ): + wx.Dialog.__init__ ( self, parent, id = wx.ID_ANY, title = u"Via Fence Generator", pos = wx.DefaultPosition, size = wx.Size( 503,567 ), style = wx.CAPTION|wx.CLOSE_BOX|wx.RESIZE_BORDER ) + + import sys #maui + if sys.version_info[0] == 2: + self.SetSizeHintsSz( wx.Size( -1,-1 ), wx.Size( -1,-1 ) ) + else: + self.SetSizeHints( wx.Size( -1,-1 ), wx.Size( -1,-1 ) ) + + mainSizer = wx.BoxSizer( wx.VERTICAL ) + + gbSizer4 = wx.GridBagSizer( 0, 0 ) + gbSizer4.SetFlexibleDirection( wx.BOTH ) + gbSizer4.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) + + bSizer23 = wx.BoxSizer( wx.VERTICAL ) + + sbSizer2 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Via Settings" ), wx.VERTICAL ) + + fgSizer4 = wx.FlexGridSizer( 8, 2, 0, 0 ) + fgSizer4.AddGrowableCol( 1 ) + fgSizer4.SetFlexibleDirection( wx.BOTH ) + fgSizer4.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) + + self.m_staticText11 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Offset (mm):", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText11.Wrap( -1 ) + + fgSizer4.Add( self.m_staticText11, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.txtViaOffset = wx.TextCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER|wx.TE_RIGHT ) + fgSizer4.Add( self.txtViaOffset, 0, wx.ALL|wx.EXPAND, 5 ) + + self.m_staticText21 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Pitch (mm):", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText21.Wrap( -1 ) + + fgSizer4.Add( self.m_staticText21, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.txtViaPitch = wx.TextCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER|wx.TE_RIGHT ) + fgSizer4.Add( self.txtViaPitch, 0, wx.ALL|wx.EXPAND, 5 ) + + self.m_staticText13 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Via Drill (mm):", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText13.Wrap( -1 ) + + fgSizer4.Add( self.m_staticText13, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.txtViaDrill = wx.TextCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER|wx.TE_RIGHT ) + fgSizer4.Add( self.txtViaDrill, 0, wx.ALL|wx.EXPAND, 5 ) + + self.m_staticText14 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Via Size (mm):", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText14.Wrap( -1 ) + + fgSizer4.Add( self.m_staticText14, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + self.txtViaSize = wx.TextCtrl( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER|wx.TE_RIGHT ) + fgSizer4.Add( self.txtViaSize, 0, wx.EXPAND|wx.ALL, 5 ) + + self.m_staticText23 = wx.StaticText( sbSizer2.GetStaticBox(), wx.ID_ANY, u"Via Net:", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.m_staticText23.Wrap( -1 ) + + fgSizer4.Add( self.m_staticText23, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5 ) + + lstViaNetChoices = [] + self.lstViaNet = wx.Choice( sbSizer2.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, lstViaNetChoices, 0 ) + self.lstViaNet.SetSelection( 0 ) + fgSizer4.Add( self.lstViaNet, 1, wx.EXPAND|wx.ALL, 5 ) + + + sbSizer2.Add( fgSizer4, 1, wx.EXPAND, 5 ) + + + bSizer23.Add( sbSizer2, 1, wx.ALL|wx.EXPAND, 5 ) + + + gbSizer4.Add( bSizer23, wx.GBPosition( 0, 0 ), wx.GBSpan( 1, 1 ), wx.EXPAND, 5 ) + + bSizer21 = wx.BoxSizer( wx.VERTICAL ) + + + bSizer21.Add( ( 0, 9), 0, 0, 5 ) + + self.bmpViafence = wx.StaticBitmap( self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer21.Add( self.bmpViafence, 1, wx.EXPAND, 5 ) + + + gbSizer4.Add( bSizer21, wx.GBPosition( 0, 1 ), wx.GBSpan( 1, 1 ), wx.EXPAND|wx.ALL, 5 ) + + sbSizer411 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Input Tracks" ), wx.VERTICAL ) + + gSizer4 = wx.GridSizer( 3, 1, 0, 0 ) + + self.chkIncludeSelection = wx.CheckBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Include Selected", wx.DefaultPosition, wx.DefaultSize, 0 ) + self.chkIncludeSelection.SetValue(True) + gSizer4.Add( self.chkIncludeSelection, 0, wx.ALL, 5 ) + + self.chkIncludeDrawing = wx.CheckBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Include Drawing Lines", wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer4.Add( self.chkIncludeDrawing, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, 5 ) + + fgSizer311 = wx.FlexGridSizer( 1, 2, 0, 10 ) + fgSizer311.AddGrowableCol( 1 ) + fgSizer311.SetFlexibleDirection( wx.HORIZONTAL ) + fgSizer311.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) + + self.chkNetFilter = wx.CheckBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Net(s):", wx.DefaultPosition, wx.DefaultSize, 0 ) + fgSizer311.Add( self.chkNetFilter, 0, wx.ALL|wx.EXPAND, 5 ) + + txtNetFilterChoices = [] + self.txtNetFilter = wx.ComboBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Combo!", wx.DefaultPosition, wx.DefaultSize, txtNetFilterChoices, 0 ) + self.txtNetFilter.Enable( False ) + + fgSizer311.Add( self.txtNetFilter, 1, wx.ALL|wx.EXPAND, 5 ) + + + gSizer4.Add( fgSizer311, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 ) + + fgSizer31 = wx.FlexGridSizer( 1, 2, 0, 10 ) + fgSizer31.AddGrowableCol( 1 ) + fgSizer31.SetFlexibleDirection( wx.HORIZONTAL ) + fgSizer31.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED ) + + self.chkLayer = wx.CheckBox( sbSizer411.GetStaticBox(), wx.ID_ANY, u"Layer:", wx.DefaultPosition, wx.DefaultSize, 0 ) + fgSizer31.Add( self.chkLayer, 1, wx.ALL|wx.EXPAND, 5 ) + + lstLayerChoices = [] + self.lstLayer = wx.Choice( sbSizer411.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, lstLayerChoices, 0 ) + self.lstLayer.SetSelection( 0 ) + self.lstLayer.Enable( False ) + + fgSizer31.Add( self.lstLayer, 1, wx.ALL|wx.EXPAND, 5 ) + + + gSizer4.Add( fgSizer31, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5 ) + + + sbSizer411.Add( gSizer4, 0, wx.EXPAND, 5 ) + + + gbSizer4.Add( sbSizer411, wx.GBPosition( 1, 0 ), wx.GBSpan( 1, 1 ), wx.ALL|wx.EXPAND, 5 ) + + sbSizer4 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"Output VIAs" ), wx.VERTICAL ) + + gSizer2 = wx.GridSizer( 3, 1, 0, 0 ) + + self.chkSameNetZoneViasOnly = wx.CheckBox( sbSizer4.GetStaticBox(), wx.ID_ANY, u"Keep VIAs in \nVia Net zones only", wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer2.Add( self.chkSameNetZoneViasOnly, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.LEFT, 5 ) + + self.chkRemoveViasWithClearanceViolation = wx.CheckBox( sbSizer4.GetStaticBox(), wx.ID_ANY, u"Remove VIAs violating \nclearance rules", wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer2.Add( self.chkRemoveViasWithClearanceViolation, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.RIGHT|wx.LEFT, 5 ) + + self.m_buttonDelete = wx.Button( sbSizer4.GetStaticBox(), wx.ID_ANY, u"Delete Vias", wx.DefaultPosition, wx.DefaultSize, 0 ) + gSizer2.Add( self.m_buttonDelete, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) + + + sbSizer4.Add( gSizer2, 1, wx.EXPAND, 5 ) + + + gbSizer4.Add( sbSizer4, wx.GBPosition( 1, 1 ), wx.GBSpan( 1, 1 ), wx.EXPAND|wx.ALL, 5 ) + + + gbSizer4.AddGrowableCol( 0 ) + + mainSizer.Add( gbSizer4, 1, wx.EXPAND, 5 ) + + bSizer5 = wx.BoxSizer( wx.HORIZONTAL ) + + self.chkDebugDump = wx.CheckBox( self, wx.ID_ANY, u"Debug Dump", wx.DefaultPosition, wx.DefaultSize, 0 ) + bSizer5.Add( self.chkDebugDump, 0, wx.ALL|wx.EXPAND, 5 ) + + + bSizer5.Add( ( 0, 0), 1, wx.EXPAND, 5 ) + + m_sdbSizer1 = wx.StdDialogButtonSizer() + self.m_sdbSizer1OK = wx.Button( self, wx.ID_OK ) + m_sdbSizer1.AddButton( self.m_sdbSizer1OK ) + self.m_sdbSizer1Cancel = wx.Button( self, wx.ID_CANCEL ) + m_sdbSizer1.AddButton( self.m_sdbSizer1Cancel ) + m_sdbSizer1.Realize(); + + bSizer5.Add( m_sdbSizer1, 0, wx.EXPAND|wx.ALL, 5 ) + + + mainSizer.Add( bSizer5, 0, wx.EXPAND, 5 ) + + + self.SetSizer( mainSizer ) + self.Layout() + + self.Centre( wx.BOTH ) + + # Connect Events + self.Bind( wx.EVT_INIT_DIALOG, self.OnInitDialog ) + self.chkNetFilter.Bind( wx.EVT_CHECKBOX, self.OnNetFilterCheckBox ) + self.chkLayer.Bind( wx.EVT_CHECKBOX, self.OnLayerCheckBox ) + + def __del__( self ): + pass + + + # Virtual event handlers, overide them in your derived class + def OnInitDialog( self, event ): + event.Skip() + + def OnNetFilterCheckBox( self, event ): + event.Skip() + + def OnLayerCheckBox( self, event ): + event.Skip() + + diff --git a/kicad_plugins/via_fence_generator/viafence_dialogs.py b/kicad_plugins/via_fence_generator/viafence_dialogs.py new file mode 100644 index 00000000..7c5cd16b --- /dev/null +++ b/kicad_plugins/via_fence_generator/viafence_dialogs.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +import os +import sys +from .viafence_basedialogs import * + +class MainDialog(MainDialogBase): + def __init__(self, parent): + MainDialogBase.__init__(self, parent) + # Small workaround to fix the paths generated by wxFormBuilder + self.bmpViafence.SetBitmap(wx.Bitmap( os.path.join(os.path.dirname(os.path.realpath(__file__)), "resources", "viafence.png") ) ) + + def OnInitDialog(self, event): + self.Layout() + self.GetSizer().Fit(self) + self.SetMinSize(self.GetSize()) + #self.SetMaxSize(self.GetSize()) + self.SetTitle(u"Via Fence Generator") + if sys.version_info[0] == 2: + self.chkDebugDump.SetToolTipString( u"Creates a json file in the same directory as the opened board file containing the tracks and settings" ) + else: + self.chkDebugDump.SetToolTip( u"Creates a json file in the same directory as the opened board file containing the tracks and settings" ) + + + def OnNetFilterCheckBox(self, event): + self.txtNetFilter.Enable(event.IsChecked()) + + def OnLayerCheckBox(self, event): + self.lstLayer.Enable(event.IsChecked()) +