[Stencil*] Moved common code to out_any_stencil.py
This commit is contained in:
parent
a9000716a7
commit
2b86ef9e80
|
|
@ -3590,7 +3590,8 @@ Notes:
|
|||
- *frame_width*: Alias for framewidth.
|
||||
- `frameclearance`: [number=0] Clearance for the stencil register [mm].
|
||||
- `framewidth`: [number=1] Register frame width.
|
||||
- `include_scad`: [boolean=true] Include the generated OpenSCAD files. Note that this also includes the DXF files.
|
||||
- `include_scad`: [boolean=true] Include the generated OpenSCAD files.
|
||||
Note that this also includes the DXF files.
|
||||
- *pcb_thickness*: Alias for pcbthickness.
|
||||
- `pcbthickness`: [number=0] PCB thickness [mm]. If 0 we will ask KiCad.
|
||||
- `pre_transform`: [string|list(string)='_none'] Name of the filter to transform fields before applying other filters.
|
||||
|
|
|
|||
|
|
@ -2488,7 +2488,8 @@ outputs:
|
|||
frameclearance: 0
|
||||
# [number=1] Register frame width
|
||||
framewidth: 1
|
||||
# [boolean=true] Include the generated OpenSCAD files. Note that this also includes the DXF files
|
||||
# [boolean=true] Include the generated OpenSCAD files.
|
||||
# Note that this also includes the DXF files
|
||||
include_scad: true
|
||||
# [string='%f-%i%I%v.%x'] Filename for the output (%i='stencil_3d_top'|'stencil_3d_bottom'|'stencil_3d_edge',
|
||||
# %x='stl'|'scad'|'dxf'). Affected by global options
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2022 Salvador E. Tropea
|
||||
# Copyright (c) 2022 Instituto Nacional de Tecnología Industrial
|
||||
# License: GPL-3.0
|
||||
# Project: KiBot (formerly KiPlot)
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from .error import PlotError
|
||||
from .gs import GS
|
||||
from .kiplot import run_command
|
||||
from .out_base import VariantOptions
|
||||
from .misc import W_AUTONONE
|
||||
from .macros import macros, document, output_class # noqa: F401
|
||||
from . import log
|
||||
|
||||
logger = log.get_logger()
|
||||
|
||||
|
||||
class Stencil_Options(VariantOptions):
|
||||
def __init__(self):
|
||||
with document:
|
||||
self.side = 'auto'
|
||||
""" [top,bottom,auto,both] Which side of the PCB we want. Using `auto` will detect which
|
||||
side contains solder paste """
|
||||
self.include_scad = True
|
||||
""" Include the generated OpenSCAD files """
|
||||
self.cutout = ''
|
||||
""" [string|list(string)] List of components to add a cutout based on the component courtyard.
|
||||
This is useful when you have already pre-populated board and you want to populate more
|
||||
components """
|
||||
self.pcbthickness = 0
|
||||
""" PCB thickness [mm]. If 0 we will ask KiCad """
|
||||
self.pcb_thickness = None
|
||||
""" {pcbthickness} """
|
||||
super().__init__()
|
||||
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self.cutout = ','.join(self.force_list(self.cutout))
|
||||
|
||||
def move_output(self, src_dir, src_file, id, ext, replacement=None, patch=False, relative=False):
|
||||
self._expand_id = id
|
||||
self._expand_ext = ext
|
||||
dst_name = self._parent.expand_filename(self._parent.output_dir, self.output)
|
||||
src_name = os.path.join(src_dir, src_file)
|
||||
if not os.path.isfile(src_name):
|
||||
raise PlotError('Missing output file {}'.format(src_name))
|
||||
if patch:
|
||||
# Adjust the names of the DXF files
|
||||
with open(src_name, 'r') as f:
|
||||
content = f.read()
|
||||
for k, v in replacement.items():
|
||||
content = content.replace(k, v)
|
||||
with open(dst_name, 'w') as f:
|
||||
f.write(content)
|
||||
else:
|
||||
shutil.move(src_name, dst_name)
|
||||
if replacement is not None:
|
||||
if relative:
|
||||
src_name = os.path.basename(src_name)
|
||||
replacement[src_name] = os.path.basename(dst_name)
|
||||
|
||||
def run(self, output):
|
||||
cmd_kikit = self.ensure_tool('KiKit')
|
||||
self.ensure_tool('OpenSCAD')
|
||||
super().run(output)
|
||||
# Apply variants and filters
|
||||
filtered = self.filter_pcb_components(GS.board)
|
||||
if self.side == 'auto':
|
||||
detected_top, detected_bottom = self.detect_solder_paste(GS.board)
|
||||
fname = self.save_tmp_board() if filtered else GS.pcb_file
|
||||
if filtered:
|
||||
self.unfilter_pcb_components(GS.board)
|
||||
# Avoid running the tool if we will generate useless models
|
||||
if self.side == 'auto' and not detected_top and not detected_bottom:
|
||||
logger.warning(W_AUTONONE+'No solder paste detected, skipping stencil generation')
|
||||
return
|
||||
# If no PCB thickness indicated ask KiCad
|
||||
if not self.pcbthickness:
|
||||
ds = GS.board.GetDesignSettings()
|
||||
self.pcbthickness = self.to_mm(ds.GetBoardThickness())
|
||||
# Create the command line
|
||||
cmd = self.create_cmd(cmd_kikit)
|
||||
# Create the outputs
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
cmd.append(fname)
|
||||
cmd.append(tmp)
|
||||
try:
|
||||
run_command(cmd)
|
||||
finally:
|
||||
# Remove temporal variant
|
||||
if filtered:
|
||||
GS.remove_pcb_and_pro(fname)
|
||||
# Now copy the files we want
|
||||
# - Which side?
|
||||
do_top = do_bottom = False
|
||||
if self.side == 'top':
|
||||
do_top = True
|
||||
elif self.side == 'bottom':
|
||||
do_bottom = True
|
||||
elif self.side == 'both':
|
||||
do_top = True
|
||||
do_bottom = True
|
||||
else: # auto
|
||||
do_top = detected_top
|
||||
do_bottom = detected_bottom
|
||||
prj_name = os.path.splitext(os.path.basename(fname))[0]
|
||||
self.move_outputs(tmp, prj_name, do_top, do_bottom)
|
||||
|
|
@ -15,39 +15,20 @@ Dependencies:
|
|||
arch: openscad
|
||||
role: mandatory
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from .error import PlotError
|
||||
from .gs import GS
|
||||
from .kiplot import run_command
|
||||
from .out_base import VariantOptions
|
||||
from .misc import W_AUTONONE
|
||||
from .macros import macros, document, output_class # noqa: F401
|
||||
from .out_any_stencil import Stencil_Options
|
||||
from . import log
|
||||
|
||||
logger = log.get_logger()
|
||||
|
||||
|
||||
class Stencil_3D_Options(VariantOptions):
|
||||
class Stencil_3D_Options(Stencil_Options):
|
||||
def __init__(self):
|
||||
with document:
|
||||
self.output = GS.def_global_output
|
||||
""" *Filename for the output (%i='stencil_3d_top'|'stencil_3d_bottom'|'stencil_3d_edge',
|
||||
%x='stl'|'scad'|'dxf') """
|
||||
self.side = 'auto'
|
||||
""" [top,bottom,auto,both] Which side of the PCB we want. Using `auto` will detect which
|
||||
side contains solder paste """
|
||||
self.include_scad = True
|
||||
""" Include the generated OpenSCAD files. Note that this also includes the DXF files """
|
||||
self.cutout = ''
|
||||
""" [string|list(string)] List of components to add a cutout based on the component courtyard.
|
||||
This is useful when you have already pre-populated board and you want to populate more
|
||||
components """
|
||||
self.pcbthickness = 0
|
||||
""" PCB thickness [mm]. If 0 we will ask KiCad """
|
||||
self.pcb_thickness = None
|
||||
""" {pcbthickness} """
|
||||
self.thickness = 0.15
|
||||
""" *Stencil thickness [mm]. Defines amount of paste dispensed """
|
||||
self.framewidth = 1
|
||||
|
|
@ -63,30 +44,7 @@ class Stencil_3D_Options(VariantOptions):
|
|||
self.enlarge_holes = None
|
||||
""" {enlarge_holes} """
|
||||
super().__init__()
|
||||
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self.cutout = ','.join(self.force_list(self.cutout))
|
||||
|
||||
def move_output(self, src_dir, src_file, id, ext, replacement=None, patch=False):
|
||||
self._expand_id = id
|
||||
self._expand_ext = ext
|
||||
dst_name = self._parent.expand_filename(self._parent.output_dir, self.output)
|
||||
src_name = os.path.join(src_dir, src_file)
|
||||
if not os.path.isfile(src_name):
|
||||
raise PlotError('Missing output file {}'.format(src_name))
|
||||
if patch:
|
||||
# Adjust the names of the DXF files
|
||||
with open(src_name, 'r') as f:
|
||||
content = f.read()
|
||||
for k, v in replacement.items():
|
||||
content = content.replace(k, v)
|
||||
with open(dst_name, 'w') as f:
|
||||
f.write(content)
|
||||
else:
|
||||
shutil.move(src_name, dst_name)
|
||||
if replacement is not None:
|
||||
replacement[src_name] = os.path.basename(dst_name)
|
||||
self.add_to_doc('include_scad', 'Note that this also includes the DXF files')
|
||||
|
||||
def get_targets(self, out_dir):
|
||||
# TODO: auto side is tricky, needs variants applied
|
||||
|
|
@ -103,6 +61,7 @@ class Stencil_3D_Options(VariantOptions):
|
|||
cmd.extend(['--frameclearance', str(self.frameclearance)])
|
||||
if self.enlargeholes:
|
||||
cmd.extend(['--enlargeholes', str(self.enlargeholes)])
|
||||
return cmd
|
||||
|
||||
def move_outputs(self, tmp, prj_name, do_top, do_bottom):
|
||||
replacements = {}
|
||||
|
|
@ -122,53 +81,6 @@ class Stencil_3D_Options(VariantOptions):
|
|||
self.move_output(tmp, prj_name+'-PasteBottom.dxf', 'Stencil_For_Jig_bottom', 'dxf', replacements)
|
||||
self.move_output(tmp, 'bottomStencil.scad', 'Stencil_For_Jig_bottom', 'scad', replacements, patch=True)
|
||||
|
||||
def run(self, output):
|
||||
cmd_kikit = self.ensure_tool('KiKit')
|
||||
self.ensure_tool('OpenSCAD')
|
||||
super().run(output)
|
||||
# Apply variants and filters
|
||||
filtered = self.filter_pcb_components(GS.board)
|
||||
if self.side == 'auto':
|
||||
detected_top, detected_bottom = self.detect_solder_paste(GS.board)
|
||||
fname = self.save_tmp_board() if filtered else GS.pcb_file
|
||||
if filtered:
|
||||
self.unfilter_pcb_components(GS.board)
|
||||
# Avoid running the tool if we will generate useless models
|
||||
if self.side == 'auto' and not detected_top and not detected_bottom:
|
||||
logger.warning(W_AUTONONE+'No solder paste detected, skipping stencil generation')
|
||||
return
|
||||
# If no PCB thickness indicated ask KiCad
|
||||
if not self.pcbthickness:
|
||||
ds = GS.board.GetDesignSettings()
|
||||
self.pcbthickness = self.to_mm(ds.GetBoardThickness())
|
||||
# Create the command line
|
||||
cmd = self.create_cmd(cmd_kikit)
|
||||
# Create the outputs
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
cmd.append(fname)
|
||||
cmd.append(tmp)
|
||||
try:
|
||||
run_command(cmd)
|
||||
finally:
|
||||
# Remove temporal variant
|
||||
if filtered:
|
||||
GS.remove_pcb_and_pro(fname)
|
||||
# Now copy the files we want
|
||||
# - Which side?
|
||||
do_top = do_bottom = False
|
||||
if self.side == 'top':
|
||||
do_top = True
|
||||
elif self.side == 'bottom':
|
||||
do_bottom = True
|
||||
elif self.side == 'both':
|
||||
do_top = True
|
||||
do_bottom = True
|
||||
else: # auto
|
||||
do_top = detected_top
|
||||
do_bottom = detected_bottom
|
||||
prj_name = os.path.splitext(os.path.basename(fname))[0]
|
||||
self.move_outputs(tmp, prj_name, do_top, do_bottom)
|
||||
|
||||
|
||||
@output_class
|
||||
class Stencil_3D(BaseOutput): # noqa: F821
|
||||
|
|
|
|||
|
|
@ -15,39 +15,20 @@ Dependencies:
|
|||
arch: openscad
|
||||
role: mandatory
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from .error import PlotError
|
||||
from .gs import GS
|
||||
from .kiplot import run_command
|
||||
from .out_base import VariantOptions
|
||||
from .misc import W_AUTONONE
|
||||
from .macros import macros, document, output_class # noqa: F401
|
||||
from .out_any_stencil import Stencil_Options
|
||||
from . import log
|
||||
|
||||
logger = log.get_logger()
|
||||
|
||||
|
||||
class Stencil_For_Jig_Options(VariantOptions):
|
||||
class Stencil_For_Jig_Options(Stencil_Options):
|
||||
def __init__(self):
|
||||
with document:
|
||||
self.output = GS.def_global_output
|
||||
""" *Filename for the output (%i='stencil_for_jig_top'|'stencil_for_jig_bottom',
|
||||
%x='stl'|'scad'|'gbp'|'gtp'|'gbrjob') """
|
||||
self.side = 'auto'
|
||||
""" [top,bottom,auto,both] Which side of the PCB we want. Using `auto` will detect which
|
||||
side contains solder paste """
|
||||
self.include_scad = True
|
||||
""" Include the generated OpenSCAD files """
|
||||
self.cutout = ''
|
||||
""" [string|list(string)] List of components to add a cutout based on the component courtyard.
|
||||
This is useful when you have already pre-populated board and you want to populate more
|
||||
components """
|
||||
self.pcbthickness = 0
|
||||
""" PCB thickness [mm]. If 0 we will ask KiCad """
|
||||
self.pcb_thickness = None
|
||||
""" {pcbthickness} """
|
||||
self.jigthickness = 3
|
||||
""" *Jig thickness [mm] """
|
||||
self.jig_thickness = None
|
||||
|
|
@ -72,32 +53,6 @@ class Stencil_For_Jig_Options(VariantOptions):
|
|||
""" {jigheight} """
|
||||
super().__init__()
|
||||
|
||||
def config(self, parent):
|
||||
super().config(parent)
|
||||
self.cutout = ','.join(self.force_list(self.cutout))
|
||||
|
||||
def move_output(self, src_dir, src_file, id, ext, replacement=None, patch=False, relative=False):
|
||||
self._expand_id = id
|
||||
self._expand_ext = ext
|
||||
dst_name = self._parent.expand_filename(self._parent.output_dir, self.output)
|
||||
src_name = os.path.join(src_dir, src_file)
|
||||
if not os.path.isfile(src_name):
|
||||
raise PlotError('Missing output file {}'.format(src_name))
|
||||
if patch:
|
||||
# Adjust the names of the DXF files
|
||||
with open(src_name, 'r') as f:
|
||||
content = f.read()
|
||||
for k, v in replacement.items():
|
||||
content = content.replace(k, v)
|
||||
with open(dst_name, 'w') as f:
|
||||
f.write(content)
|
||||
else:
|
||||
shutil.move(src_name, dst_name)
|
||||
if replacement is not None:
|
||||
if relative:
|
||||
src_name = os.path.basename(src_name)
|
||||
replacement[src_name] = os.path.basename(dst_name)
|
||||
|
||||
def get_targets(self, out_dir):
|
||||
# TODO: auto side is tricky, needs variants applied
|
||||
return [self._parent.expand_filename(out_dir, self.output)]
|
||||
|
|
@ -131,53 +86,6 @@ class Stencil_For_Jig_Options(VariantOptions):
|
|||
if do_top and do_bottom:
|
||||
self.move_output(tmp, 'gerber/stencil.gbrjob', 'stencil_for_jig', 'gbrjob', replacements, patch=True)
|
||||
|
||||
def run(self, output):
|
||||
cmd_kikit = self.ensure_tool('KiKit')
|
||||
self.ensure_tool('OpenSCAD')
|
||||
super().run(output)
|
||||
# Apply variants and filters
|
||||
filtered = self.filter_pcb_components(GS.board)
|
||||
if self.side == 'auto':
|
||||
detected_top, detected_bottom = self.detect_solder_paste(GS.board)
|
||||
fname = self.save_tmp_board() if filtered else GS.pcb_file
|
||||
if filtered:
|
||||
self.unfilter_pcb_components(GS.board)
|
||||
# Avoid running the tool if we will generate useless models
|
||||
if self.side == 'auto' and not detected_top and not detected_bottom:
|
||||
logger.warning(W_AUTONONE+'No solder paste detected, skipping stencil generation')
|
||||
return
|
||||
# If no PCB thickness indicated ask KiCad
|
||||
if not self.pcbthickness:
|
||||
ds = GS.board.GetDesignSettings()
|
||||
self.pcbthickness = self.to_mm(ds.GetBoardThickness())
|
||||
# Create the command line
|
||||
cmd = self.create_cmd(cmd_kikit)
|
||||
# Create the outputs
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
cmd.append(fname)
|
||||
cmd.append(tmp)
|
||||
try:
|
||||
run_command(cmd)
|
||||
finally:
|
||||
# Remove temporal variant
|
||||
if filtered:
|
||||
GS.remove_pcb_and_pro(fname)
|
||||
# Now copy the files we want
|
||||
# - Which side?
|
||||
do_top = do_bottom = False
|
||||
if self.side == 'top':
|
||||
do_top = True
|
||||
elif self.side == 'bottom':
|
||||
do_bottom = True
|
||||
elif self.side == 'both':
|
||||
do_top = True
|
||||
do_bottom = True
|
||||
else: # auto
|
||||
do_top = detected_top
|
||||
do_bottom = detected_bottom
|
||||
prj_name = os.path.splitext(os.path.basename(fname))[0]
|
||||
self.move_outputs(tmp, prj_name, do_top, do_bottom)
|
||||
|
||||
|
||||
@output_class
|
||||
class Stencil_For_Jig(BaseOutput): # noqa: F821
|
||||
|
|
|
|||
Loading…
Reference in New Issue