[Panelize] Added mechanism to extend defined options.

This commit is contained in:
Salvador E. Tropea 2022-11-30 17:01:40 -03:00
parent 5750cfd10a
commit 425840059c
7 changed files with 558 additions and 18 deletions

View File

@ -2451,6 +2451,9 @@ Notes:
* Description: Creates a panel to fabricate various copies of the PCB at once.
It currently uses the KiKit tool, which must be available.
Consult KiKit docs for detailed information.
Current versions of KiKit only support KiCad 6 and my tests using
KiKit 1.0.5 (the last to support KiCad 5) shown some
incompatibilities.
Note that you don't need to specify the units for all distances.
If they are omitted they are assumed to be `default_units`.
The same is valid for angles, using `default_angles`
@ -2605,6 +2608,9 @@ Notes:
- `drawboxes`: [boolean=false] Draw boxes.
- `drawtabfail`: [boolean=false] Draw tab fail.
- `trace`: [boolean=false] Trace.
- `extends`: [string=''] A configuration to use as base for this one. Use the following format: `OUTPUT_NAME[CFG_NAME]`.
- `name`: [string=''] A name to identify this configuration. If empty will be the order in the list, starting with 1.
Don't use just a number or it will be confused as an index.
- `post`: [dict] Finishing touches to the panel.
* Valid keys:
- `copperfill`: [boolean=false] Fill tabs and frame with copper (e.g., to save etchant or to increase rigidity of flex-PCB panels).
@ -2647,7 +2653,7 @@ Notes:
*boardCompany* the company from the source board,
*boardComment1*-*boardComment9* comments from the source board.
- `thickness`: [number|string] Stroke thickness.
- `type`: [string='simple'] [simple] Currently fixed.
- `type`: [string='none'] [none,simple] Currently fixed. BTW: don't ask me about this ridiculous default, is how KiKit works.
- `vjustify`: [string='center'] [left,right,center] Vertical justification of the text.
- `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).
@ -2669,7 +2675,7 @@ Notes:
*boardCompany* the company from the source board,
*boardComment1*-*boardComment9* comments from the source board.
- `thickness`: [number|string] Stroke thickness.
- `type`: [string='simple'] [simple] Currently fixed.
- `type`: [string='none'] [none,simple] Currently fixed. BTW: don't ask me about this ridiculous default, is how KiKit works.
- `vjustify`: [string='center'] [left,right,center] Vertical justification of the text.
- `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).
@ -2691,7 +2697,7 @@ Notes:
*boardCompany* the company from the source board,
*boardComment1*-*boardComment9* comments from the source board.
- `thickness`: [number|string] Stroke thickness.
- `type`: [string='simple'] [simple] Currently fixed.
- `type`: [string='none'] [none,simple] Currently fixed. BTW: don't ask me about this ridiculous default, is how KiKit works.
- `vjustify`: [string='center'] [left,right,center] Vertical justification of the text.
- `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).
@ -2713,7 +2719,7 @@ Notes:
*boardCompany* the company from the source board,
*boardComment1*-*boardComment9* comments from the source board.
- `thickness`: [number|string] Stroke thickness.
- `type`: [string='simple'] [simple] Currently fixed.
- `type`: [string='none'] [none,simple] Currently fixed. BTW: don't ask me about this ridiculous default, is how KiKit works.
- `vjustify`: [string='center'] [left,right,center] Vertical justification of the text.
- `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).

View File

