rs274x: Add support for SR step-repeat command

This commit is contained in:
jaseg 2024-07-18 16:39:58 +02:00
parent 1ecb7be6f9
commit 58d5784903
10 changed files with 51 additions and 14 deletions

View file

@ -21,6 +21,7 @@
import re
import math
import copy
import warnings
from pathlib import Path
import dataclasses
@ -623,6 +624,7 @@ class GerberParser:
'aperture_definition': fr"ADD(?P<number>\d+)(?P<shape>C|R|O|P|{NAME})(,(?P<modifiers>[^,%]*))?$",
'aperture_macro': fr"AM(?P<name>{NAME})\*(?P<macro>[^%]*)",
'siemens_garbage': r'^ICAS$',
'step_repeat': fr'^SR(?P<coords>X(?P<X>[0-9]+)Y(?P<Y>[0-9]+)I(?P<I>{DECIMAL})J(?P<J>{DECIMAL}))?$',
'old_unit':r'(?P<mode>G7[01])',
'old_notation': r'(?P<mode>G9[01])',
'ignored': r"(?P<stmt>M01)",
@ -642,6 +644,8 @@ class GerberParser:
self.aperture_map = {}
self.aperture_macros = {}
self.current_region = None
self.step_repeat_coords = None
self.step_repeat_objects = None
self.eof_found = False
self.multi_quadrant_mode = None # used only for syntax checking
self.macros = {}
@ -784,7 +788,10 @@ class GerberParser:
# in multi-quadrant mode this may return None if start and end point of the arc are the same.
obj = self.graphics_state.interpolate(x, y, i, j, multi_quadrant=self.multi_quadrant_mode)
if obj is not None:
self.target.objects.append(obj)
if self.step_repeat_objects:
self.step_repeat_objects.append(obj)
else:
self.target.objects.append(obj)
else:
obj = self.graphics_state.interpolate(x, y, i, j, aperture=False, multi_quadrant=self.multi_quadrant_mode)
if obj is not None:
@ -795,14 +802,21 @@ class GerberParser:
if self.current_region:
# Start a new region for every outline. As gerber has no concept of fill rules or winding numbers,
# it does not make a graphical difference, and it makes the implementation slightly easier.
self.target.objects.append(self.current_region)
if self.step_repeat_objects:
self.step_repeat_objects.append(self.current_region)
else:
self.target.objects.append(self.current_region)
self.current_region = go.Region(
polarity_dark=self.graphics_state.polarity_dark,
unit=self.file_settings.unit)
elif op == '3':
if self.current_region is None:
self.target.objects.append(self.graphics_state.flash(x, y))
obj = self.graphics_state.flash(x, y)
if self.step_repeat_objects:
self.step_repeat_objects.append(obj)
else:
self.target.objects.append(obj)
else:
raise SyntaxError('DO3 flash statement inside region')
@ -1064,6 +1078,30 @@ class GerberParser:
if 'EAGLE' in self.file_attrs.get('.GenerationSoftware', []) or match['eagle_garbage']:
self.generator_hints.append('eagle')
def _parse_step_repeat(self, match):
if match['coords']:
if self.step_repeat_coords:
raise SyntaxError('SR step-repeat called inside ongoing SR step-repeat')
x, y = int(match['X']), int(match['Y'])
i, j = float(match['I']), float(match['J'])
if x < 1 or y < 1:
raise SyntaxError('SR step-repeat X and Y values must be at least 1')
self.step_repeat_coords = [
(i*nx, j*ny)
for nx in range(x) for ny in range(y)] # the order matters here, cf. the spec
self.step_repeat_objects = []
else:
for obj in self.step_repeat_objects:
for dx, dy in self.step_repeat_coords:
new_obj = copy.copy(obj)
new_obj.offset(dx, dy)
self.target.objects.append(new_obj)
self.step_repeat_coords = None
self.step_repeat_objects = None
def _parse_eof(self, match):
self.eof_found = True

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -6,4 +6,4 @@
%ADD13C,0.120000*%
%LPD*%
G54D10*X168523809Y-90902380D02*X168523809Y-89902380D01*X168285714Y-89902380D01*X168142857Y-89950000D01*X168047619Y-90045238D01*X168000000Y-90140476D01*X167952380Y-90330952D01*X167952380Y-90473809D01*X168000000Y-90664285D01*X168047619Y-90759523D01*X168142857Y-90854761D01*X168285714Y-90902380D01*X168523809Y-90902380D01*X167571428Y-90616666D02*X167095238Y-90616666D01*X167666666Y-90902380D02*X167333333Y-89902380D01*X167000000Y-90902380D01*X166809523Y-89902380D02*X166238095Y-89902380D01*X166523809Y-90902380D02*X166523809Y-89902380D01*X165904761Y-90378571D02*X165571428Y-90378571D01*X165428571Y-90902380D02*X165904761Y-90902380D01*X165904761Y-89902380D01*X165428571Y-89902380D01*X168509523Y-78304761D02*X168366666Y-78352380D01*X168128571Y-78352380D01*X168033333Y-78304761D01*X167985714Y-78257142D01*X167938095Y-78161904D01*X167938095Y-78066666D01*X167985714Y-77971428D01*X168033333Y-77923809D01*X168128571Y-77876190D01*X168319047Y-77828571D01*X168414285Y-77780952D01*X168461904Y-77733333D01*X168509523Y-77638095D01*X168509523Y-77542857D01*X168461904Y-77447619D01*X168414285Y-77400000D01*X168319047Y-77352380D01*X168080952Y-77352380D01*X167938095Y-77400000D01*X167509523Y-78352380D02*X167509523Y-77352380D01*X166938095Y-78352380D01*X166938095Y-77352380D01*G54D11*G36*X168500000Y-89450000D02*G01X128500000Y-89450000D01*X128500000Y-78950000D01*X168500000Y-78950000D01*X168500000Y-89450000D01*G37*X168500000Y-89450000D02*X128500000Y-89450000D01*X128500000Y-78950000D01*X168500000Y-78950000D01*X168500000Y-89450000D01*G54D12*X131250000Y-58357142D02*X130678571Y-58357142D01*X130392857Y-58500000D01*X130107142Y-58785714D01*X129964285Y-59357142D01*X129964285Y-60357142D01*X130107142Y-60928571D01*X130392857Y-61214285D01*X130678571Y-61357142D01*X131250000Y-61357142D01*X131535714Y-61214285D01*X131821428Y-60928571D01*X131964285Y-60357142D01*X131964285Y-59357142D01*X131821428Y-58785714D01*X131535714Y-58500000D01*X131250000Y-58357142D01*X128678571Y-58357142D02*X128678571Y-60785714D01*X128535714Y-61071428D01*X128392857Y-61214285D01*X128107142Y-61357142D01*X127535714Y-61357142D01*X127250000Y-61214285D01*X127107142Y-61071428D01*X126964285Y-60785714D01*X126964285Y-58357142D01*X125964285Y-58357142D02*X124250000Y-58357142D01*X125107142Y-61357142D02*X125107142Y-58357142D01*X150071428Y-61357142D02*X150071428Y-58357142D01*X148642857Y-61357142D02*X148642857Y-58357142D01*X146928571Y-61357142D01*X146928571Y-58357142D01*G54D13*X117000000Y-76450000D02*X117000000Y-77150000D01*X118200000Y-77150000D02*X118200000Y-76450000D01*G54D10*X120242857Y-77157142D02*X120290476Y-77204761D01*X120433333Y-77252380D01*X120528571Y-77252380D01*X120671428Y-77204761D01*X120766666Y-77109523D01*X120814285Y-77014285D01*X120861904Y-76823809D01*X120861904Y-76680952D01*X120814285Y-76490476D01*X120766666Y-76395238D01*X120671428Y-76300000D01*X120528571Y-76252380D01*X120433333Y-76252380D01*X120290476Y-76300000D01*X120242857Y-76347619D01*X119290476Y-77252380D02*X119861904Y-77252380D01*X119576190Y-77252380D02*X119576190Y-76252380D01*X119671428Y-76395238D01*X119766666Y-76490476D01*X119861904Y-76538095D01*X118338095Y-77252380D02*X118909523Y-77252380D01*X118623809Y-77252380D02*X118623809Y-76252380D01*X118719047Y-76395238D01*X118814285Y-76490476D01*X118909523Y-76538095D01*X0Y0D02*M00*
G54D10*X168523809Y-90902380D02*X168523809Y-89902380D01*X168285714Y-89902380D01*X168142857Y-89950000D01*X168047619Y-90045238D01*X168000000Y-90140476D01*X167952380Y-90330952D01*X167952380Y-90473809D01*X168000000Y-90664285D01*X168047619Y-90759523D01*X168142857Y-90854761D01*X168285714Y-90902380D01*X168523809Y-90902380D01*X167571428Y-90616666D02*X167095238Y-90616666D01*X167666666Y-90902380D02*X167333333Y-89902380D01*X167000000Y-90902380D01*X166809523Y-89902380D02*X166238095Y-89902380D01*X166523809Y-90902380D02*X166523809Y-89902380D01*X165904761Y-90378571D02*X165571428Y-90378571D01*X165428571Y-90902380D02*X165904761Y-90902380D01*X165904761Y-89902380D01*X165428571Y-89902380D01*X168509523Y-78304761D02*X168366666Y-78352380D01*X168128571Y-78352380D01*X168033333Y-78304761D01*X167985714Y-78257142D01*X167938095Y-78161904D01*X167938095Y-78066666D01*X167985714Y-77971428D01*X168033333Y-77923809D01*X168128571Y-77876190D01*X168319047Y-77828571D01*X168414285Y-77780952D01*X168461904Y-77733333D01*X168509523Y-77638095D01*X168509523Y-77542857D01*X168461904Y-77447619D01*X168414285Y-77400000D01*X168319047Y-77352380D01*X168080952Y-77352380D01*X167938095Y-77400000D01*X167509523Y-78352380D02*X167509523Y-77352380D01*X166938095Y-78352380D01*X166938095Y-77352380D01*G54D11*G36*X168500000Y-89450000D02*G01*X128500000Y-89450000D01*X128500000Y-78950000D01*X168500000Y-78950000D01*X168500000Y-89450000D01*G37*X168500000Y-89450000D02*X128500000Y-89450000D01*X128500000Y-78950000D01*X168500000Y-78950000D01*X168500000Y-89450000D01*G54D12*X131250000Y-58357142D02*X130678571Y-58357142D01*X130392857Y-58500000D01*X130107142Y-58785714D01*X129964285Y-59357142D01*X129964285Y-60357142D01*X130107142Y-60928571D01*X130392857Y-61214285D01*X130678571Y-61357142D01*X131250000Y-61357142D01*X131535714Y-61214285D01*X131821428Y-60928571D01*X131964285Y-60357142D01*X131964285Y-59357142D01*X131821428Y-58785714D01*X131535714Y-58500000D01*X131250000Y-58357142D01*X128678571Y-58357142D02*X128678571Y-60785714D01*X128535714Y-61071428D01*X128392857Y-61214285D01*X128107142Y-61357142D01*X127535714Y-61357142D01*X127250000Y-61214285D01*X127107142Y-61071428D01*X126964285Y-60785714D01*X126964285Y-58357142D01*X125964285Y-58357142D02*X124250000Y-58357142D01*X125107142Y-61357142D02*X125107142Y-58357142D01*X150071428Y-61357142D02*X150071428Y-58357142D01*X148642857Y-61357142D02*X148642857Y-58357142D01*X146928571Y-61357142D01*X146928571Y-58357142D01*G54D13*X117000000Y-76450000D02*X117000000Y-77150000D01*X118200000Y-77150000D02*X118200000Y-76450000D01*G54D10*X120242857Y-77157142D02*X120290476Y-77204761D01*X120433333Y-77252380D01*X120528571Y-77252380D01*X120671428Y-77204761D01*X120766666Y-77109523D01*X120814285Y-77014285D01*X120861904Y-76823809D01*X120861904Y-76680952D01*X120814285Y-76490476D01*X120766666Y-76395238D01*X120671428Y-76300000D01*X120528571Y-76252380D01*X120433333Y-76252380D01*X120290476Y-76300000D01*X120242857Y-76347619D01*X119290476Y-77252380D02*X119861904Y-77252380D01*X119576190Y-77252380D02*X119576190Y-76252380D01*X119671428Y-76395238D01*X119766666Y-76490476D01*X119861904Y-76538095D01*X118338095Y-77252380D02*X118909523Y-77252380D01*X118623809Y-77252380D02*X118623809Y-76252380D01*X118719047Y-76395238D01*X118814285Y-76490476D01*X118909523Y-76538095D01*X0Y0D02*M00*

View file

@ -32,7 +32,7 @@ def map_line(line):
return 'X0Y0D02*M00*'
# Merge G01/02/03 with following coordinate
if line in ('G01*', 'G02*', 'G03*'):
if line in ('G01*', 'G02*', 'G03*') and ('X' in line or 'Y' in line):
return line[:-1]
# Preserve line endings for header lines

View file

@ -306,9 +306,8 @@ REFERENCE_DIRS = {
}
@filter_syntax_warnings
@pytest.mark.parametrize('ref_dir', list(REFERENCE_DIRS.items()))
def test_layer_classifier(ref_dir):
ref_dir, file_map = ref_dir
@pytest.mark.parametrize('ref_dir,file_map', list(REFERENCE_DIRS.items()))
def test_layer_classifier(ref_dir, file_map):
path = reference_path(ref_dir)
print('Reference path is', path)
file_map = { filename: role for filename, role in file_map.items() if role is not None }