From 67dfad8418a092ed9465e88be479f0e555e640ff Mon Sep 17 00:00:00 2001 From: jaseg Date: Tue, 21 Feb 2023 23:06:39 +0100 Subject: layers: Fix single file handling --- gerbonara/cli.py | 38 +++++++++++---- gerbonara/excellon_settings.py | 105 ----------------------------------------- gerbonara/layers.py | 22 +++++---- 3 files changed, 41 insertions(+), 124 deletions(-) delete mode 100644 gerbonara/excellon_settings.py diff --git a/gerbonara/cli.py b/gerbonara/cli.py index c40fe31..d24088e 100644 --- a/gerbonara/cli.py +++ b/gerbonara/cli.py @@ -1,4 +1,21 @@ -#!/usr/bin/env python3 +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2023 Jan Sebastian Götte +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + import math import click @@ -124,7 +141,7 @@ def cli(): @click.option('--force-zip', is_flag=True, help='''Force treating input path as a zip file (default: guess file type from extension and contents)''') @click.option('--top/--bottom', default=True, help='Which side of the board to render') -@click.option('--command-line-units', type=Unit(), default=MM, help='''Units for values given in other options. Default: +@click.option('--command-line-units', type=Unit(), help='''Units for values given in other options. Default: millimeter''') @click.option('--margin', type=float, default=0.0, help='Add space around the board inside the viewport') @click.option('--force-bounds', help='Force SVG bounding box to value given as "min_x,min_y,max_x,max_y"') @@ -155,7 +172,8 @@ def render(inpath, outfile, format_warnings, input_map, use_builtin_name_rules, if colorscheme: colorscheme = json.loads(colorscheme.read_text()) - outfile.write(str(stack.to_pretty_svg(side='top' if top else 'bottom', margin=margin, arg_unit=command_line_units, + outfile.write(str(stack.to_pretty_svg(side='top' if top else 'bottom', margin=margin, + arg_unit=(command_line_units or MM), svg_unit=MM, force_bounds=force_bounds, inkscape=inkscape, colors=colorscheme))) @@ -170,7 +188,7 @@ def render(inpath, outfile, format_warnings, input_map, use_builtin_name_rules, move its bottom-left corner to the origin. Coordinates are given in --command-line-units, angles in degrees, and scale as a scale factor (as opposed to a percentage). Example: "translate(-10, 0); rotate(45, 0, 5)"''') -@click.option('--command-line-units', type=Unit(), default=MM, help='''Units for values given in other options. Default: +@click.option('--command-line-units', type=Unit(), help='''Units for values given in other options. Default: millimeter''') @click.option('-n', '--number-format', help='''Override number format to use during export in "[integer digits].[decimal digits]" notation, e.g. "2.6".''') @@ -212,7 +230,7 @@ def rewrite(transform, command_line_units, number_format, units, zero_suppressio f = GerberFile.open(infile, override_settings=input_settings) if transform: - apply_transform(transform, command_line_units, f) + apply_transform(transform, command_line_units or MM, f) output_format = FileSettings() if output_format == 'reuse' else FileSettings.defaults() if number_format: @@ -238,7 +256,7 @@ def rewrite(transform, command_line_units, number_format, units, zero_suppressio rules and use only rules given by --input-map''') @click.option('--warnings', 'format_warnings', type=click.Choice(['default', 'ignore', 'once']), default='default', help='''Enable or disable file format warnings during parsing (default: on)''') -@click.option('--units', type=Unit(), default=MM, help='Units for values given in other options. Default: millimeter') +@click.option('--units', type=Unit(), help='Units for values given in other options. Default: millimeter') @click.option('-n', '--number-format', help='''Override number format to use during export in "[integer digits].[decimal digits]" notation, e.g. "2.6".''') @click.option('--reuse-input-settings', 'output_format', flag_value='reuse', help='''Use the same export settings as the @@ -281,8 +299,8 @@ def transform(transform, units, output_format, inpath, outpath, @cli.command() -@click.option('--command-line-units', type=Unit(), default=MM, help='Units for values given in --transform. Default: - millimeter') +@click.option('--command-line-units', type=Unit(), help='''Units for values given in --transform. Default: + millimeter''') @click.option('--warnings', 'format_warnings', type=click.Choice(['default', 'ignore', 'once']), default='default', help='''Enable or disable file format warnings during parsing (default: on)''') @click.option('--offset', multiple=True, type=Coordinate(), help="""Offset for the n'th file as a "x,y" string in unit @@ -333,7 +351,7 @@ def merge(inpath, outpath, offset, rotation, input_map, command_line_units, outp stack = LayerStack.open(p, overrides=overrides, autoguess=use_builtin_name_rules) if not math.isclose(offset[0], 0, abs_tol=1e-3) and math.isclose(offset[1], 0, abs_tol=1e-3): - stack.offset(*offset, command_line_units) + stack.offset(*offset, command_line_units or MM) if not math.isclose(theta, 0, abs_tol=1e-2): stack.rotate(theta, cx, cy) @@ -357,7 +375,7 @@ def merge(inpath, outpath, offset, rotation, input_map, command_line_units, outp @click.option('--version', is_flag=True, callback=print_version, expose_value=False, is_eager=True) @click.option('--warnings', 'format_warnings', type=click.Choice(['default', 'ignore', 'once']), default='default', help='''Enable or disable file format warnings during parsing (default: on)''') -@click.option('--units', type=Unit(), default=MM, help='Output bounding box in this unit (default: millimeter)') +@click.option('--units', type=Unit(), help='Output bounding box in this unit (default: millimeter)') @click.option('--input-number-format', help='Override number format of input file (mostly useful for Excellon files)') @click.option('--input-units', type=Unit(), help='Override units of input file') @click.option('--input-zero-suppression', type=click.Choice(['off', 'leading', 'trailing']), help='Override zero suppression setting of input file') diff --git a/gerbonara/excellon_settings.py b/gerbonara/excellon_settings.py deleted file mode 100644 index 4dbe0ca..0000000 --- a/gerbonara/excellon_settings.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from argparse import PARSER - -# Copyright 2015 Garret Fick - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Excellon Settings Definition File module -==================== -**Excellon file classes** - -This module provides Excellon file classes and parsing utilities -""" - -import re -try: - from cStringIO import StringIO -except(ImportError): - from io import StringIO - -from .cam import FileSettings - -def loads(data): - """ Read settings file information and return an FileSettings - Parameters - ---------- - data : string - string containing Excellon settings file contents - - Returns - ------- - file settings: FileSettings - - """ - - return ExcellonSettingsParser().parse_raw(data) - -def map_coordinates(value): - if value == 'ABSOLUTE': - return 'absolute' - return 'relative' - -def map_units(value): - if value == 'ENGLISH': - return 'inch' - return 'metric' - -def map_boolean(value): - return value == 'YES' - -SETTINGS_KEYS = { - 'INTEGER-PLACES': (int, 'format-int'), - 'DECIMAL-PLACES': (int, 'format-dec'), - 'COORDINATES': (map_coordinates, 'notation'), - 'OUTPUT-UNITS': (map_units, 'units'), - } - -class ExcellonSettingsParser(object): - """Excellon Settings PARSER - - Parameters - ---------- - None - """ - - def __init__(self): - self.values = {} - self.settings = None - - def parse_raw(self, data): - for line in StringIO(data): - self._parse(line.strip()) - - # Create the FileSettings object - self.settings = FileSettings( - notation=self.values['notation'], - units=self.values['units'], - format=(self.values['format-int'], self.values['format-dec']) - ) - - return self.settings - - def _parse(self, line): - - line_items = line.split() - if len(line_items) == 2: - - item_type_info = SETTINGS_KEYS.get(line_items[0]) - if item_type_info: - # Convert the value to the expected type - item_value = item_type_info[0](line_items[1]) - - self.values[item_type_info[1]] = item_value \ No newline at end of file diff --git a/gerbonara/layers.py b/gerbonara/layers.py index a1c854a..f5455a2 100644 --- a/gerbonara/layers.py +++ b/gerbonara/layers.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # # Copyright 2014 Hamilton Kibbe -# Copyright 2022 Jan Götte +# Copyright 2022 Jan Sebastian Götte # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -258,7 +258,7 @@ class LayerStack: elif path.suffix.lower() == '.zip' or is_zipfile(path): return kls.open_zip(path, board_name=board_name, lazy=lazy, overrides=overrides, autoguess=autoguess) else: - return kls.from_files([path], board_name=board_name, lazy=lazy, overrides=overrides, autoguess=autoguess) + return kls.from_files([path], board_name=board_name, lazy=lazy, overrides=overrides, autoguess=False) @classmethod def open_zip(kls, file, original_path=None, board_name=None, lazy=False, overrides=None, autoguess=True): @@ -294,7 +294,11 @@ class LayerStack: if autoguess: generator, filemap = best_match(files) else: - generator, filemap = 'custom', {} + generator = 'custom' + if overrides: + filemap = {} + else: + filemap = {'unknown unknown': files} all_generator_hints = set() if overrides: @@ -310,7 +314,7 @@ class LayerStack: filemap[layer].remove(fn) filemap[layer] = filemap.get(layer, []) + [fn] - if sum(len(files) for files in filemap.values()) < 6: + if sum(len(files) for files in filemap.values()) < 6 and autoguess: warnings.warn('Ambiguous gerber filenames. Trying last-resort autoguesser.') generator = None filemap = do_autoguess(files) @@ -665,18 +669,18 @@ class LayerStack: self.drill_pth = self.drill_npth = self.drill_unknown = None def __len__(self): - return len(self.layers) + return len(self.graphic_layers) def get(self, index, default=None): - if self.contains(key): - return self[key] + if index in self: + return self[index] else: return default def __contains__(self, index): if isinstance(index, str): side, _, use = index.partition(' ') - return (side, use) in self.layers + return (side, use) in self.graphic_layers elif isinstance(index, tuple): return index in self.graphic_layers @@ -718,7 +722,7 @@ class LayerStack: @property def outline(self): - return self['mechanical outline'] + return self.get('mechanical outline') def outline_svg_d(self, tol=0.01, unit=MM): chains = self.outline_polygons(tol, unit) -- cgit