@ -1209,6 +1209,9 @@ outputs:
# Panelize:
# It currently uses the KiKit tool, which must be available.
# Consult KiKit docs for detailed information.
# Current versions of KiKit only support KiCad 6 and my tests using
# KiKit 1.0.5 (the last to support KiCad 5) shown some
# incompatibilities.
# Note that you don't need to specify the units for all distances.
# If they are omitted they are assumed to be `default_units`.
# The same is valid for angles, using `default_angles`
@ -1275,6 +1278,8 @@ outputs:
drawtabfail: false
# [boolean=false] Trace
trace: false
# [string=''] A configuration to use as base for this one. Use the following format: `OUTPUT_NAME[CFG_NAME]`
extends: ''
# [dict] Used to add fiducial marks to the (rail/frame of) the panel
fiducials:
# `copper_size` is an alias for `coppersize`
@ -1370,6 +1375,9 @@ outputs:
vboneskip: 0
# [number|string] Specify the vertical gap between the boards
vspace: 0
# [string=''] A name to identify this configuration. If empty will be the order in the list, starting with 1.
# Don't use just a number or it will be confused as an index
name: ''
# [dict] Sets page size on the resulting panel and position the panel in the page
page:
# [string='tl'] [tl,tr,bl,br,mt,mb,ml,mr,c] Point of the panel to be placed at given position. Can be one of tl, tr, bl, br
@ -1481,8 +1489,8 @@ outputs:
text: ''
# [number|string] Stroke thickness
thickness: 0.3
# [string='simple'] [simple] Currently fixed
type: 'simple'
# [string='none'] [none,simple] Currently fixed. BTW: don't ask me about this ridiculous default, is how KiKit works
type: 'none'
# [string='center'] [left,right,center] Vertical justification of the text
vjustify: 'center'
# [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system
@ -1515,8 +1523,8 @@ outputs:
text: ''
# [number|string] Stroke thickness
thickness: 0.3
# [string='simple'] [simple] Currently fixed
type: 'simple'
# [string='none'] [none,simple] Currently fixed. BTW: don't ask me about this ridiculous default, is how KiKit works
type: 'none'
# [string='center'] [left,right,center] Vertical justification of the text
vjustify: 'center'
# [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system
@ -1549,8 +1557,8 @@ outputs:
text: ''
# [number|string] Stroke thickness
thickness: 0.3
# [string='simple'] [simple] Currently fixed
type: 'simple'
# [string='none'] [none,simple] Currently fixed. BTW: don't ask me about this ridiculous default, is how KiKit works
type: 'none'
# [string='center'] [left,right,center] Vertical justification of the text
vjustify: 'center'
# [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system
@ -1583,8 +1591,8 @@ outputs:
text: ''
# [number|string] Stroke thickness
thickness: 0.3
# [string='simple'] [simple] Currently fixed
type: 'simple'
# [string='none'] [none,simple] Currently fixed. BTW: don't ask me about this ridiculous default, is how KiKit works
type: 'none'
# [string='center'] [left,right,center] Vertical justification of the text
vjustify: 'center'
# [number|string] Specify the vertical offset from anchor. Respects KiCAD coordinate system

View File

@ -195,7 +195,18 @@ class Optionable(object):
new_val.append(element)
v = new_val
# Seems to be ok, map it
setattr(self, alias if is_alias else k, v)
dest_name = alias if is_alias else k
setattr(self, dest_name, v)
self.set_user_defined(dest_name)
def set_user_defined(self, name):
setattr(self, '_{}_user_defined'.format(name), True)
def get_user_defined(self, name):
name = '_{}_user_defined'.format(name)
if hasattr(self, name):
return getattr(self, name)
return False
def set_tree(self, tree):
self._tree = tree

View File

