[Panelize] Added preview option

- Enabled for quick start
This commit is contained in:
Salvador E. Tropea 2022-12-03 18:38:28 -03:00
parent adcdd5fde9
commit 2cea9925d5
8 changed files with 61 additions and 22 deletions

View File

@ -787,7 +787,8 @@ global:
- `time_format`: [string='%H-%M-%S'] Format used for the time we started the script. Uses the `strftime` format. - `time_format`: [string='%H-%M-%S'] Format used for the time we started the script. Uses the `strftime` format.
- `time_reformat`: [boolean=true] Tries to reformat the PCB/SCH date using the `date_format`. - `time_reformat`: [boolean=true] Tries to reformat the PCB/SCH date using the `date_format`.
This assumes you let KiCad fill this value and hence the time is in ISO format (YY-MM-DD). This assumes you let KiCad fill this value and hence the time is in ISO format (YY-MM-DD).
- `units`: [string=''] [millimeters,inches,mils] Default units. Affects `position` and `bom` outputs. Also KiCad 6 dimensions. - `units`: [string=''] [millimeters,inches,mils] Default units. Affects `position`, `bom` and `panelize` outputs.
Also KiCad 6 dimensions.
- `use_dir_for_preflights`: [boolean=true] Use the global `dir` as subdir for the preflights. - `use_dir_for_preflights`: [boolean=true] Use the global `dir` as subdir for the preflights.
- `variant`: [string=''] Default variant to apply to all outputs. - `variant`: [string=''] Default variant to apply to all outputs.
@ -2467,7 +2468,7 @@ Notes:
KiKit 1.0.5 (the last to support KiCad 5) shown some KiKit 1.0.5 (the last to support KiCad 5) shown some
incompatibilities. incompatibilities.
Note that you don't need to specify the units for all distances. Note that you don't need to specify the units for all distances.
If they are omitted they are assumed to be `default_units`. If they are omitted they are assumed to be `units`.
The same is valid for angles, using `default_angles` The same is valid for angles, using `default_angles`
* Valid keys: * Valid keys:
- **`comment`**: [string=''] A comment for documentation purposes. - **`comment`**: [string=''] A comment for documentation purposes.
@ -2764,14 +2765,15 @@ Notes:
- `voffset`: [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system. - `voffset`: [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system.
- `width`: [number|string] Width of the characters (the same parameters as KiCAD uses). - `width`: [number|string] Width of the characters (the same parameters as KiCAD uses).
- **`output`**: [string='%f-%i%I%v.%x'] Filename for the output (%i=panel, %x=kicad_pcb). Affected by global options. - **`output`**: [string='%f-%i%I%v.%x'] Filename for the output (%i=panel, %x=kicad_pcb). Affected by global options.
- `create_preview`: [boolean=false] Use PcbDraw to create a preview of the panel.
- `default_angles`: [string='deg'] [deg,°,rad] Angles used when omitted. - `default_angles`: [string='deg'] [deg,°,rad] Angles used when omitted.
- `default_units`: [string='mm'] [mm,cm,dm,m,mil,inch,in] Units used when omitted.
- `dnf_filter`: [string|list(string)='_none'] Name of the filter to mark components as not fitted. - `dnf_filter`: [string|list(string)='_none'] Name of the filter to mark components as not fitted.
A short-cut to use for simple cases where a variant is an overkill. A short-cut to use for simple cases where a variant is an overkill.
- `pre_transform`: [string|list(string)='_none'] Name of the filter to transform fields before applying other filters. - `pre_transform`: [string|list(string)='_none'] Name of the filter to transform fields before applying other filters.
A short-cut to use for simple cases where a variant is an overkill. A short-cut to use for simple cases where a variant is an overkill.
- `title`: [string=''] Text used to replace the sheet title. %VALUE expansions are allowed. - `title`: [string=''] Text used to replace the sheet title. %VALUE expansions are allowed.
If it starts with `+` the text is concatenated. If it starts with `+` the text is concatenated.
- `units`: [string='mm'] [millimeters,inches,mils,mm,cm,dm,m,mil,inch,in] Units used when omitted.
- `variant`: [string=''] Board variant to apply. - `variant`: [string=''] Board variant to apply.
- `category`: [string|list(string)=''] The category for this output. If not specified an internally defined category is used. - `category`: [string|list(string)=''] The category for this output. If not specified an internally defined category is used.
Categories looks like file system paths, i.e. PCB/fabrication/gerber. Categories looks like file system paths, i.e. PCB/fabrication/gerber.

View File

@ -1214,7 +1214,7 @@ outputs:
# KiKit 1.0.5 (the last to support KiCad 5) shown some # KiKit 1.0.5 (the last to support KiCad 5) shown some
# incompatibilities. # incompatibilities.
# Note that you don't need to specify the units for all distances. # Note that you don't need to specify the units for all distances.
# If they are omitted they are assumed to be `default_units`. # If they are omitted they are assumed to be `units`.
# The same is valid for angles, using `default_angles` # The same is valid for angles, using `default_angles`
- name: 'panelize_example' - name: 'panelize_example'
comment: 'Creates a panel to fabricate various copies of the PCB at once.' comment: 'Creates a panel to fabricate various copies of the PCB at once.'
@ -1662,10 +1662,10 @@ outputs:
type: 'none' type: 'none'
# [number|string] Vertical offset from panel edges # [number|string] Vertical offset from panel edges
voffset: 0 voffset: 0
# [boolean=false] Use PcbDraw to create a preview of the panel
create_preview: false
# [string='deg'] [deg,°,rad] Angles used when omitted # [string='deg'] [deg,°,rad] Angles used when omitted
default_angles: 'deg' default_angles: 'deg'
# [string='mm'] [mm,cm,dm,m,mil,inch,in] Units used when omitted
default_units: 'mm'
# [string|list(string)='_none'] Name of the filter to mark components as not fitted. # [string|list(string)='_none'] Name of the filter to mark components as not fitted.
# A short-cut to use for simple cases where a variant is an overkill # A short-cut to use for simple cases where a variant is an overkill
dnf_filter: '_none' dnf_filter: '_none'
@ -1677,6 +1677,8 @@ outputs:
# [string=''] Text used to replace the sheet title. %VALUE expansions are allowed. # [string=''] Text used to replace the sheet title. %VALUE expansions are allowed.
# If it starts with `+` the text is concatenated # If it starts with `+` the text is concatenated
title: '' title: ''
# [string='mm'] [millimeters,inches,mils,mm,cm,dm,m,mil,inch,in] Units used when omitted
units: 'mm'
# [string=''] Board variant to apply # [string=''] Board variant to apply
variant: '' variant: ''
# PCB Print: # PCB Print:

View File

@ -226,7 +226,8 @@ class Globals(FiltersOptions):
""" Tries to reformat the PCB/SCH date using the `date_format`. """ Tries to reformat the PCB/SCH date using the `date_format`.
This assumes you let KiCad fill this value and hence the time is in ISO format (YY-MM-DD) """ This assumes you let KiCad fill this value and hence the time is in ISO format (YY-MM-DD) """
self.units = '' self.units = ''
""" [millimeters,inches,mils] Default units. Affects `position` and `bom` outputs. Also KiCad 6 dimensions """ """ [millimeters,inches,mils] Default units. Affects `position`, `bom` and `panelize` outputs.
Also KiCad 6 dimensions """
self.use_dir_for_preflights = True self.use_dir_for_preflights = True
""" Use the global `dir` as subdir for the preflights """ """ Use the global `dir` as subdir for the preflights """
self.variant = '' self.variant = ''

View File

@ -395,6 +395,10 @@ class GS(object):
""" Will be repplaced by kiplot.py """ """ Will be repplaced by kiplot.py """
raise AssertionError() raise AssertionError()
@staticmethod
def load_board_low_level(file):
return pcbnew.LoadBoard(file)
@staticmethod @staticmethod
def load_sch(): def load_sch():
""" Will be repplaced by kiplot.py """ """ Will be repplaced by kiplot.py """
@ -423,6 +427,12 @@ class GS(object):
""" Looks for a dependency """ """ Looks for a dependency """
return GS.check_tool_dep(context, name, fatal=False) return GS.check_tool_dep(context, name, fatal=False)
@staticmethod
def reload_project(pro_name):
sm = pcbnew.GetSettingsManager()
sm.UnloadProject(GS.board.GetProject(), False)
assert sm.LoadProject(pro_name)
@staticmethod @staticmethod
def get_resource_path(name): def get_resource_path(name):
# Try relative to the script # Try relative to the script

View File

@ -16,7 +16,8 @@ import json
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from .error import KiPlotConfigurationError from .error import KiPlotConfigurationError
from .gs import GS from .gs import GS
from .kiplot import run_command from .kiplot import run_command, config_output
from .layer import Layer from .layer import Layer
from .misc import W_PANELEMPTY from .misc import W_PANELEMPTY
from .optionable import BaseOptions from .optionable import BaseOptions
@ -49,7 +50,7 @@ class PanelOptions(BaseOptions):
if val is None: if val is None:
continue continue
if isinstance(val, (int, float)): if isinstance(val, (int, float)):
setattr(self, op, str(val)+self._parent._parent.default_units) setattr(self, op, str(val)+self._parent._parent.units)
else: else:
m = PanelOptions._num_regex.match(val) m = PanelOptions._num_regex.match(val)
if m is None: if m is None:
@ -583,6 +584,7 @@ class PanelizeConfig(PanelOptions):
class PanelizeOptions(VariantOptions): class PanelizeOptions(VariantOptions):
_extends_regex = re.compile(r'(.+)\[(.+)\]') _extends_regex = re.compile(r'(.+)\[(.+)\]')
_unit_alias = {'millimeters': 'mm', 'inches': 'inch', 'mils': 'mil'}
def __init__(self): def __init__(self):
with document: with document:
@ -596,10 +598,12 @@ class PanelizeOptions(VariantOptions):
self.title = '' self.title = ''
""" Text used to replace the sheet title. %VALUE expansions are allowed. """ Text used to replace the sheet title. %VALUE expansions are allowed.
If it starts with `+` the text is concatenated """ If it starts with `+` the text is concatenated """
self.default_units = 'mm' self.units = 'mm'
""" [mm,cm,dm,m,mil,inch,in] Units used when omitted """ """ [millimeters,inches,mils,mm,cm,dm,m,mil,inch,in] Units used when omitted """
self.default_angles = 'deg' self.default_angles = 'deg'
""" [deg,°,rad] Angles used when omitted """ """ [deg,°,rad] Angles used when omitted """
self.create_preview = False
""" Use PcbDraw to create a preview of the panel """
super().__init__() super().__init__()
self._expand_id = 'panel' self._expand_id = 'panel'
self._expand_ext = 'kicad_pcb' self._expand_ext = 'kicad_pcb'
@ -684,6 +688,7 @@ class PanelizeOptions(VariantOptions):
if configs: if configs:
list(map(self.solve_extends, filter(lambda x: 'extends' in x, configs))) list(map(self.solve_extends, filter(lambda x: 'extends' in x, configs)))
super().config(parent) super().config(parent)
self.units = PanelizeOptions._unit_alias.get(self.units, self.units)
if isinstance(self.configs, type): if isinstance(self.configs, type):
logger.warning(W_PANELEMPTY+'Generating a panel with default options, not very useful') logger.warning(W_PANELEMPTY+'Generating a panel with default options, not very useful')
self.configs = [] self.configs = []
@ -705,6 +710,23 @@ class PanelizeOptions(VariantOptions):
f.write(js) f.write(js)
return f.name return f.name
def create_preview_file(self, name):
if not self.create_preview or not os.path.isfile(name):
return
img_name = os.path.splitext(name)[0]+'.png'
tree = {'name': '_temporal_pcbdraw_preview',
'type': 'pcbdraw',
'comment': 'Internally created for panel preview',
'options': {'output': img_name, 'variant': '', 'format': 'png'}}
out = RegOutput.get_class_for('pcbdraw')()
out.set_tree(tree)
config_output(out)
logger.debug('Loading PCB panel ...')
board = GS.load_board_low_level(name)
logger.debug('Creating preview image ...')
out.options.create_image(img_name, board)
GS.reload_project(GS.pro_file)
def run(self, output): def run(self, output):
cmd_kikit, version = self.ensure_tool_get_ver('KiKit') cmd_kikit, version = self.ensure_tool_get_ver('KiKit')
if GS.ki5 and version >= (1, 1, 0): if GS.ki5 and version >= (1, 1, 0):
@ -742,6 +764,7 @@ class PanelizeOptions(VariantOptions):
cmd.append(output) cmd.append(output)
try: try:
run_command(cmd) run_command(cmd)
self.create_preview_file(output)
finally: finally:
# Remove temporals # Remove temporals
for f in to_remove: for f in to_remove:
@ -763,7 +786,7 @@ class Panelize(BaseOutput): # noqa: F821
KiKit 1.0.5 (the last to support KiCad 5) shown some KiKit 1.0.5 (the last to support KiCad 5) shown some
incompatibilities. incompatibilities.
Note that you don't need to specify the units for all distances. Note that you don't need to specify the units for all distances.
If they are omitted they are assumed to be `default_units`. If they are omitted they are assumed to be `units`.
The same is valid for angles, using `default_angles` """ The same is valid for angles, using `default_angles` """
def __init__(self): def __init__(self):
super().__init__() super().__init__()

View File

@ -431,8 +431,7 @@ class PcbDrawOptions(VariantOptions):
plot_components.highlight = lambda ref: ref in highlight_set plot_components.highlight = lambda ref: ref in highlight_set
return plot_components return plot_components
def run(self, name): def create_image(self, name, board):
super().run(name)
self.ensure_tool('LXML') self.ensure_tool('LXML')
from .PcbDraw.plot import PcbPlotter, PlotPaste, PlotPlaceholders, PlotSubstrate, PlotVCuts from .PcbDraw.plot import PcbPlotter, PlotPaste, PlotPlaceholders, PlotSubstrate, PlotVCuts
# Select a name and format that PcbDraw can handle # Select a name and format that PcbDraw can handle
@ -449,11 +448,8 @@ class PcbDrawOptions(VariantOptions):
self.convert_command = self.ensure_tool('ImageMagick') self.convert_command = self.ensure_tool('ImageMagick')
save_output_name = _get_tmp_name('.png') save_output_name = _get_tmp_name('.png')
# Apply any variant
self.filter_pcb_components(GS.board, do_3D=True)
try: try:
plotter = PcbPlotter(GS.board) plotter = PcbPlotter(board)
# Read libs from KiBot resources # Read libs from KiBot resources
plotter.setup_arbitrary_data_path(GS.get_resource_path('pcbdraw')) plotter.setup_arbitrary_data_path(GS.get_resource_path('pcbdraw'))
# Libs indicated by PCBDRAW_LIB_PATH # Libs indicated by PCBDRAW_LIB_PATH
@ -522,6 +518,12 @@ class PcbDrawOptions(VariantOptions):
_run_command(cmd) _run_command(cmd)
os.remove(save_output_name) os.remove(save_output_name)
def run(self, name):
super().run(name)
# Apply any variant
self.filter_pcb_components(GS.board, do_3D=True)
# Create the image
self.create_image(name, GS.board)
# Undo the variant # Undo the variant
self.unfilter_pcb_components(GS.board, do_3D=True) self.unfilter_pcb_components(GS.board, do_3D=True)

View File

@ -10,7 +10,6 @@ Dependencies:
""" """
import json import json
import os import os
import pcbnew
import re import re
from subprocess import run, PIPE from subprocess import run, PIPE
import sys import sys
@ -150,8 +149,7 @@ class Set_Text_Variables(BasePreFlight): # noqa: F821
f.write(json.dumps(data, sort_keys=True, indent=2)) f.write(json.dumps(data, sort_keys=True, indent=2))
if GS.board: if GS.board:
# Force a project reload # Force a project reload
sm = pcbnew.GetSettingsManager() GS.reload_project(pro_name)
sm.UnloadProject(GS.board.GetProject(), False) # TODO: Do we really need to reload the PCB?
assert sm.LoadProject(pro_name)
# Force the PCB reload (will reload the project file) # Force the PCB reload (will reload the project file)
GS.board = None GS.board = None

View File

@ -10,6 +10,7 @@ outputs:
options: options:
title: '+ (Panel)' title: '+ (Panel)'
default_units: mm default_units: mm
create_preview: true
configs: configs:
- layout: - layout:
rows: 4 rows: 4