From e4941dd5e371e8c9e729a72b8ec30d021bceb0cc Mon Sep 17 00:00:00 2001 From: jaseg Date: Thu, 30 Dec 2021 12:57:53 +0100 Subject: Fix more bugs, refined round-trip tests pass now --- .gitignore | 119 +-------------------- gerbonara/gerber/cam.py | 1 + gerbonara/gerber/rs274x.py | 1 + gerbonara/gerber/tests/image_support.py | 22 ++-- .../tests/resources/example_single_contour_1.gbr | 2 +- gerbonara/gerber/tests/test_rs274x.py | 23 ++-- 6 files changed, 32 insertions(+), 136 deletions(-) diff --git a/.gitignore b/.gitignore index 11614af..1829a16 100644 --- a/.gitignore +++ b/.gitignore @@ -1,115 +1,4 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ +gerbonara_test_failures +*.egg-info +__pycache__ +.tox diff --git a/gerbonara/gerber/cam.py b/gerbonara/gerber/cam.py index 2917fc5..d00194b 100644 --- a/gerbonara/gerber/cam.py +++ b/gerbonara/gerber/cam.py @@ -78,6 +78,7 @@ class FileSettings: value = value.lstrip('+-') if self.zeros == 'leading': + value = '0'*decimal_digits + value # pad with zeros to ensure we have enough decimals return float(sign + value[:-decimal_digits] + '.' + value[-decimal_digits:]) else: # no or trailing zero suppression diff --git a/gerbonara/gerber/rs274x.py b/gerbonara/gerber/rs274x.py index 28949c5..654c389 100644 --- a/gerbonara/gerber/rs274x.py +++ b/gerbonara/gerber/rs274x.py @@ -505,6 +505,7 @@ class GerberParser: y = self.file_settings.parse_gerber_value(match['y']) i = self.file_settings.parse_gerber_value(match['i']) j = self.file_settings.parse_gerber_value(match['j']) + print(f'coord x={x} y={y} i={i} j={j}') if not (op := match['operation']): if self.last_operation == 'D01': diff --git a/gerbonara/gerber/tests/image_support.py b/gerbonara/gerber/tests/image_support.py index e1b1c00..8ce0d72 100644 --- a/gerbonara/gerber/tests/image_support.py +++ b/gerbonara/gerber/tests/image_support.py @@ -8,8 +8,8 @@ import numpy as np from PIL import Image class ImageDifference: - def __init__(self, value, ref_path, act_path): - self.value, self.ref_path, self.act_path = value, ref_path, act_path + def __init__(self, value): + self.value = value def __float__(self): return float(self.value) @@ -47,34 +47,32 @@ def gbr_to_svg(in_gbr, out_svg, origin=(0, 0), size=(10, 10)): '-o', str(out_svg), str(in_gbr)] subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) -def gerber_difference(reference, actual): +def gerber_difference(reference, actual, diff_out=None): with tempfile.NamedTemporaryFile(suffix='.svg') as act_svg,\ tempfile.NamedTemporaryFile(suffix='.svg') as ref_svg: gbr_to_svg(reference, ref_svg.name) gbr_to_svg(actual, act_svg.name) - diff = svg_difference(ref_svg.name, act_svg.name) - diff.ref_path, diff.act_path = reference, actual - return diff + return svg_difference(ref_svg.name, act_svg.name, diff_out=diff_out) -def svg_difference(reference, actual): +def svg_difference(reference, actual, diff_out=None): with tempfile.NamedTemporaryFile(suffix='.png') as ref_png,\ tempfile.NamedTemporaryFile(suffix='.png') as act_png: svg_to_png(reference, ref_png.name) svg_to_png(actual, act_png.name) - diff = image_difference(ref_png.name, act_png.name) - diff.ref_path, diff.act_path = reference, actual - return diff + return image_difference(ref_png.name, act_png.name, diff_out=diff_out) -def image_difference(reference, actual): +def image_difference(reference, actual, diff_out=None): ref = np.array(Image.open(reference)).astype(float) out = np.array(Image.open(actual)).astype(float) ref, out = ref.mean(axis=2), out.mean(axis=2) # convert to grayscale delta = np.abs(out - ref).astype(float) / 255 - return ImageDifference(delta.mean(), reference, actual) + if diff_out: + Image.fromarray((delta*255).astype(np.uint8), mode='L').save(diff_out) + return ImageDifference(delta.mean()), ImageDifference(delta.max()) diff --git a/gerbonara/gerber/tests/resources/example_single_contour_1.gbr b/gerbonara/gerber/tests/resources/example_single_contour_1.gbr index e9f9a75..545f757 100644 --- a/gerbonara/gerber/tests/resources/example_single_contour_1.gbr +++ b/gerbonara/gerber/tests/resources/example_single_contour_1.gbr @@ -12,4 +12,4 @@ Y60000D01* X50000D01* Y50000Y50000D01* G37* -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 f359ca9..28ee891 100644 --- a/gerbonara/gerber/tests/test_rs274x.py +++ b/gerbonara/gerber/tests/test_rs274x.py @@ -25,10 +25,11 @@ def clear_failure_dir(request): reference_path = lambda reference: Path(__file__).parent / 'resources' / reference @pytest.fixture -def tmp_gbr(request): - with tempfile.NamedTemporaryFile(suffix='.gbr') as tmp_out_gbr: +def temp_files(request): + with tempfile.NamedTemporaryFile(suffix='.gbr') as tmp_out_gbr,\ + tempfile.NamedTemporaryFile(suffix='.png') as tmp_out_png: - yield Path(tmp_out_gbr.name) + yield Path(tmp_out_gbr.name), Path(tmp_out_png.name) if request.node.rep_call.failed: module, _, test_name = request.node.nodeid.rpartition('::') @@ -36,9 +37,12 @@ def tmp_gbr(request): test_name, _, _ext = test_name.partition('.') test_name = re.sub(r'[^\w\d]', '_', test_name) fail_dir.mkdir(exist_ok=True) - perm_path = fail_dir / f'failure_{test_name}.gbr' - shutil.copy(tmp_out_gbr.name, perm_path) - print(f'Failing output saved to {perm_path}') + perm_path_gbr = fail_dir / f'failure_{test_name}.gbr' + perm_path_png = fail_dir / f'failure_{test_name}.png' + shutil.copy(tmp_out_gbr.name, perm_path_gbr) + shutil.copy(tmp_out_png.name, perm_path_png) + print(f'Failing output saved to {perm_path_gbr}') + print(f'Difference image saved to {perm_path_png}') print(f'Reference file is {reference_path(request.node.funcargs["reference"])}') @pytest.mark.filterwarnings('ignore:Deprecated.*statement found.*:DeprecationWarning') @@ -88,8 +92,11 @@ top_copper.GTL top_mask.GTS top_silk.GTO '''.splitlines() if l ]) -def test_round_trip(tmp_gbr, reference): +def test_round_trip(temp_files, reference): + tmp_gbr, tmp_png = temp_files ref = reference_path(reference) GerberFile.open(ref).save(tmp_gbr) - assert gerber_difference(ref, tmp_gbr) < 1e-5 + mean, max = gerber_difference(ref, tmp_gbr, diff_out=tmp_png) + assert mean < 1e-6 + assert max < 0.1 -- cgit