Fix hole transparency in aperture macros
This commit is contained in:
parent
d0f836ecfa
commit
66da2d1654
5 changed files with 74 additions and 18 deletions
|
|
@ -1064,9 +1064,6 @@ class RoundRectangle(Primitive):
|
|||
|
||||
|
||||
class Obround(Primitive):
|
||||
"""
|
||||
"""
|
||||
|
||||
def __init__(self, position, width, height, hole_diameter=0,
|
||||
hole_width=0,hole_height=0, **kwargs):
|
||||
super(Obround, self).__init__(**kwargs)
|
||||
|
|
|
|||
|
|
@ -513,9 +513,21 @@ class GerberCairoContext(GerberContext):
|
|||
self.ctx.mask_surface(mask.surface, self.origin_in_pixels[0])
|
||||
|
||||
def _render_amgroup(self, amgroup, color):
|
||||
|
||||
mask_surface = cairo.SVGSurface(None, self.size_in_pixels[0], self.size_in_pixels[1])
|
||||
mask_ctx = cairo.Context(mask_surface)
|
||||
mask_ctx.set_matrix(self.ctx.get_matrix())
|
||||
|
||||
old_surface, self.surface = self.surface, mask_surface
|
||||
old_ctx, self.ctx = self.ctx, mask_ctx
|
||||
|
||||
for primitive in amgroup.primitives:
|
||||
self.render(primitive)
|
||||
|
||||
old_ctx.mask_surface(mask_surface, self.origin_in_pixels[0])
|
||||
mask_surface.finish()
|
||||
self.surface, self.ctx = old_surface, old_ctx
|
||||
|
||||
def _render_test_record(self, primitive, color):
|
||||
position = [pos + origin for pos, origin in
|
||||
zip(primitive.position, self.origin_in_inch)]
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 6.1 KiB |
|
|
@ -1,16 +1,16 @@
|
|||
G04 Umaco example for exposure modifier and clearing area*
|
||||
%FSLAX26Y26*%
|
||||
%MOIN*%
|
||||
%AMSQUAREWITHHOLE*
|
||||
21,0.1,1,1,0,0,0*
|
||||
1,0,0.5,0,0*%
|
||||
%ADD10SQUAREWITHHOLE*%
|
||||
%MOMM*%
|
||||
%AMSquareWithHole*
|
||||
21,1,10,10,0,0,0*
|
||||
1,0,5,0,0*%
|
||||
%ADD10SquareWithHole*%
|
||||
%ADD11C,1*%
|
||||
G01*
|
||||
%LPD*%
|
||||
D11*
|
||||
X-1000000Y-250000D02*
|
||||
X1000000Y250000D01*
|
||||
X-08939393Y-2500000D02*
|
||||
X08939393Y2500000D01*
|
||||
D10*
|
||||
X0Y0D03*
|
||||
M02*
|
||||
M02*
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import shutil
|
|||
import io
|
||||
import tempfile
|
||||
import uuid
|
||||
import cv2
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
|
@ -201,12 +202,16 @@ def test_holes_dont_clear():
|
|||
)
|
||||
|
||||
|
||||
def _DISABLED_test_render_am_exposure_modifier():
|
||||
def test_render_am_exposure_modifier():
|
||||
"""Umaco example that an aperture macro with a hole does not clear the area"""
|
||||
|
||||
_test_render(
|
||||
"resources/example_am_exposure_modifier.gbr",
|
||||
"golden/example_am_exposure_modifier.png",
|
||||
scale = 50,
|
||||
autocrop_golden = True,
|
||||
auto_contrast = True,
|
||||
max_delta = 0.005 # Take artifacts due to differences in anti-aliasing and thresholding into account
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -252,19 +257,59 @@ def test_fine_lines_x():
|
|||
def _resolve_path(path):
|
||||
return os.path.join(os.path.dirname(__file__), path)
|
||||
|
||||
def images_match(reference, output, max_delta):
|
||||
def images_match(reference, output, max_delta, autocrop_golden=False, auto_contrast=False):
|
||||
global output_dir
|
||||
|
||||
ref, out = Image.open(reference), Image.open(output)
|
||||
if ref.mode == 'P': # palette mode
|
||||
ref = ref.convert('RGB')
|
||||
|
||||
ref, out = np.array(ref), np.array(out)
|
||||
# convert to grayscale
|
||||
ref, out = ref.astype(float).mean(axis=2), out.astype(float).mean(axis=2)
|
||||
|
||||
if autocrop_golden:
|
||||
rows = ref.sum(axis=1)
|
||||
cols = ref.sum(axis=0)
|
||||
|
||||
x0 = np.argmax(cols > 0)
|
||||
y0 = np.argmax(rows > 0)
|
||||
x1 = len(cols) - np.argmax(cols[::-1] > 0)
|
||||
y1 = len(rows) - np.argmax(rows[::-1] > 0)
|
||||
print(f'{x0=} {y0=} {x1=} {y1=}')
|
||||
|
||||
ref = ref[y0:y1, x0:x1]
|
||||
ref = cv2.resize(ref, dsize=out.shape[::-1], interpolation=cv2.INTER_LINEAR)
|
||||
|
||||
def print_stats(name, ref):
|
||||
print(name, 'stats:', ref.min(), ref.mean(), ref.max(), 'std:', ref.std())
|
||||
|
||||
if auto_contrast:
|
||||
print_stats('ref pre proc', ref)
|
||||
print_stats('out pre proc', out)
|
||||
|
||||
ref -= ref.min()
|
||||
ref /= ref.max()
|
||||
ref *= 255
|
||||
|
||||
out -= out.min()
|
||||
out /= out.max()
|
||||
out *= 255
|
||||
|
||||
def write_refout():
|
||||
nonlocal autocrop_golden, ref
|
||||
if autocrop_golden:
|
||||
global output_dir
|
||||
with output_dir.create(suffix='.png') as ref_out:
|
||||
cv2.imwrite(str(ref_out), ref)
|
||||
print('Processed reference image:', ref_out)
|
||||
|
||||
if ref.shape != out.shape:
|
||||
print(f'Rendering image size mismatch')
|
||||
print(f'Rendering image size mismatch: {ref.shape} != {out.shape}')
|
||||
print(f'Reference image: {Path(reference).absolute()}')
|
||||
print(f'Actual output: {output}')
|
||||
|
||||
write_refout()
|
||||
output_dir.keep()
|
||||
|
||||
return False
|
||||
|
|
@ -275,11 +320,13 @@ def images_match(reference, output, max_delta):
|
|||
print(f'Renderings mismatch: {delta.mean()=}, {max_delta=}')
|
||||
print(f'Reference image: {Path(reference).absolute()}')
|
||||
print(f'Actual output: {output}')
|
||||
def print_stats(name, ref):
|
||||
print(name, 'stats:', ref.min(), ref.mean(), ref.max(), 'std:', ref.std())
|
||||
with output_dir.create(suffix='.png') as proc_out:
|
||||
cv2.imwrite(str(proc_out), out)
|
||||
print('Processed output image:', proc_out)
|
||||
print_stats('reference', ref)
|
||||
print_stats('actual', out)
|
||||
|
||||
write_refout()
|
||||
output_dir.keep()
|
||||
|
||||
return False
|
||||
|
|
@ -287,7 +334,7 @@ def images_match(reference, output, max_delta):
|
|||
return True
|
||||
|
||||
|
||||
def _test_render(gerber_path, png_expected_path, max_delta=1e-6, scale=300):
|
||||
def _test_render(gerber_path, png_expected_path, max_delta=1e-6, scale=300, autocrop_golden=False, auto_contrast=False):
|
||||
"""Render the gerber file and compare to the expected PNG output.
|
||||
|
||||
Parameters
|
||||
|
|
@ -314,7 +361,7 @@ def _test_render(gerber_path, png_expected_path, max_delta=1e-6, scale=300):
|
|||
with output_dir.create(suffix='.png') as outfile:
|
||||
actual_bytes = ctx.dump(outfile)
|
||||
|
||||
assert images_match(png_expected_path, outfile, max_delta)
|
||||
assert images_match(png_expected_path, outfile, max_delta, autocrop_golden, auto_contrast)
|
||||
|
||||
return gerber
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue