[Any Layer] Enabled scaling for most plot outputs

- Only the gerber is excluded
- The new `individual_page_scaling` option is also available
- Now unknown options are treated as errors
This commit is contained in:
Salvador E. Tropea 2023-03-28 08:37:10 -03:00
parent eaa9569e71
commit bb475ad75a
7 changed files with 58 additions and 35 deletions

View File

@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `cache_3d_resistors` to avoid generating them all the time.
- 3D: colored 3D models for THT resistors
- Datasheet download: now the warnings mention which reference failed.
- Plot related outputs and PCB_Print:
- `individual_page_scaling`: to control if the center of the page is computed
using all pages or individually.
- Plot related outputs:
- All outputs now support scaling.
### Fixed
- Makefile: don't skip all preflights on each run, just the ones we generate

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2022 Salvador E. Tropea
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020-2023 Salvador E. Tropea
# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
""" Miscellaneous definitions """
@ -271,6 +271,7 @@ W_BADTOL = '(W122) '
W_BADRES = '(W123) '
W_RESVALISSUE = '(W124) '
W_RES3DNAME = '(W125) '
W_ESCINV = '(W126) '
# Somehow arbitrary, the colors are real, but can be different
PCB_MAT_COLORS = {'fr1': "937042", 'fr2': "949d70", 'fr3': "adacb4", 'fr4': "332B16", 'fr5': "6cc290"}
PCB_FINISH_COLORS = {'hal': "8b898c", 'hasl': "8b898c", 'imag': "8b898c", 'enig': "cfb96e", 'enepig': "cfb96e",

View File

@ -8,13 +8,13 @@
import os
import re
from pcbnew import (GERBER_JOBFILE_WRITER, PLOT_CONTROLLER, IsCopperLayer, F_Cu, B_Cu, Edge_Cuts, PLOT_FORMAT_HPGL,
PLOT_FORMAT_GERBER, PLOT_FORMAT_POST, PLOT_FORMAT_DXF, PLOT_FORMAT_PDF, PLOT_FORMAT_SVG, LSEQ)
PLOT_FORMAT_GERBER, PLOT_FORMAT_POST, PLOT_FORMAT_DXF, PLOT_FORMAT_PDF, PLOT_FORMAT_SVG, LSEQ, LSET)
from .optionable import Optionable
from .out_base import BaseOutput, VariantOptions
from .error import PlotError, KiPlotConfigurationError
from .layer import Layer
from .gs import GS
from .misc import W_NOLAYER, KICAD_VERSION_7_0_1, MISSING_TOOL
from .misc import W_NOLAYER, KICAD_VERSION_7_0_1, MISSING_TOOL, AUTO_SCALE
from .macros import macros, document # noqa: F401
from . import log
@ -80,7 +80,13 @@ class AnyLayerOptions(VariantOptions):
self.sketch_pad_line_width = 0.1
""" Line width for the sketched pads [mm], see `sketch_pads_on_fab_layers` (KiCad 6+)
Note that this value is currently ignored by KiCad (6.0.9) """
self.scaling = 1
""" *Scale factor (0 means autoscaling) """
self.individual_page_scaling = True
""" Tell KiCad to apply the scaling for each layer as a separated entity.
Disabling it the pages are coherent and can be superposed """
super().__init__()
self._unkown_is_error = True
def config(self, parent):
super().config(parent)
@ -107,6 +113,14 @@ class AnyLayerOptions(VariantOptions):
po.SetCreateGerberJobFile(False)
# We'll come back to this on a per-layer basis
po.SetSkipPlotNPTH_Pads(False)
# Scaling/Autoscale
if self._plot_format != PLOT_FORMAT_GERBER:
if self.scaling == AUTO_SCALE:
po.SetAutoScale(True)
po.SetScale(1)
else:
po.SetAutoScale(False)
po.SetScale(self.scaling)
def compute_name(self, k_filename, output_dir, output, id, suffix):
if output:
@ -141,6 +155,8 @@ class AnyLayerOptions(VariantOptions):
logger.error("Plotting the edge layer is not supported by KiCad 7.0.0\n"
"Please upgrade KiCad to 7.0.1 or newer")
exit(MISSING_TOOL)
# Memorize the list of visible layers
old_visible = GS.board.GetVisibleLayers()
# Apply the variants and filters
exclude = self.filter_pcb_components()
# fresh plot controller
@ -157,6 +173,13 @@ class AnyLayerOptions(VariantOptions):
# Plot every layer in the output
generated = {}
layers = Layer.solve(layers)
# Make visible only the layers we need
# This is very important when scaling, otherwise the results are controlled by the .kicad_prl (See #407)
if self._plot_format != PLOT_FORMAT_GERBER and not self.individual_page_scaling:
vis_layers = LSET()
for la in layers:
vis_layers.addLayer(la._id)
GS.board.SetVisibleLayers(vis_layers)
for la in layers:
suffix = la.suffix
desc = la.description
@ -164,6 +187,11 @@ class AnyLayerOptions(VariantOptions):
if not GS.board.IsLayerEnabled(id):
logger.warning(W_NOLAYER+'Layer "{}" isn\'t used'.format(desc))
continue
if self._plot_format != PLOT_FORMAT_GERBER and self.individual_page_scaling:
# Only this layer is visible
vis_layers = LSET()
vis_layers.addLayer(la._id)
GS.board.SetVisibleLayers(vis_layers)
# Set current layer
plot_ctrl.SetLayer(id)
# Skipping NPTH is controlled by whether or not this is
@ -211,6 +239,8 @@ class AnyLayerOptions(VariantOptions):
# Restore the eliminated layers
if exclude:
self.unfilter_pcb_components()
# Restore the list of visible layers
GS.board.SetVisibleLayers(old_visible)
self._generated_files = generated
def solve_extension(self, layer):
@ -258,6 +288,11 @@ class AnyLayerOptions(VariantOptions):
else:
self.sketch_pads_on_fab_layers = po.GetSketchPadsOnFabLayers()
self.sketch_pad_line_width = po.GetSketchPadLineWidth()
# scaleselection
if self._plot_format != PLOT_FORMAT_GERBER:
sel = po.GetScaleSelection()
sel = sel if sel < 0 or sel > 4 else 4
self.scaling = (AUTO_SCALE, 1.0, 1.5, 2.0, 3.0)[sel]
class AnyLayer(BaseOutput):