@ -11,6 +11,8 @@ Dependencies:
downloader: pytool
role: mandatory
"""
import collections
from copy import deepcopy
import os
import re
import json
@ -22,12 +24,24 @@ from .layer import Layer
from .misc import W_PANELEMPTY
from .optionable import BaseOptions
from .out_base import VariantOptions
from .registrable import RegOutput
from .macros import macros, document, output_class # noqa: F401
from . import log
logger = log.get_logger()
def update_dict(d, u):
for k, v in u.items():
if isinstance(v, collections.abc.Mapping):
d[k] = update_dict(d.get(k, {}), v)
elif isinstance(v, list) and k in d:
d[k] = v+d[k]
else:
d[k] = v
return d
class PanelOptions(BaseOptions):
_num_regex = re.compile(r'([\d\.]+)(mm|cm|dm|m|mil|inch|in)')
_ang_regex = re.compile(r'([\d\.]+)(deg|°|rad)')
@ -336,8 +350,8 @@ class PanelizeFiducials(PanelOptions):
class PanelizeText(PanelOptions):
def __init__(self):
with document:
self.type = 'simple'
""" [simple] Currently fixed """
self.type = 'none'
""" [none,simple] Currently fixed. BTW: don't ask me about this ridiculous default, is how KiKit works """
self.text = ''
""" The text to be displayed. Note that you can escape ; via \\.
Available variables in text: *date* formats current date as <year>-<month>-<day>,
@ -474,6 +488,11 @@ class PanelizeDebug(PanelOptions):
class PanelizeConfig(PanelOptions):
def __init__(self):
with document:
self.name = ''
""" A name to identify this configuration. If empty will be the order in the list, starting with 1.
Don't use just a number or it will be confused as an index """
self.extends = ''
""" A configuration to use as base for this one. Use the following format: `OUTPUT_NAME[CFG_NAME]` """
self.page = PanelizePage
""" *[dict] Sets page size on the resulting panel and position the panel in the page """
self.layout = PanelizeLayout
@ -506,6 +525,15 @@ class PanelizeConfig(PanelOptions):
def config(self, parent):
super().config(parent)
# Avoid confusing names
name_is_number = True
try:
_ = int(self.name)
except ValueError:
name_is_number = False
if name_is_number:
raise KiPlotConfigurationError("Don't use a number as name, this can be confused with an index ({})".
format(self.name))
# Make None all things not specified
for k, v in self.get_attrs_gen():
if isinstance(v, type):
@ -513,6 +541,8 @@ class PanelizeConfig(PanelOptions):
class PanelizeOptions(VariantOptions):
_extends_regex = re.compile(r'(.+)\[(.+)\]')
def __init__(self):
with document:
self.output = GS.def_global_output
@ -533,21 +563,103 @@ class PanelizeOptions(VariantOptions):
self._expand_id = 'panel'
self._expand_ext = 'kicad_pcb'
def solve_cfg_name(self, cfg):
""" Find the name of a configuration that isn't yet configured """
name = cfg.get('name')
if name:
return name
return str(self._tree['configs'].index(cfg)+1)
def solve_extends(self, tree, level=0, used=None, our_name=None):
base = tree.get('extends')
if our_name is None:
our_name = '{}[{}]'.format(self._parent.name, self.solve_cfg_name(tree))
if used is None:
used = {our_name}
else:
if our_name in used:
raise KiPlotConfigurationError('Recursive extends detected in `extends: {}` ({})'.format(base, used))
used.add(our_name)
logger.debugl(1, "Extending from "+base)
# Should be an string
if not isinstance(base, str):
raise KiPlotConfigurationError('`extends` must be a string, not {}'.format(type(base)))
# Extract the output and config names
m = PanelizeOptions._extends_regex.match(base)
if m is None:
raise KiPlotConfigurationError('Malformed `extends` reference: `{}` use OUTPUT_NAME[CFG_NAME]'.format(base))
out_name, cfg_name = m.groups()
# Look for the output
out = RegOutput.get_output(out_name)
if out is None:
raise KiPlotConfigurationError('Unknown output `{}` in `extends: {}`'.format(out_name, base))
# Look for the config
configs = None
out_options = out._tree.get('options')
if out_options:
configs = out_options.get('configs')
if configs is None or isinstance(configs, str):
raise KiPlotConfigurationError("Using `extends: {}` but `{}` hasn't configs to copy". format(base, out_name))
cfg_name_is_number = True
try:
id = int(cfg_name)-1
except ValueError:
cfg_name_is_number = False
if cfg_name_is_number:
# Using an index, is it valid?
if id >= len(configs):
raise KiPlotConfigurationError('Using `extends: {}` but `{}` has {} configs'.
format(base, out_name, len(configs)))
origin = configs[id]
else:
# Using a name
origin = next(filter(lambda x: 'name' in x and x['name'] == cfg_name, configs), None)
if origin is None:
raise KiPlotConfigurationError("Using `extends: {}` but `{}` doesn't define `{}`".
format(base, out_name, cfg_name))
# Now we have the origin
# Does it also use extends?
origin_extends = origin.get('extends')
if origin_extends:
origin = self.solve_extends(origin, level=level+1, used=used, our_name=base)
# Copy the origin, update it and replace the current values
logger.debugl(1, "{} before applying {}: {}".format(our_name, base, tree))
logger.debugl(1, "- Should add {}".format(origin))
new_origin = deepcopy(origin)
update_dict(new_origin, tree)
if level:
tree = deepcopy(tree)
logger.error(tree)
update_dict(tree, new_origin)
if not level:
# Remove the extends, we solved it
del tree['extends']
logger.debugl(1, "After apply: {}".format(tree))
return tree
def config(self, parent):
self._parent = parent
# Look for configs that uses extends
configs = self._tree.get('configs')
if configs:
list(map(self.solve_extends, filter(lambda x: 'extends' in x, configs)))
super().config(parent)
if isinstance(self.configs, type):
logger.warning(W_PANELEMPTY+'Generating a panel with default options, not very useful')
self.configs = []
elif isinstance(self.configs, str):
self.configs = [self.configs]
for c, cfg in enumerate(self.configs):
if not cfg.name:
cfg.name = str(c+1)
def create_config(self, cfg):
with NamedTemporaryFile(mode='w', delete=False, suffix='.json', prefix='kibot_panel_cfg') as f:
logger.debug('Writing panel config to '+f.name)
cfg_d = {}
for k, v in cfg.get_attrs_gen():
if v:
cfg_d[k] = {k: v for k, v in v.get_attrs_gen() if v is not None}
if isinstance(v, PanelOptions):
cfg_d[k] = {ky: va for ky, va in v.get_attrs_gen() if va is not None and v.get_user_defined(ky)}
js = json.dumps(cfg_d, indent=4)
logger.debugl(1, js)
f.write(js)
@ -576,7 +688,7 @@ class PanelizeOptions(VariantOptions):
fname = GS.pcb_file
# Create the command
cmd = [cmd_kikit, 'panelize']
cmd = [cmd_kikit, 'panelize'] # , '--dump', 'test.json'
# Add all the configurations
for cfg in self.configs:
cmd.append('--preset')

