Add pretty_svg test, fix some bugs.

This commit is contained in:
jaseg 2026-03-09 16:31:08 +01:00
parent 1a0f519720
commit 0c15111463
5 changed files with 53 additions and 21 deletions

View file

@ -26,7 +26,7 @@ import shutil
from pathlib import Path
from functools import cached_property
from .utils import LengthUnit, MM, Inch, Tag, sum_bounds, setup_svg
from .utils import LengthUnit, MM, Inch, Tag, sum_bounds, setup_svg, convex_hull
from . import graphic_primitives as gp
from . import graphic_objects as go
@ -351,6 +351,24 @@ class CamFile:
return sum_bounds(( p.bounding_box(unit) for p in self.objects ), default=default)
def convex_hull(self, tol=0.01, unit=None):
unit = unit or self.unit
points = []
for obj in self.objects:
if isinstance(obj, go.Line):
line = obj.as_primitive(unit)
points.append((line.x1, line.y1))
points.append((line.x2, line.y2))
elif isinstance(obj, go.Arc):
for obj in obj.approximate(tol, unit):
line = obj.as_primitive(unit)
points.append((line.x1, line.y1))
points.append((line.x2, line.y2))
return convex_hull(points)
def to_excellon(self):
""" Convert to a :py:class:`.ExcellonFile`. Returns ``self`` if it already is one. """
raise NotImplementedError()

View file

@ -1315,7 +1315,7 @@ class LayerStack:
return
if (cur, i) in joins and joins[(cur, i)] != (nearest, j):
warnings.warn(f'Three-way intersection on outline layer at: {(nearest, j)}; {(cur, i)}; and {joins[(nearest, j)]}. Falling back to returning the convex hull of the outline layer.{maybe_allegro_hint}')
warnings.warn(f'Three-way intersection on outline layer at: {(nearest, j)}; {(cur, i)}; and {joins[(cur, i)]}. Falling back to returning the convex hull of the outline layer.{maybe_allegro_hint}')
yield list(convex_hull_to_lines(self.outline.instance.convex_hull(tol, unit), unit))
return

View file

@ -28,7 +28,7 @@ import dataclasses
import functools
from .cam import CamFile, FileSettings
from .utils import MM, Inch, units, InterpMode, UnknownStatementWarning, convex_hull
from .utils import MM, Inch, units, InterpMode, UnknownStatementWarning
from .aperture_macros.parse import ApertureMacro, GenericMacros
from . import graphic_primitives as gp
from . import graphic_objects as go
@ -377,24 +377,6 @@ class GerberFile(CamFile):
for obj in self.objects:
obj.polarity_dark = not obj.polarity_dark
def convex_hull(self, tol=0.01, unit=None):
unit = unit or self.unit
points = []
for obj in self.objects:
if isinstance(obj, go.Line):
line = obj.as_primitive(unit)
points.append((line.x1, line.y1))
points.append((line.x2, line.y2))
elif isinstance(obj, go.Arc):
for obj in obj.approximate(tol, unit):
line = obj.as_primitive(unit)
points.append((line.x1, line.y1))
points.append((line.x2, line.y2))
return convex_hull(points)
class GraphicsState:
""" Internal class used to track Gerber processing state during import and export.

View file

@ -17,6 +17,7 @@
#
from pathlib import Path
import tempfile
import pytest
@ -317,6 +318,18 @@ REFERENCE_DIRS = {
'silk_screen_bottom.art': 'bottom silk',
'silk_screen_top.art': 'top silk',
},
'world_clock_2': {
'wc2-B_Cu.gbr': 'bottom copper',
'wc2-B_Mask.gbr': 'bottom mask',
'wc2-B_Paste.gbr': 'bottom paste',
'wc2-B_SilkS.gbr': 'bottom silk',
'wc2-Edge_Cuts.gbr': 'mechanical outline',
'wc2-F_Cu.gbr': 'top copper',
'wc2-F_Mask.gbr': 'top mask',
'wc2-F_Paste.gbr': 'top paste',
'wc2-F_SilkS.gbr': 'top silk',
'wc2.kicad_pcb': None,
},
}
@filter_syntax_warnings
@ -359,3 +372,13 @@ def test_layer_classifier(ref_dir, file_map):
if 'upverter' not in ref_dir:
assert isinstance(layer, ExcellonFile)
@filter_syntax_warnings
@pytest.mark.parametrize('ref_dir', list(REFERENCE_DIRS))
def test_pretty_svg_export(ref_dir):
""" Tests the basic functionality of to_pretty_svg """
path = reference_path(ref_dir)
stack = LayerStack.open_dir(path)
with tempfile.NamedTemporaryFile(suffix='.svg') as f:
stack.to_pretty_svg()

View file

@ -301,6 +301,15 @@ REFERENCE_FILES = [ l.strip() for l in '''
kicad-x2-tests/x2noap/Flashpads-F_Mask.gbr
kicad-x2-tests/x2noap/Flashpads-F_Paste.gbr
kicad-x2-tests/x2noap/Flashpads-F_Silkscreen.gbr
world_clock_2/wc2-B_Cu.gbr
world_clock_2/wc2-B_Mask.gbr
world_clock_2/wc2-B_Paste.gbr
world_clock_2/wc2-B_SilkS.gbr
world_clock_2/wc2-Edge_Cuts.gbr
world_clock_2/wc2-F_Cu.gbr
world_clock_2/wc2-F_Mask.gbr
world_clock_2/wc2-F_Paste.gbr
world_clock_2/wc2-F_SilkS.gbr
gerbv.gbr
'''.splitlines() if l ]