View File

@ -43,6 +43,9 @@ class GerberOptions(AnyLayerOptions):
self.disable_aperture_macros = False
""" Disable aperture macros (workaround for buggy CAM software) (KiCad 6) """
super().__init__()
# Gerbers are always 1:1
del(self.scaling)
del(self.individual_page_scaling)
self._plot_format = PLOT_FORMAT_GERBER
if GS.global_output is not None:
self.gerber_job_file = GS.global_output

View File

@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020 Salvador E. Tropea
# Copyright (c) 2020 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020-2023 Salvador E. Tropea
# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
from pcbnew import PLOT_FORMAT_HPGL, SKETCH, FILLED
from .misc import AUTO_SCALE
from .out_any_layer import AnyLayer
from .drill_marks import DrillMarks
from .macros import macros, document, output_class # noqa: F401
@ -35,13 +34,6 @@ class HPGLOptions(DrillMarks):
po.SetHPGLPenSpeed(self.pen_speed)
po.SetPlotMode(SKETCH if self.sketch_plot else FILLED)
po.SetMirror(self.mirror_plot)
# Scaling/Autoscale
if self.scaling == AUTO_SCALE:
po.SetAutoScale(True)
po.SetScale(1)
else:
po.SetAutoScale(False)
po.SetScale(self.scaling)
def read_vals_from_po(self, po):
super().read_vals_from_po(po)
@ -50,10 +42,6 @@ class HPGLOptions(DrillMarks):
self.pen_speed = po.GetHPGLPenSpeed()
self.sketch_plot = po.GetPlotMode() == SKETCH
self.mirror_plot = po.GetMirror()
# scaleselection
sel = po.GetScaleSelection()
sel = sel if sel < 0 or sel > 4 else 4
self.scaling = (AUTO_SCALE, 1.0, 1.5, 2.0, 3.0)[sel]
@output_class

View File

@ -1,12 +1,11 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020 Salvador E. Tropea
# Copyright (c) 2020 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2020-2023 Salvador E. Tropea
# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial
# Copyright (c) 2018 John Beard
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
# Adapted from: https://github.com/johnbeard/kiplot
from pcbnew import PLOT_FORMAT_POST, FromMM, ToMM, SKETCH, FILLED
from .misc import AUTO_SCALE
from .out_any_layer import AnyLayer
from .drill_marks import DrillMarks
from .gs import GS
@ -25,8 +24,6 @@ class PSOptions(DrillMarks):
""" Invert black and white """
self.sketch_plot = False
""" Don't fill objects, just draw the outline """
self.scaling = 1
""" *Scale factor (0 means autoscaling)"""
self.scale_adjust_x = 1.0
""" Fine grain adjust for the X scale (floating point multiplier) """
self.scale_adjust_y = 1.0
@ -49,13 +46,6 @@ class PSOptions(DrillMarks):
po.SetLineWidth(FromMM(self.line_width))
po.SetNegative(self.negative_plot)
po.SetMirror(self.mirror_plot)
# Scaling/Autoscale
if self.scaling == AUTO_SCALE:
po.SetAutoScale(True)
po.SetScale(1)
else:
po.SetAutoScale(False)
po.SetScale(self.scaling)
def read_vals_from_po(self, po):
super().read_vals_from_po(po)
@ -68,10 +58,6 @@ class PSOptions(DrillMarks):
self.line_width = ToMM(po.GetLineWidth())
self.negative_plot = po.GetNegative()
self.mirror_plot = po.GetMirror()
# scaleselection
sel = po.GetScaleSelection()
sel = sel if sel < 0 or sel > 4 else 4
self.scaling = (AUTO_SCALE, 1.0, 1.5, 2.0, 3.0)[sel]
@output_class

View File

@ -10,6 +10,7 @@ from pcbnew import PLOT_FORMAT_SVG, FromMM, ToMM
from .drill_marks import DrillMarks
from .gs import GS
from .kicad.patch_svg import change_svg_viewbox
from .misc import W_ESCINV
from .out_base import PcbMargin
from .out_any_layer import AnyLayer
from .macros import macros, document, output_class # noqa: F401
@ -33,7 +34,8 @@ class SVGOptions(DrillMarks):
The value is how much zeros has the multiplier (1 mm = 10 power `svg_precision` units).
Note that for an A4 paper Firefox 91 and Chrome 105 can't handle more than 5 """
self.limit_viewbox = False
""" When enabled the view box is limited to a selected area """
""" When enabled the view box is limited to a selected area.
This option can't be enabled when using a scale """
self.size_detection = 'kicad_edge'
""" [kicad_edge,kicad_all] Method used to detect the size of the view box.
The `kicad_edge` method uses the size of the board as reported by KiCad,
@ -71,6 +73,9 @@ class SVGOptions(DrillMarks):
super().run(output_dir, layers)
if not self.limit_viewbox:
return
if self.scaling != 1:
logger.warning(W_ESCINV+"Scaling and view port limit can't be mixed")
return
# Limit the view box of the SVG
bbox = GS.get_rect_for(GS.board.ComputeBoundingBox(self.size_detection == 'kicad_edge'))
# Apply the margin (left right top bottom)