diff --git a/CHANGELOG.md b/CHANGELOG.md index ba00b85b..05c48325 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Drawings removed from *.Adhes - Components crossed in *.Fab - STEP (3D) support for variants. +- PcbDraw support for variants. ### Fixed - Virtual components are always excluded from position files. diff --git a/Makefile b/Makefile index 0e0fb40c..1c1102b1 100644 --- a/Makefile +++ b/Makefile @@ -110,6 +110,8 @@ gen_ref: mv "$(REFDIR)no_inductor/test_v5-schematic_(no_L).pdf" $(REFDIR) rmdir $(REFDIR)no_inductor/ src/kibot -b tests/board_samples/kibom-variant_4.kicad_pcb -c tests/yaml_samples/pdf_variant_1.kibot.yaml -d $(REFDIR) + src/kibot -b tests/board_samples/kibom-variant_3.kicad_pcb -c tests/yaml_samples/pcbdraw_variant_1.kibot.yaml -d $(REFDIR) + src/kibot -b tests/board_samples/kibom-variant_3.kicad_pcb -c tests/yaml_samples/pcbdraw_variant_2.kibot.yaml -d $(REFDIR) cp -a $(REFILL).ok $(REFILL) doc: diff --git a/README.md b/README.md index 7efee06a..f1f9f4fb 100644 --- a/README.md +++ b/README.md @@ -725,6 +725,8 @@ Next time you need this list just use an alias, like this: - `options`: [dict] Options for the `pcbdraw` output. * Valid keys: - `bottom`: [boolean=false] render the bottom side of the board (default is top side). + - `dnf_filter`: [string|list(string)=''] Name of the filter to mark components as not fitted. + A short-cut to use for simple cases where a variant is an overkill. - `dpi`: [number=300] [10,1200] dots per inch (resolution) of the generated image. - `format`: [string='svg'] [svg,png,jpg] output format. Only used if no `output` is specified. - `highlight`: [list(string)=[]] list of components to highlight. @@ -734,7 +736,7 @@ Next time you need this list just use an alias, like this: - `output`: [string='%f-%i%v.%x'] name for the generated file. Affected by global options. - `placeholder`: [boolean=false] show placeholder for missing components. - `remap`: [dict|None] replacements for PCB references using components (lib:component). - - `show_components`: [string|list(string)=none] [none,all] list of components to draw, can be also a string for none or all. + - `show_components`: [list(string)|string=none] [none,all] list of components to draw, can be also a string for none or all. The default is none. - `style`: [string|dict] PCB style (colors). An internal name, the name of a JSON file or the style options. * Valid keys: @@ -748,6 +750,7 @@ Next time you need this list just use an alias, like this: - `pads`: [string='#b5ae30'] color for the exposed pads (metal finish). - `silk`: [string='#f0f0f0'] color for the silk screen. - `vcut`: [string='#bf2600'] color for the V-CUTS. + - `variant`: [string=''] Board variant to apply. - `vcuts`: [boolean=false] render V-CUTS on the Cmts.User layer. - `warnings`: [string='visible'] [visible,all,none] using visible only the warnings about components in the visible side are generated. diff --git a/docs/samples/generic_plot.kibot.yaml b/docs/samples/generic_plot.kibot.yaml index e6a8d6a8..0bd0aa91 100644 --- a/docs/samples/generic_plot.kibot.yaml +++ b/docs/samples/generic_plot.kibot.yaml @@ -531,6 +531,9 @@ outputs: options: # [boolean=false] render the bottom side of the board (default is top side) bottom: false + # [string|list(string)=''] Name of the filter to mark components as not fitted. + # A short-cut to use for simple cases where a variant is an overkill + dnf_filter: '' # [number=300] [10,1200] dots per inch (resolution) of the generated image dpi: 300 # [string='svg'] [svg,png,jpg] output format. Only used if no `output` is specified @@ -549,7 +552,7 @@ outputs: placeholder: false # [dict|None] replacements for PCB references using components (lib:component) remap: - # [string|list(string)=none] [none,all] list of components to draw, can be also a string for none or all. + # [list(string)|string=none] [none,all] list of components to draw, can be also a string for none or all. # The default is none show_components: none # [string|dict] PCB style (colors). An internal name, the name of a JSON file or the style options @@ -574,6 +577,8 @@ outputs: silk: '#f0f0f0' # [string='#bf2600'] color for the V-CUTS vcut: '#bf2600' + # [string=''] Board variant to apply + variant: '' # [boolean=false] render V-CUTS on the Cmts.User layer vcuts: false # [string='visible'] [visible,all,none] using visible only the warnings about components in the visible side are generated diff --git a/kibot/out_pcbdraw.py b/kibot/out_pcbdraw.py index 96369194..f68dcec8 100644 --- a/kibot/out_pcbdraw.py +++ b/kibot/out_pcbdraw.py @@ -13,7 +13,10 @@ from .misc import PCBDRAW, PCBDRAW_ERR, URL_PCBDRAW from .kiplot import check_script from .error import KiPlotConfigurationError from .gs import (GS) -from .optionable import (BaseOptions, Optionable) +from .optionable import BaseOptions, Optionable +from .registrable import RegOutput +from .kiplot import load_sch +from .fil_base import BaseFilter, apply_fitted_filter from .macros import macros, document, output_class # noqa: F401 from . import log @@ -136,6 +139,11 @@ class PcbDrawOptions(BaseOptions): """ [svg,png,jpg] output format. Only used if no `output` is specified """ self.output = GS.def_global_output """ name for the generated file """ + self.variant = '' + """ Board variant to apply """ + self.dnf_filter = Optionable + """ [string|list(string)=''] Name of the filter to mark components as not fitted. + A short-cut to use for simple cases where a variant is an overkill """ super().__init__() def config(self): @@ -150,10 +158,15 @@ class PcbDrawOptions(BaseOptions): self.highlight = None else: self.highlight = ','.join(self.highlight) + # Variants + self.variant = RegOutput.check_variant(self.variant) + self.dnf_filter = BaseFilter.solve_filter(self.dnf_filter, 'dnf_filter') # Filter if isinstance(self.show_components, type): self.show_components = '' elif isinstance(self.show_components, str): + if self.variant or self.dnf_filter: + logger.warning('Ambiguous list of components to show `{}` vs variant/filter'.format(self.show_components)) if self.show_components == 'none': self.show_components = '' else: @@ -204,6 +217,39 @@ class PcbDrawOptions(BaseOptions): f.close() return f.name + def get_filtered_refs(self): + if not self.dnf_filter and not self.variant: + return [] + load_sch() + # Get the components list from the schematic + comps = GS.sch.get_components() + # Apply the filter + apply_fitted_filter(comps, self.dnf_filter) + # Apply the variant + if self.variant: + # Apply the variant + self.variant.filter(comps) + return [c.ref for c in comps if c.fitted] + + def _append_output(self, cmd, output): + svg = None + if self.format == 'svg': + cmd.append(output) + else: + # PNG and JPG outputs are unreliable + if shutil.which(SVG2PNG) is None: + logger.warning('`{}` not installed, using unreliable PNG/JPG conversion'.format(SVG2PNG)) + logger.warning('If you experiment problems install `librsvg2-bin` or equivalent') + cmd.append(output) + elif shutil.which(CONVERT) is None: + logger.warning('`{}` not installed, using unreliable PNG/JPG conversion'.format(CONVERT)) + logger.warning('If you experiment problems install `imagemagick` or equivalent') + cmd.append(output) + else: + svg = _get_tmp_name('.svg') + cmd.append(svg) + return svg + def run(self, output_dir, board): check_script(PCBDRAW, URL_PCBDRAW, '0.6.0') # Output file name @@ -231,6 +277,10 @@ class PcbDrawOptions(BaseOptions): if self.highlight: cmd.extend(['-a', self.highlight]) if self.show_components is not None: + to_add = ','.join(self.get_filtered_refs()) + if self.show_components and to_add: + self.show_components += ',' + self.show_components += to_add cmd.extend(['-f', self.show_components]) if self.vcuts: cmd.append('-v') @@ -247,22 +297,7 @@ class PcbDrawOptions(BaseOptions): tmp_remap = None # The board & output cmd.append(GS.pcb_file) - svg = None - if self.format == 'svg': - cmd.append(output) - else: - # PNG and JPG outputs are unreliable - if shutil.which(SVG2PNG) is None: - logger.warning('`{}` not installed, using unreliable PNG/JPG conversion'.format(SVG2PNG)) - logger.warning('If you experiment problems install `librsvg2-bin` or equivalent') - cmd.append(output) - elif shutil.which(CONVERT) is None: - logger.warning('`{}` not installed, using unreliable PNG/JPG conversion'.format(CONVERT)) - logger.warning('If you experiment problems install `imagemagick` or equivalent') - cmd.append(output) - else: - svg = _get_tmp_name('.svg') - cmd.append(svg) + svg = self._append_output(cmd, output) # Execute and inform is successful _run_command(cmd, tmp_remap, tmp_style) if svg is not None: diff --git a/tests/reference/kibom-variant_3-top-C1.png b/tests/reference/kibom-variant_3-top-C1.png new file mode 100644 index 00000000..167932a5 Binary files /dev/null and b/tests/reference/kibom-variant_3-top-C1.png differ diff --git a/tests/reference/kibom-variant_3-top.png b/tests/reference/kibom-variant_3-top.png new file mode 100644 index 00000000..2197a984 Binary files /dev/null and b/tests/reference/kibom-variant_3-top.png differ diff --git a/tests/test_plot/test_pcbdraw.py b/tests/test_plot/test_pcbdraw.py index ba72405f..5333604b 100644 --- a/tests/test_plot/test_pcbdraw.py +++ b/tests/test_plot/test_pcbdraw.py @@ -69,6 +69,7 @@ def test_pcbdraw_miss_rsvg(caplog, monkeypatch): o.style = '' o.remap = None o.format = 'jpg' + o.config() cov.load() cov.start() o.run('', None) @@ -87,6 +88,7 @@ def test_pcbdraw_miss_convert(caplog, monkeypatch): o.style = '' o.remap = None o.format = 'jpg' + o.config() cov.load() cov.start() o.run('', None) @@ -94,3 +96,37 @@ def test_pcbdraw_miss_convert(caplog, monkeypatch): cov.save() assert 'using unreliable PNG/JPG' in caplog.text, caplog.text assert 'imagemagick' in caplog.text, caplog.text + + +def test_pcbdraw_variant_1(): + prj = 'kibom-variant_3' + ctx = context.TestContext('test_pcbdraw_variant_1', prj, 'pcbdraw_variant_1', '') + ctx.run() + # Check all outputs are there + fname = prj+'-top.png' + ctx.expect_out_file(fname) + ctx.compare_image(fname) + ctx.clean_up() + + +def test_pcbdraw_variant_2(): + prj = 'kibom-variant_3' + ctx = context.TestContext('test_pcbdraw_variant_2', prj, 'pcbdraw_variant_2', '') + ctx.run() + # Check all outputs are there + fname = prj+'-top-C1.png' + ctx.expect_out_file(fname) + ctx.compare_image(fname) + ctx.clean_up() + + +def test_pcbdraw_variant_3(): + prj = 'kibom-variant_3' + ctx = context.TestContext('test_pcbdraw_variant_1', prj, 'pcbdraw_variant_3', '') + ctx.run() + # Check all outputs are there + fname = prj+'-top.png' + ctx.expect_out_file(fname) + ctx.compare_image(fname) + assert ctx.search_err("Ambiguous list of components to show .?none.? vs variant/filter") + ctx.clean_up() diff --git a/tests/yaml_samples/pcbdraw_simple.kibot.yaml b/tests/yaml_samples/pcbdraw_simple.kibot.yaml index 1c4a919a..f2544518 100644 --- a/tests/yaml_samples/pcbdraw_simple.kibot.yaml +++ b/tests/yaml_samples/pcbdraw_simple.kibot.yaml @@ -13,6 +13,7 @@ outputs: mirror: True vcuts: True warnings: all + show_components: all - name: PcbDraw comment: "PcbDraw test bottom" diff --git a/tests/yaml_samples/pcbdraw_variant_1.kibot.yaml b/tests/yaml_samples/pcbdraw_variant_1.kibot.yaml new file mode 100644 index 00000000..ccd4c8f4 --- /dev/null +++ b/tests/yaml_samples/pcbdraw_variant_1.kibot.yaml @@ -0,0 +1,18 @@ +# Example KiBot config file +kibot: + version: 1 + +variants: + - name: 'default' + comment: 'Default variant' + type: ibom + variants_blacklist: T2,T3 + +outputs: + - name: 'pcbdraw_default' + comment: "PcbDraw w/variant" + type: pcbdraw + options: + variant: default + format: png + diff --git a/tests/yaml_samples/pcbdraw_variant_2.kibot.yaml b/tests/yaml_samples/pcbdraw_variant_2.kibot.yaml new file mode 100644 index 00000000..77910499 --- /dev/null +++ b/tests/yaml_samples/pcbdraw_variant_2.kibot.yaml @@ -0,0 +1,22 @@ +# Example KiBot config file +kibot: + version: 1 + +variants: + - name: 'default' + comment: 'Default variant' + type: ibom + file_id: '-C1' + variants_blacklist: T2,T3 + +outputs: + - name: 'pcbdraw_default' + comment: "PcbDraw w/variant" + type: pcbdraw + options: + variant: default + format: png + # This isn't a good idea, but works + show_components: + - 'C1' + diff --git a/tests/yaml_samples/pcbdraw_variant_3.kibot.yaml b/tests/yaml_samples/pcbdraw_variant_3.kibot.yaml new file mode 100644 index 00000000..7c790561 --- /dev/null +++ b/tests/yaml_samples/pcbdraw_variant_3.kibot.yaml @@ -0,0 +1,19 @@ +# Example KiBot config file +kibot: + version: 1 + +variants: + - name: 'default' + comment: 'Default variant' + type: ibom + variants_blacklist: T2,T3 + +outputs: + - name: 'pcbdraw_default' + comment: "PcbDraw w/variant" + type: pcbdraw + options: + variant: default + format: png + # This is incoherent: all or filtered? + show_components: none