From bfdc024a33c2d9121cc5941d82461c7e3d8a98e4 Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Sun, 10 Apr 2022 15:26:35 -0300 Subject: [PATCH] Added an option to sort the layer as KiCad to pcb_print --- .pre-commit-config.yaml | 8 +- .../kicad/Print_Layer/layers.kicad_pcb | 153 ++++++++++++++++++ experiments/kicad/Print_Layer/layers.pdf | Bin 0 -> 22502 bytes kibot/layer.py | 24 +++ kibot/out_pcb_print.py | 11 +- 5 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 experiments/kicad/Print_Layer/layers.kicad_pcb create mode 100644 experiments/kicad/Print_Layer/layers.pdf diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 120c8f5d..d8d1d384 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -52,10 +52,6 @@ repos: # rev: 22.1.0 # hooks: # - id: black - - repo: https://github.com/Lucas-C/pre-commit-hooks-bandit - rev: v1.0.5 - hooks: - - id: python-bandit-vulnerability-check - repo: https://github.com/fsouza/autoflake8 rev: v0.3.1 hooks: @@ -87,4 +83,8 @@ repos: # rev: v0.931 # hooks: # - id: mypy + - repo: https://github.com/Lucas-C/pre-commit-hooks-bandit + rev: v1.0.5 + hooks: + - id: python-bandit-vulnerability-check # TODO: mdformat --wrap 75 README.md --number diff --git a/experiments/kicad/Print_Layer/layers.kicad_pcb b/experiments/kicad/Print_Layer/layers.kicad_pcb new file mode 100644 index 00000000..c322765b --- /dev/null +++ b/experiments/kicad/Print_Layer/layers.kicad_pcb @@ -0,0 +1,153 @@ +(kicad_pcb (version 20211014) (generator pcbnew) + + (general + (thickness 4.69) + ) + + (paper "A4") + (layers + (0 "F.Cu" signal) + (1 "In1.Cu" signal) + (2 "In2.Cu" signal) + (31 "B.Cu" signal) + (32 "B.Adhes" user "B.Adhesive") + (33 "F.Adhes" user "F.Adhesive") + (34 "B.Paste" user) + (35 "F.Paste" user) + (36 "B.SilkS" user "B.Silkscreen") + (37 "F.SilkS" user "F.Silkscreen") + (38 "B.Mask" user) + (39 "F.Mask" user) + (40 "Dwgs.User" user "User.Drawings") + (41 "Cmts.User" user "User.Comments") + (42 "Eco1.User" user "User.Eco1") + (43 "Eco2.User" user "User.Eco2") + (44 "Edge.Cuts" user) + (45 "Margin" user) + (46 "B.CrtYd" user "B.Courtyard") + (47 "F.CrtYd" user "F.Courtyard") + (48 "B.Fab" user) + (49 "F.Fab" user) + (50 "User.1" user) + (51 "User.2" user) + (52 "User.3" user) + (53 "User.4" user) + (54 "User.5" user) + (55 "User.6" user) + (56 "User.7" user) + (57 "User.8" user) + (58 "User.9" user) + ) + + (setup + (stackup + (layer "F.SilkS" (type "Top Silk Screen")) + (layer "F.Paste" (type "Top Solder Paste")) + (layer "F.Mask" (type "Top Solder Mask") (thickness 0.01)) + (layer "F.Cu" (type "copper") (thickness 0.035)) + (layer "dielectric 1" (type "core") (thickness 1.51) (material "FR4") (epsilon_r 4.5) (loss_tangent 0.02)) + (layer "In1.Cu" (type "copper") (thickness 0.035)) + (layer "dielectric 2" (type "prepreg") (thickness 1.51) (material "FR4") (epsilon_r 4.5) (loss_tangent 0.02)) + (layer "In2.Cu" (type "copper") (thickness 0.035)) + (layer "dielectric 3" (type "core") (thickness 1.51) (material "FR4") (epsilon_r 4.5) (loss_tangent 0.02)) + (layer "B.Cu" (type "copper") (thickness 0.035)) + (layer "B.Mask" (type "Bottom Solder Mask") (thickness 0.01)) + (layer "B.Paste" (type "Bottom Solder Paste")) + (layer "B.SilkS" (type "Bottom Silk Screen")) + (copper_finish "None") + (dielectric_constraints no) + ) + (pad_to_mask_clearance 0) + (pcbplotparams + (layerselection 0x00010fc_ffffffff) + (disableapertmacros false) + (usegerberextensions false) + (usegerberattributes true) + (usegerberadvancedattributes true) + (creategerberjobfile true) + (svguseinch false) + (svgprecision 6) + (excludeedgelayer true) + (plotframeref false) + (viasonmask false) + (mode 1) + (useauxorigin false) + (hpglpennumber 1) + (hpglpenspeed 20) + (hpglpendiameter 15.000000) + (dxfpolygonmode true) + (dxfimperialunits true) + (dxfusepcbnewfont true) + (psnegative false) + (psa4output false) + (plotreference true) + (plotvalue true) + (plotinvisibletext false) + (sketchpadsonfab false) + (subtractmaskfromsilk false) + (outputformat 1) + (mirror false) + (drillshape 1) + (scaleselection 1) + (outputdirectory "") + ) + ) + + (net 0 "") + + (gr_line (start 78 94) (end 78 34) (layer "F.Cu") (width 1) (tstamp 262f85ee-a49a-4194-bdee-29ac02a484ec)) + (gr_line (start 70 40) (end 130 40) (layer "F.Cu") (width 1) (tstamp 77da69f1-4a7e-4daf-b100-27fb75871e8c)) + (gr_line (start 80 94) (end 80 34) (layer "In1.Cu") (width 1) (tstamp fa1503a0-19c0-4e06-a1de-65c87d9f3046)) + (gr_line (start 70 42) (end 130 42) (layer "In1.Cu") (width 1) (tstamp fb7c97ee-bfba-49df-b0a6-949d8c1dbc80)) + (gr_line (start 82 94) (end 82 34) (layer "In2.Cu") (width 1) (tstamp 09c5b2e9-fadc-49a8-867f-ed662ece0465)) + (gr_line (start 70 44) (end 130 44) (layer "In2.Cu") (width 1) (tstamp ea4e4e6a-929c-474e-821a-a752170b4f9c)) + (gr_line (start 84 94) (end 84 34) (layer "B.Cu") (width 1) (tstamp 54c8435a-0b4b-47ec-b2ba-919fa8bf92bd)) + (gr_line (start 70 46) (end 130 46) (layer "B.Cu") (width 1) (tstamp d312a4d8-3900-420d-83df-acf2d1616827)) + (gr_line (start 70 50) (end 130 50) (layer "B.Adhes") (width 1) (tstamp db8a60a1-6c78-42ba-b45c-08cf72ddf99e)) + (gr_line (start 88 94) (end 88 34) (layer "B.Adhes") (width 1) (tstamp e3da7779-0ea1-46dc-90c1-3da0eae63ac3)) + (gr_line (start 70 48) (end 130 48) (layer "F.Adhes") (width 1) (tstamp 2c93e68b-23e0-4a8f-845c-7911d3abc09e)) + (gr_line (start 86 94) (end 86 34) (layer "F.Adhes") (width 1) (tstamp 959a520e-05e4-488b-a17d-dfb714eea3cc)) + (gr_line (start 70 54) (end 130 54) (layer "B.Paste") (width 1) (tstamp 69029636-79e5-47ae-bb14-9bc5dbdeb2b4)) + (gr_line (start 92 94) (end 92 34) (layer "B.Paste") (width 1) (tstamp b5ffc3b0-893d-4977-bac8-ca0fd10d098d)) + (gr_line (start 90 94) (end 90 34) (layer "F.Paste") (width 1) (tstamp 364ea6d5-81d6-485d-af85-ad66a6d4fe3f)) + (gr_line (start 70 52) (end 130 52) (layer "F.Paste") (width 1) (tstamp 52c6d709-bf2c-4bb8-aab3-486121f784ad)) + (gr_line (start 96 94) (end 96 34) (layer "B.SilkS") (width 1) (tstamp 4c0f28bd-4fdd-4e3f-866b-0af6e20563d6)) + (gr_line (start 70 58) (end 130 58) (layer "B.SilkS") (width 1) (tstamp de4d9514-3cb5-4e56-aa34-9a36cc7ab2fb)) + (gr_line (start 70 56) (end 130 56) (layer "F.SilkS") (width 1) (tstamp 55366e14-cec9-493d-901d-448b04d2f286)) + (gr_line (start 94 94) (end 94 34) (layer "F.SilkS") (width 1) (tstamp ac400113-5b0c-4ba3-90f5-fba5c1ab46ed)) + (gr_line (start 70 62) (end 130 62) (layer "B.Mask") (width 1) (tstamp 004f1cac-5431-476d-8d12-f0d7e1d2971c)) + (gr_line (start 100 94) (end 100 34) (layer "B.Mask") (width 1) (tstamp 61d13227-ea38-4175-a5c0-8f75a3d5765d)) + (gr_line (start 70 60) (end 130 60) (layer "F.Mask") (width 1) (tstamp 5aeb1e78-7ed8-446f-a1fa-e72019642e8e)) + (gr_line (start 98 94) (end 98 34) (layer "F.Mask") (width 1) (tstamp 92927a9e-f25b-41ba-9c93-2d6e3e6c1f89)) + (gr_line (start 70 64) (end 130 64) (layer "Dwgs.User") (width 1) (tstamp c457d6bc-d372-4e5a-9060-512765531115)) + (gr_line (start 102 94) (end 102 34) (layer "Dwgs.User") (width 1) (tstamp ed719640-2001-4a0b-956b-2fc557f849a0)) + (gr_line (start 104 94) (end 104 34) (layer "Cmts.User") (width 1) (tstamp 65648dec-894d-4846-9000-a3f37128d377)) + (gr_line (start 70 66) (end 130 66) (layer "Cmts.User") (width 1) (tstamp 8bcf2b99-1928-47d5-9785-f90fe779323f)) + (gr_line (start 106 94) (end 106 34) (layer "Eco1.User") (width 1) (tstamp 725ddd62-c356-4053-88dd-d8de16f6d111)) + (gr_line (start 70 68) (end 130 68) (layer "Eco1.User") (width 1) (tstamp 883e7763-c7c3-4085-8e36-b949c37033d0)) + (gr_line (start 108 94) (end 108 34) (layer "Eco2.User") (width 1) (tstamp 8d9916ee-e2bd-408c-960d-d9bae62b28e4)) + (gr_line (start 70 70) (end 130 70) (layer "Eco2.User") (width 1) (tstamp c898c915-89f5-4003-9fb8-8b0c3f06dfe7)) + (gr_line (start 110 94) (end 110 34) (layer "Edge.Cuts") (width 1) (tstamp 196afe34-74fd-48ae-9b9f-d7a341cb4cdd)) + (gr_line (start 70 72) (end 130 72) (layer "Edge.Cuts") (width 1) (tstamp 925356e8-9fe3-4fca-8329-eba967a76629)) + (gr_line (start 70 74) (end 130 74) (layer "Margin") (width 1) (tstamp da88cf57-0975-4f67-b828-34f4f4c6151f)) + (gr_line (start 112 94) (end 112 34) (layer "Margin") (width 1) (tstamp e36b28a4-7427-4708-a63e-3fe312e8d49f)) + (gr_line (start 116 94) (end 116 34) (layer "B.CrtYd") (width 1) (tstamp aef028c9-bd4b-4984-aea9-019dcc39d7ec)) + (gr_line (start 70 78) (end 130 78) (layer "B.CrtYd") (width 1) (tstamp f8978d6f-bc80-4d45-99fe-9eda6ceed8ec)) + (gr_line (start 70 76) (end 130 76) (layer "F.CrtYd") (width 1) (tstamp 84164d3c-90bc-45b0-ac63-7f7a93843cb3)) + (gr_line (start 114 94) (end 114 34) (layer "F.CrtYd") (width 1) (tstamp e10a8197-feb1-49a8-8ce1-531c3527f182)) + (gr_line (start 120 94) (end 120 34) (layer "B.Fab") (width 1) (tstamp 2a77a72e-d058-40b9-a6e8-cfe4c97e7ab1)) + (gr_line (start 70 82) (end 130 82) (layer "B.Fab") (width 1) (tstamp 96916265-4653-41c3-9a80-f6775aa2b630)) + (gr_line (start 70 80) (end 130 80) (layer "F.Fab") (width 1) (tstamp 1a253373-7aaa-4800-82a0-f05224ca4a7a)) + (gr_line (start 118 94) (end 118 34) (layer "F.Fab") (width 1) (tstamp c00a6ff3-d367-48aa-9987-c597c23d6ece)) + (gr_line (start 70 84) (end 130 84) (layer "User.1") (width 1) (tstamp 1e5a4a4f-7ec1-4d5e-aab0-77eebafcd5cd)) + (gr_line (start 122 94) (end 122 34) (layer "User.1") (width 1) (tstamp 75e54a73-a71d-4649-833f-7b284b918c88)) + (gr_line (start 124 94) (end 124 34) (layer "User.2") (width 1) (tstamp 63775781-01d0-47bd-b139-79a50fca0217)) + (gr_line (start 70 86) (end 130 86) (layer "User.2") (width 1) (tstamp 7505eede-a417-42c3-88a2-1fe21ee21a2a)) + (gr_text "F.Cu\nIn1.Cu\nIn2.Cu\nB.Cu\nF.Adhes\nB.Adhes\nF.Paste\nB.Paste\nF.SilkS\nB.SilkS\nF.Mask\nB.Mask\nDwgs.User\nCmts.User\nEco1.User\nEco2.User\nEdge.Cuts\nMargin\nF.CrtYd\nB.CrtYd\nF.Fab\nB.Fab\nUser.1\nUser.2" (at 69 63) (layer "F.Cu") (tstamp 82c3fcff-0c4d-46ec-9117-fd4b044c0976) + (effects (font (size 1.25 1.5) (thickness 0.25)) (justify right)) + ) + (gr_text "F.Cu\nIn1.Cu\nIn2.Cu\nB.Cu\nF.Adhes\nB.Adhes\nF.Paste\nB.Paste\nF.SilkS\nB.SilkS\nF.Mask\nB.Mask\nDwgs.User\nCmts.User\nEco1.User\nEco2.User\nEdge.Cuts\nMargin\nF.CrtYd\nB.CrtYd\nF.Fab\nB.Fab\nUser.1\nUser.2" (at 101 33 90) (layer "F.Cu") (tstamp f231041b-336c-4b9b-9f86-123f9dc12d97) + (effects (font (size 1.25 1.5) (thickness 0.25)) (justify left)) + ) + +) diff --git a/experiments/kicad/Print_Layer/layers.pdf b/experiments/kicad/Print_Layer/layers.pdf new file mode 100644 index 0000000000000000000000000000000000000000..71281dc8bb5a1d21f29c8e06e105081a1e1c6869 GIT binary patch literal 22502 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 literal 0 HcmV?d00001 diff --git a/kibot/layer.py b/kibot/layer.py index 9a94788b..74b40ff1 100644 --- a/kibot/layer.py +++ b/kibot/layer.py @@ -15,6 +15,29 @@ from . import log logger = log.get_logger() +LAYER_ORDER = ['F.Cu', 'F.Mask', 'F.SilkS', 'F.Paste', 'F.Adhes', 'F.CrtYd', 'F.Fab', 'Dwgs.User', 'Cmts.User', 'Eco1.User', + 'Eco2.User', 'Edge.Cuts', 'Margin', 'User.1', 'User.2', 'User.3', 'User.4', 'User.5', 'User.6', 'User.7', + 'User.8', 'User.9', 'In1.Cu', 'In2.Cu', 'In3.Cu', 'In4.Cu', 'In5.Cu', 'In6.Cu', 'In7.Cu', 'In8.Cu', 'In9.Cu', + 'In10.Cu', 'In11.Cu', 'In12.Cu', 'In13.Cu', 'In14.Cu', 'In15.Cu', 'In16.Cu', 'In17.Cu', 'In18.Cu', 'In19.Cu', + 'In20.Cu', 'In21.Cu', 'In22.Cu', 'In23.Cu', 'In24.Cu', 'In25.Cu', 'In26.Cu', 'In27.Cu', 'In28.Cu', 'In29.Cu', + 'In30.Cu', 'B.Cu', 'B.Mask', 'B.SilkS', 'B.Paste', 'B.Adhes', 'B.CrtYd', 'B.Fab'] +LAYER_PRIORITY = {} + + +def create_print_priority(board): + """ Fills LAYER_PRIORITY. This is used to sort layers for printing. + It is the way KiCad sorts the layers. + We do it as soon as we have a valid board. """ + global LAYER_PRIORITY + if len(LAYER_PRIORITY) > 0: + return + LAYER_PRIORITY = {board.GetLayerID(name): c for c, name in enumerate(LAYER_ORDER)} + + +def get_priority(id): + return LAYER_PRIORITY.get(id, 1e6) + + class Layer(Optionable): """ A layer description """ # Default names @@ -151,6 +174,7 @@ class Layer(Optionable): layer_cnt = 2 if board: layer_cnt = board.GetCopperLayerCount() + create_print_priority(board) # Get the list of used layers from the board # Used for 'all' but also to validate the layer names if Layer._pcb_layers is None: diff --git a/kibot/out_pcb_print.py b/kibot/out_pcb_print.py index c0a7c436..1293a237 100644 --- a/kibot/out_pcb_print.py +++ b/kibot/out_pcb_print.py @@ -16,14 +16,17 @@ from .optionable import Optionable from .out_base import VariantOptions from .kicad.color_theme import load_color_theme from .macros import macros, document, output_class # noqa: F401 -from .layer import Layer +from .layer import Layer, get_priority from . import PyPDF2 from . import log logger = log.get_logger() # TODO: -# - Opciones de out_pdf y out_any_layer +# - Cache de colores +# - Frame en k5? +# - SVG? +# - rsvg-convert -f pdf -o pp.pdf simple_2layer-F_Cu.svg def hex_to_rgb(value): @@ -216,6 +219,8 @@ class PagesOptions(Optionable): """ Cover the vias """ self.black_holes = True """ Change the drill holes to be black instead of white """ + self.sort_layers = False + """ Try to sort the layers in the same order that uses KiCad for printing """ self.layers = LayerOptions """ [list(dict)] List of layers printed in this page. Order is important, the last goes on top """ @@ -225,6 +230,8 @@ class PagesOptions(Optionable): raise KiPlotConfigurationError("Missing `layers` list") # Fill the ID member for all the layers self.layers = Layer.solve(self.layers) + if self.sort_layers: + self.layers.sort(key=lambda x: get_priority(x._id), reverse=True) if self.sheet_reference_color: self.validate_color('sheet_reference_color')