From 4101815b2fac78be67c1cd8d8c6520d41dcac7cf Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 23 Jan 2022 21:19:51 +0100 Subject: Fix more bugs --- gerbonara/gerber/cam.py | 42 ++++++++++++++-------- gerbonara/gerber/graphic_objects.py | 6 +++- gerbonara/gerber/graphic_primitives.py | 8 ++--- gerbonara/gerber/rs274x.py | 24 ++++++++----- .../gerber/tests/resources/fritzing/combined.gbl | 9 ++--- .../gerber/tests/resources/fritzing/combined.gbo | 9 ++--- .../gerber/tests/resources/fritzing/combined.gbs | 10 +++--- .../gerber/tests/resources/fritzing/combined.gm1 | 9 ++--- .../gerber/tests/resources/fritzing/combined.gtl | 9 ++--- .../gerber/tests/resources/fritzing/combined.gto | 9 ++--- .../gerber/tests/resources/fritzing/combined.gts | 9 ++--- gerbonara/gerber/tests/test_rs274x.py | 6 +++- 12 files changed, 93 insertions(+), 57 deletions(-) diff --git a/gerbonara/gerber/cam.py b/gerbonara/gerber/cam.py index 7283316..ccfa7a2 100644 --- a/gerbonara/gerber/cam.py +++ b/gerbonara/gerber/cam.py @@ -21,6 +21,7 @@ from copy import deepcopy from .utils import LengthUnit, MM, Inch, Tag from . import graphic_primitives as gp +from . import graphic_objects as go @dataclass class FileSettings: @@ -181,24 +182,37 @@ class CamFile: w = 1.0 if math.isclose(w, 0.0) else w h = 1.0 if math.isclose(h, 0.0) else h - primitives = [ prim for obj in self.objects for prim in obj.to_primitives(unit=svg_unit) ] view = tag('sodipodi:namedview', [], id='namedview1', pagecolor=bg, inkscape__document_units=svg_unit.shorthand) + tags = [] polyline = None - for primitive in primitives: - if isinstance(primitive, gp.Line): - if not polyline: - polyline = gp.Polyline(primitive) - else: - if not polyline.append(primitive): - tags.append(polyline.to_svg(tag, fg, bg)) - polyline = gp.Polyline(primitive) - else: - if polyline: - tags.append(polyline.to_svg(tag, fg, bg)) - polyline = None - tags.append(primitive.to_svg(tag, fg, bg)) + for i, obj in enumerate(self.objects): + #if isinstance(obj, go.Flash): + # if polyline: + # tags.append(polyline.to_svg(tag, fg, bg)) + # polyline = None + + # mask_tags = [ prim.to_svg(tag, 'white', 'black') for prim in obj.to_primitives(unit=svg_unit) ] + # mask_tags.insert(0, tag('rect', width='100%', height='100%', fill='black')) + # mask_id = f'mask{i}' + # tag('mask', mask_tags, id=mask_id) + # tag('rect', width='100%', height='100%', mask='url(#{mask_id})', fill=fg) + + #else: + for primitive in obj.to_primitives(unit=svg_unit): + if isinstance(primitive, gp.Line): + if not polyline: + polyline = gp.Polyline(primitive) + else: + if not polyline.append(primitive): + tags.append(polyline.to_svg(tag, fg, bg)) + polyline = gp.Polyline(primitive) + else: + if polyline: + tags.append(polyline.to_svg(tag, fg, bg)) + polyline = None + tags.append(primitive.to_svg(tag, fg, bg)) if polyline: tags.append(polyline.to_svg(tag, fg, bg)) diff --git a/gerbonara/gerber/graphic_objects.py b/gerbonara/gerber/graphic_objects.py index 131bf57..98fc094 100644 --- a/gerbonara/gerber/graphic_objects.py +++ b/gerbonara/gerber/graphic_objects.py @@ -154,6 +154,10 @@ class Region(GerberObject): def to_statements(self, gs): yield from gs.set_polarity(self.polarity_dark) yield 'G36*' + # Repeat interpolation mode at start of region statement to work around gerbv bug. Without this, gerbv will + # not display a region consisting of only a single arc. + # TODO report gerbv issue upstream + yield gs.interpolation_mode_statement() + '*' yield from gs.set_current_point(self.poly.outline[0], unit=self.unit) @@ -266,7 +270,7 @@ class Arc(GerberObject): cy : Length(float) clockwise : bool aperture : object - + def _with_offset(self, dx, dy): return replace(self, x1=self.x1+dx, y1=self.y1+dy, x2=self.x2+dx, y2=self.y2+dy) diff --git a/gerbonara/gerber/graphic_primitives.py b/gerbonara/gerber/graphic_primitives.py index 401156e..cd5e70c 100644 --- a/gerbonara/gerber/graphic_primitives.py +++ b/gerbonara/gerber/graphic_primitives.py @@ -65,13 +65,13 @@ class Obround(GraphicPrimitive): def to_line(self): if self.w > self.h: - w, a, b = self.h, self.w, 0 + w, a, b = self.h, self.w-self.h, 0 else: - w, a, b = self.w, 0, self.h + w, a, b = self.w, 0, self.h-self.w return Line( *rotate_point(self.x-a/2, self.y-b/2, self.rotation, self.x, self.y), *rotate_point(self.x+a/2, self.y+b/2, self.rotation, self.x, self.y), - w) + w, polarity_dark=self.polarity_dark) def bounding_box(self): return self.to_line().bounding_box() @@ -399,5 +399,5 @@ class RegularPolygon(GraphicPrimitive): return self.to_arc_poly().bounding_box() def to_svg(self, tag, fg, bg): - return self.to_arc_poly().to_svg(tag, color, fg, bg) + return self.to_arc_poly().to_svg(tag, fg, bg) diff --git a/gerbonara/gerber/rs274x.py b/gerbonara/gerber/rs274x.py index db93fb5..2e04d13 100644 --- a/gerbonara/gerber/rs274x.py +++ b/gerbonara/gerber/rs274x.py @@ -470,7 +470,13 @@ class GraphicsState: def set_interpolation_mode(self, mode): if self.interpolation_mode != mode: self.interpolation_mode = mode - yield {InterpMode.LINEAR: 'G01', InterpMode.CIRCULAR_CW: 'G02', InterpMode.CIRCULAR_CCW: 'G03'}[mode] + yield self.interpolation_mode_statement() + + def interpolation_mode_statement(self): + return { + InterpMode.LINEAR: 'G01', + InterpMode.CIRCULAR_CW: 'G02', + InterpMode.CIRCULAR_CCW: 'G03'}[self.interpolation_mode] class GerberParser: @@ -489,18 +495,18 @@ class GerberParser: 'allegro_format_spec': r"FS(?P(L|T|D))?(?P(A|I))[NG0-9]*X(?P[0-7][0-7])Y(?P[0-7][0-7])[DM0-9]*\*MO(?PIN|MM)", 'unit_mode': r"MO(?P(MM|IN))", 'format_spec': r"FS(?P(L|T|D))?(?P(A|I))[NG0-9]*X(?P[0-7][0-7])Y(?P[0-7][0-7])[DM0-9]*", - 'allegro_legacy_params': r'IR(?P[0-9]+)\*IP(?P(POS|NEG))\*OF(A(?P{DECIMAL}))?(B(?P{DECIMAL}))?\*MI(A(?P0|1))?(B(?P0|1))?\*SF(A(?P{DECIMAL}))?(B(?P{DECIMAL}))?', + 'allegro_legacy_params': fr'^IR(?P[0-9]+)\*IP(?P(POS|NEG))\*OF(A(?P{DECIMAL}))?(B(?P{DECIMAL}))?\*MI(A(?P0|1))?(B(?P0|1))?\*SF(A(?P{DECIMAL}))?(B(?P{DECIMAL}))?', 'load_polarity': r"LP(?P(D|C))", # FIXME LM, LR, LS 'load_name': r"LN(?P.*)", 'offset': fr"OF(A(?P{DECIMAL}))?(B(?P{DECIMAL}))?", 'include_file': r"IF(?P.*)", - 'image_name': r"IN(?P.*)", - 'axis_selection': r"AS(?PAXBY|AYBX)", - 'image_polarity': r"IP(?P(POS|NEG))", - 'image_rotation': fr"IR(?P{NUMBER})", - 'mirror_image': r"MI(A(?P0|1))?(B(?P0|1))?", - 'scale_factor': fr"SF(A(?P{DECIMAL}))?(B(?P{DECIMAL}))?", + 'image_name': r"^IN(?P.*)", + 'axis_selection': r"^AS(?PAXBY|AYBX)", + 'image_polarity': r"^IP(?P(POS|NEG))", + 'image_rotation': fr"^IR(?P{NUMBER})", + 'mirror_image': r"^MI(A(?P0|1))?(B(?P0|1))?", + 'scale_factor': fr"^SF(A(?P{DECIMAL}))?(B(?P{DECIMAL}))?", 'aperture_definition': fr"ADD(?P\d+)(?PC|R|O|P|{NAME})(?P,[^,%]*)?$", 'aperture_macro': fr"AM(?P{NAME})\*(?P[^%]*)", 'siemens_garbage': r'^ICAS$', @@ -810,7 +816,7 @@ class GerberParser: mirror = bool(int(match['ma'] or '0')), bool(int(match['mb'] or '1')) if mirror != (False, False): warnings.warn('Deprecated MI (mirror image) statement found. This deprecated since rev. I1 (Dec 2012).', DeprecationWarning) - self.graphics_state.mirror = mirror + self.graphics_state.image_mirror = mirror def _parse_scale_factor(self, match): a = float(match['sa']) if match['sa'] else 1.0 diff --git a/gerbonara/gerber/tests/resources/fritzing/combined.gbl b/gerbonara/gerber/tests/resources/fritzing/combined.gbl index ad7ca19..13b6118 100644 --- a/gerbonara/gerber/tests/resources/fritzing/combined.gbl +++ b/gerbonara/gerber/tests/resources/fritzing/combined.gbl @@ -1,3 +1,4 @@ +G04 file manually fixed for GerberTools #86 / #143* %MOIN*% %OFA0B0*% %FSLAX23Y23*% @@ -8487,7 +8488,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D29* X01338Y00039D02* X01444Y01876D03* @@ -16936,7 +16937,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D38* X02637Y00039D02* X02743Y01876D03* @@ -25385,7 +25386,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D47* X02598Y02677D02* X00761Y02783D03* @@ -33827,4 +33828,4 @@ X02345Y03029D01* G37* D02* G04 End of Copper0* -M02* \ No newline at end of file +M02* diff --git a/gerbonara/gerber/tests/resources/fritzing/combined.gbo b/gerbonara/gerber/tests/resources/fritzing/combined.gbo index 365bc71..fbb0103 100644 --- a/gerbonara/gerber/tests/resources/fritzing/combined.gbo +++ b/gerbonara/gerber/tests/resources/fritzing/combined.gbo @@ -1,3 +1,4 @@ +G04 file manually fixed for GerberTools #86 / #143* %MOIN*% %OFA0B0*% %FSLAX23Y23*% @@ -8633,7 +8634,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D21* X01777Y02388D02* X01786Y02388D01* @@ -17260,7 +17261,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D22* X03076Y02388D02* X03085Y02388D01* @@ -25887,7 +25888,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D23* X00249Y03116D02* X00249Y03125D01* @@ -34507,4 +34508,4 @@ X02357Y02948D02* X02357Y02949D01* D02* G04 End of Silk0* -M02* \ No newline at end of file +M02* diff --git a/gerbonara/gerber/tests/resources/fritzing/combined.gbs b/gerbonara/gerber/tests/resources/fritzing/combined.gbs index 737b8e4..72ac193 100644 --- a/gerbonara/gerber/tests/resources/fritzing/combined.gbs +++ b/gerbonara/gerber/tests/resources/fritzing/combined.gbs @@ -1,3 +1,5 @@ +G04 file was processed by a buggy GerberTools version. +G04 file manually fixed for GerberTools #86 / #143* %MOIN*% %OFA0B0*% %FSLAX23Y23*% @@ -165,7 +167,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D28* X01338Y00039D02* X01751Y01768D03* @@ -296,7 +298,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D36* X02637Y00039D02* X03049Y01768D03* @@ -427,7 +429,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D44* X02598Y02677D02* X00869Y03090D03* @@ -551,4 +553,4 @@ X01819Y03591D03* X02019Y03591D03* X02219Y03591D03* G04 End of Mask0* -M02* \ No newline at end of file +M02* diff --git a/gerbonara/gerber/tests/resources/fritzing/combined.gm1 b/gerbonara/gerber/tests/resources/fritzing/combined.gm1 index 4812d78..71a8a95 100644 --- a/gerbonara/gerber/tests/resources/fritzing/combined.gm1 +++ b/gerbonara/gerber/tests/resources/fritzing/combined.gm1 @@ -1,3 +1,4 @@ +G04 file manually fixed for GerberTools #86 / #143* %MOIN*% %OFA0B0*% %FSLAX23Y23*% @@ -2538,7 +2539,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D21* X01443Y02598D02* X01444Y02598D01* @@ -5070,7 +5071,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D22* X02742Y02598D02* X02743Y02598D01* @@ -7602,7 +7603,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D23* X00039Y02781D02* X00039Y02783D01* @@ -10127,4 +10128,4 @@ X00040Y02781D01* X00039Y02781D01* D02* G04 End of contour* -M02* \ No newline at end of file +M02* diff --git a/gerbonara/gerber/tests/resources/fritzing/combined.gtl b/gerbonara/gerber/tests/resources/fritzing/combined.gtl index 0689715..ac17106 100644 --- a/gerbonara/gerber/tests/resources/fritzing/combined.gtl +++ b/gerbonara/gerber/tests/resources/fritzing/combined.gtl @@ -1,3 +1,4 @@ +G04 file manually fixed for GerberTools #86 / #143* %MOIN*% %OFA0B0*% %FSLAX23Y23*% @@ -405,7 +406,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D30* X01338Y00039D02* X01751Y01768D03* @@ -768,7 +769,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D40* X02637Y00039D02* X03049Y01768D03* @@ -1131,7 +1132,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D50* X02598Y02677D02* X00869Y03090D03* @@ -1487,4 +1488,4 @@ D02* X01194Y03540D02* X01194Y03464D01* G04 End of Copper1* -M02* \ No newline at end of file +M02* diff --git a/gerbonara/gerber/tests/resources/fritzing/combined.gto b/gerbonara/gerber/tests/resources/fritzing/combined.gto index 65d56e2..a059149 100644 --- a/gerbonara/gerber/tests/resources/fritzing/combined.gto +++ b/gerbonara/gerber/tests/resources/fritzing/combined.gto @@ -1,3 +1,4 @@ +G04 file manually fixed for GerberTools #86 / #143* %MOIN*% %OFA0B0*% %FSLAX23Y23*% @@ -11538,7 +11539,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D26* X01701Y02265D02* X02501Y02265D01* @@ -23054,7 +23055,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D31* X02999Y02265D02* X03800Y02265D01* @@ -34570,7 +34571,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D36* X00371Y03040D02* X00371Y03840D01* @@ -46079,4 +46080,4 @@ X02356Y02929D02* X02356Y02939D01* D02* G04 End of Silk1* -M02* \ No newline at end of file +M02* diff --git a/gerbonara/gerber/tests/resources/fritzing/combined.gts b/gerbonara/gerber/tests/resources/fritzing/combined.gts index 80f0102..ab186a8 100644 --- a/gerbonara/gerber/tests/resources/fritzing/combined.gts +++ b/gerbonara/gerber/tests/resources/fritzing/combined.gts @@ -1,3 +1,4 @@ +G04 file manually fixed for GerberTools #86 / #143* %MOIN*% %OFA0B0*% %FSLAX23Y23*% @@ -165,7 +166,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D28* X01338Y00039D02* X01751Y01768D03* @@ -296,7 +297,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D36* X02637Y00039D02* X03049Y01768D03* @@ -427,7 +428,7 @@ G04 DOUBLE SIDED* G04 HOLES PLATED* G04 CONTOUR ON CENTER OF CONTOUR VECTOR* G90* -G04 skipping 70 +G04 skipping 70* D44* X02598Y02677D02* X00869Y03090D03* @@ -551,4 +552,4 @@ X01819Y03591D03* X02019Y03591D03* X02219Y03591D03* G04 End of Mask1* -M02* \ No newline at end of file +M02* diff --git a/gerbonara/gerber/tests/test_rs274x.py b/gerbonara/gerber/tests/test_rs274x.py index b7ddbd4..7e21d62 100644 --- a/gerbonara/gerber/tests/test_rs274x.py +++ b/gerbonara/gerber/tests/test_rs274x.py @@ -427,6 +427,10 @@ def test_svg_export(reference, tmpfile): # fine though. pytest.skip() + if reference.name == 'MinnowMax_assy.art': + # This leads to worst-case performance in resvg, this testcase takes over 1h to finish. So skip. + pytest.skip() + grb = GerberFile.open(reference) bounds = (0.0, 0.0), (6.0, 6.0) # bottom left, top right @@ -447,7 +451,7 @@ def test_svg_export(reference, tmpfile): svg_to_png(out_svg, out_png, dpi=72) # make dpi match Cairo's default mean, _max, hist = image_difference(ref_png, out_png, diff_out=tmpfile('Difference', '.png')) - assert mean < 1e-3 + assert mean < 1.2e-3 assert hist[9] < 1 assert hist[3:].sum() < 1e-3*hist.size -- cgit