View File

@ -52,6 +52,7 @@ outputs:
coppersize: 2
opening: 1
text:
type: simple
text: My panel
anchor: mt
voffset: 2.5

View File

@ -0,0 +1,385 @@
# Example KiBot config file for a basic panel
kibot:
version: 1
outputs:
- name: 'panel_examples'
comment: "The KiKit examples"
type: panelize
run_by_default: false
options:
configs:
- name: basic
layout:
rows: 2
cols: 2
tabs:
type: full
cuts:
type: vcuts
- name: mill_radius_1
post:
mill_radius: 1
- name: basic_with_tabs
extends: panel_examples[basic]
layout:
space: 2
tabs:
type: fixed
hwidth: 10
vwidth: 15
- name: vcuts_railstb
extends: panel_examples[basic_with_tabs]
framing:
type: railstb
width: 5
space: 3
- name: basic_with_mouse_bites
extends: panel_examples[basic_with_tabs]
tabs:
width: 5
cuts:
type: mousebites
drill: 0.5
spacing: 1
offset: 0.2
- name: basic_with_mouse_bites_prolong
extends: panel_examples[basic_with_mouse_bites]
tabs:
width: 3
cuts:
prolong: 0.5
- name: basic_with_mouse_bites_2v
extends: panel_examples[basic_with_mouse_bites_prolong]
tabs:
vcount: 2
- name: basic_with_mouse_bites_fm1
extends: panel_examples[basic_with_mouse_bites_2v]
framing:
type: railstb
width: 5
space: 3
- name: basic_with_mouse_bites_fm2
extends: panel_examples[basic_with_mouse_bites_fm1]
framing:
type: frame
cuts: both
- name: basic_with_mouse_bites_fm3
extends: panel_examples[basic_with_mouse_bites_fm2]
framing:
type: frame
cuts: h
- name: tight
extends: panel_examples[basic]
layout:
space: 6
tabs:
type: fixed
width: 3
vcount: 2
framing:
type: tightframe
width: 5
space: 3
- name: holes_fid_text
extends: panel_examples[basic_with_mouse_bites_fm1]
tooling:
type: 3hole
hoffset: 2.5
voffset: 2.5
size: 1.5
fiducials:
type: 3fid
hoffset: 5
voffset: 2.5
coppersize: 2
opening: 1
text:
type: simple
text: Example panel
anchor: mt
voffset: 2.5
hjustify: center
vjustify: center
- name: holes_fid_text2
extends: panel_examples[holes_fid_text]
text2:
type: simple
text: "Created on {date}"
anchor: mb
voffset: -2.5
hjustify: center
vjustify: center
- name: holes_fid_text_rounded
extends: panel_examples[holes_fid_text]
framing:
fillet: 1
- name: holes_fid_text_chamfer
extends: panel_examples[holes_fid_text]
framing:
chamfer: 1
- name: holes_fid_text_minimal
extends: panel_examples[holes_fid_text]
framing:
type: frame
mintotalheight: 100
mintotalwidth: 100
text:
text: Example panel with minimal dimensions
- name: 'panel_basic'
comment: "Basic example"
type: panelize
output_id: _basic
options:
configs:
- extends: panel_examples[basic]
- name: 'panel_basic_with_mill_radius'
comment: "Basic example + mill radius simulation"
type: panelize
output_id: _basic_with_mill_radius
options:
configs:
- extends: panel_examples[basic]
post:
mill_radius: 1
- name: 'panel_basic_with_tabs'
comment: "Basic example + simple tabs"
type: panelize
output_id: _basic_with_tabs
options:
configs:
- extends: panel_examples[basic_with_tabs]
post:
mill_radius: 1
- name: 'basic_with_mouse_bites'
comment: "Basic example + mouse bites"
type: panelize
output_id: _basic_with_nouse_bites
options:
configs:
- extends: panel_examples[basic_with_mouse_bites]
- name: 'basic_with_mouse_bites_mr'
comment: "Basic example + mouse bites + mill radius simulation"
type: panelize
output_id: _basic_with_nouse_bites_mr
options:
configs:
- extends: panel_examples[basic_with_mouse_bites]
- extends: panel_examples[mill_radius_1]
- name: 'basic_with_mouse_bites_mrp'
comment: "Basic example + mouse bites + prolong + mill radius simulation"
type: panelize
output_id: _basic_with_nouse_bites_mrp
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_prolong]
- extends: panel_examples[mill_radius_1]
- name: 'basic_with_mouse_bites_2v'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + mill radius simulation"
type: panelize
output_id: _basic_with_nouse_bites_2v
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_2v]
- extends: panel_examples[mill_radius_1]
- name: 'basic_with_mouse_bites_fm1'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame h + mill radius simulation"
type: panelize
output_id: _basic_with_nouse_bites_fm1
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm1]
- extends: panel_examples[mill_radius_1]
- name: 'basic_with_mouse_bites_fm2'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame full + mill radius simulation"
type: panelize
output_id: _basic_with_nouse_bites_fm2
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm2]
- extends: panel_examples[mill_radius_1]
- name: 'basic_with_mouse_bites_fm3'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame full h cuts + mill radius simulation"
type: panelize
output_id: _basic_with_nouse_bites_fm3
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm3]
- extends: panel_examples[mill_radius_1]
- name: 'tight'
comment: "Tight frame example"
type: panelize
output_id: _tight
options:
configs:
- extends: panel_examples[tight]
- extends: panel_examples[mill_radius_1]
- name: 'holes_fid_text'
comment: "With marks and text"
type: panelize
output_id: _holes_fid_text
options:
configs:
- extends: panel_examples[holes_fid_text]
- extends: panel_examples[mill_radius_1]
- name: 'holes_fid_text2'
comment: "With marks and two texts"
type: panelize
output_id: _holes_fid_text2
options:
configs:
- extends: panel_examples[holes_fid_text2]
- extends: panel_examples[mill_radius_1]
- name: 'holes_fid_text_rounded'
comment: "With marks and text, rounded"
type: panelize
output_id: _holes_fid_text_rounded
options:
configs:
- extends: panel_examples[holes_fid_text_rounded]
- extends: panel_examples[mill_radius_1]
- name: 'holes_fid_text_chamfer'
comment: "With marks and text, chamfer"
type: panelize
output_id: _holes_fid_text_chamfer
options:
configs:
- extends: panel_examples[holes_fid_text_chamfer]
- extends: panel_examples[mill_radius_1]
- name: 'holes_fid_text_minimal'
comment: "With marks and text, minimal"
type: panelize
output_id: _holes_fid_text_minimal
options:
configs:
- extends: panel_examples[holes_fid_text_minimal]
- extends: panel_examples[mill_radius_1]
- name: 'rotated_45'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame full + rotated + mill radius simulation"
type: panelize
output_id: _rotated_45
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm2]
layout:
rotation: 45
- extends: panel_examples[mill_radius_1]
- name: 'alternated'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame full + alternated + mill radius simulation"
type: panelize
output_id: _alternated
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm2]
layout:
alternation: cols
- extends: panel_examples[mill_radius_1]
- name: 'hbone'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame h + h bone + mill radius simulation"
type: panelize
output_id: _hbone
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm1]
layout:
hbonecut: true
hbackbone: 5
- extends: panel_examples[mill_radius_1]
- name: 'both_bones'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame h + both bones + mill radius simulation"
type: panelize
output_id: _both_bones
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm1]
layout:
rows: 4
cols: 4
hbackbone: 5
vbackbone: 5
hboneskip: 1
vboneskip: 1
- extends: panel_examples[mill_radius_1]
- name: 'spec_tabs'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame h + indicated tabs + mill radius simulation"
type: panelize
output_id: _spec_tabs
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm1]
layout:
space: 5
tabs:
type: annotation
- extends: panel_examples[mill_radius_1]
- name: 'spec_tabs_bones'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame h + indicated tabs + bones + mill radius simulation"
type: panelize
output_id: _spec_tabs_bones
options:
configs:
- extends: spec_tabs[1]
layout:
space: 2
hbackbone: 3
vbackbone: 3
- extends: panel_examples[mill_radius_1]
- name: 'copperfill_solid_1'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame h + copperfill solid + mill radius simulation"
type: panelize
output_id: _copperfill_solid_1
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm1]
copperfill:
type: solid
- extends: panel_examples[mill_radius_1]
- name: 'copperfill_solid_2'
comment: "Copperfill and V-Cuts"
type: panelize
output_id: _copperfill_solid_2
options:
configs:
- extends: panel_examples[vcuts_railstb]
copperfill:
type: solid
cuts:
clearance: 1.5
- extends: panel_examples[mill_radius_1]
- name: 'copperfill_hatched'
comment: "Basic example + mouse bites + prolong + 2 vert tabs + frame h + copperfill hatched + mill radius simulation"
type: panelize
output_id: _copperfill_hatched
options:
configs:
- extends: panel_examples[basic_with_mouse_bites_fm1]
copperfill:
type: hatched
clearance: 2
spacing: 0.5
width: 0.5
- extends: panel_examples[mill_radius_1]

View File

@ -0,0 +1,17 @@
# Example KiBot config file for a basic panel
kibot:
version: 1
outputs:
- name: 'panel'
comment: "Create a 4x4 complex panel"
type: panelize
options:
title: '+ (Panel)'
default_units: mm
configs:
- layout:
rows: 2
cols: 2
page:
anchor: c