diff options
Diffstat (limited to 'gerber/tests')
-rw-r--r-- | gerber/tests/test_excellon.py | 154 | ||||
-rw-r--r-- | gerber/tests/test_primitives.py | 111 | ||||
-rw-r--r-- | gerber/tests/test_rs274x_backend.py | 38 |
3 files changed, 259 insertions, 44 deletions
diff --git a/gerber/tests/test_excellon.py b/gerber/tests/test_excellon.py index 1402938..6cddb60 100644 --- a/gerber/tests/test_excellon.py +++ b/gerber/tests/test_excellon.py @@ -6,6 +6,7 @@ import os from ..cam import FileSettings from ..excellon import read, detect_excellon_format, ExcellonFile, ExcellonParser +from ..excellon import DrillHit, DrillSlot from ..excellon_statements import ExcellonTool from .tests import * @@ -50,29 +51,28 @@ def test_read_settings(): assert_equal(ncdrill.settings['zeros'], 'trailing') -def test_bounds(): +def test_bounding_box(): ncdrill = read(NCDRILL_FILE) - xbound, ybound = ncdrill.bounds + xbound, ybound = ncdrill.bounding_box assert_array_almost_equal(xbound, (0.1300, 2.1430)) assert_array_almost_equal(ybound, (0.3946, 1.7164)) def test_report(): ncdrill = read(NCDRILL_FILE) - + rprt = ncdrill.report() def test_conversion(): import copy ncdrill = read(NCDRILL_FILE) assert_equal(ncdrill.settings.units, 'inch') ncdrill_inch = copy.deepcopy(ncdrill) + ncdrill.to_metric() assert_equal(ncdrill.settings.units, 'metric') - inch_primitives = ncdrill_inch.primitives for tool in iter(ncdrill_inch.tools.values()): tool.to_metric() - for primitive in inch_primitives: - primitive.to_metric() + for statement in ncdrill_inch.statements: statement.to_metric() @@ -80,7 +80,8 @@ def test_conversion(): iter(ncdrill_inch.tools.values())): assert_equal(i_tool, m_tool) - for m, i in zip(ncdrill.primitives, inch_primitives): + for m, i in zip(ncdrill.primitives, ncdrill_inch.primitives): + assert_equal(m.position, i.position, '%s not equal to %s' % (m, i)) assert_equal(m.diameter, i.diameter, '%s not equal to %s' % (m, i)) @@ -197,3 +198,142 @@ def test_parse_unknown(): p = ExcellonParser(FileSettings()) p._parse_line('Not A Valid Statement') assert_equal(p.statements[0].stmt, 'Not A Valid Statement') + +def test_drill_hit_units_conversion(): + """ Test unit conversion for drill hits + """ + # Inch hit + settings = FileSettings(units='inch') + tool = ExcellonTool(settings, diameter=1.0) + hit = DrillHit(tool, (1.0, 1.0)) + + assert_equal(hit.tool.settings.units, 'inch') + assert_equal(hit.tool.diameter, 1.0) + assert_equal(hit.position, (1.0, 1.0)) + + # No Effect + hit.to_inch() + + assert_equal(hit.tool.settings.units, 'inch') + assert_equal(hit.tool.diameter, 1.0) + assert_equal(hit.position, (1.0, 1.0)) + + # Should convert + hit.to_metric() + + assert_equal(hit.tool.settings.units, 'metric') + assert_equal(hit.tool.diameter, 25.4) + assert_equal(hit.position, (25.4, 25.4)) + + # No Effect + hit.to_metric() + + assert_equal(hit.tool.settings.units, 'metric') + assert_equal(hit.tool.diameter, 25.4) + assert_equal(hit.position, (25.4, 25.4)) + + # Convert back to inch + hit.to_inch() + + assert_equal(hit.tool.settings.units, 'inch') + assert_equal(hit.tool.diameter, 1.0) + assert_equal(hit.position, (1.0, 1.0)) + +def test_drill_hit_offset(): + TEST_VECTORS = [ + ((0.0 ,0.0), (0.0, 1.0), (0.0, 1.0)), + ((0.0, 0.0), (1.0, 1.0), (1.0, 1.0)), + ((1.0, 1.0), (0.0, -1.0), (1.0, 0.0)), + ((1.0, 1.0), (-1.0, -1.0), (0.0, 0.0)), + + ] + for position, offset, expected in TEST_VECTORS: + settings = FileSettings(units='inch') + tool = ExcellonTool(settings, diameter=1.0) + hit = DrillHit(tool, position) + + assert_equal(hit.position, position) + + hit.offset(offset[0], offset[1]) + + assert_equal(hit.position, expected) + + +def test_drill_slot_units_conversion(): + """ Test unit conversion for drill hits + """ + # Inch hit + settings = FileSettings(units='inch') + tool = ExcellonTool(settings, diameter=1.0) + hit = DrillSlot(tool, (1.0, 1.0), (10.0, 10.0), DrillSlot.TYPE_ROUT) + + assert_equal(hit.tool.settings.units, 'inch') + assert_equal(hit.tool.diameter, 1.0) + assert_equal(hit.start, (1.0, 1.0)) + assert_equal(hit.end, (10.0, 10.0)) + + # No Effect + hit.to_inch() + + assert_equal(hit.tool.settings.units, 'inch') + assert_equal(hit.tool.diameter, 1.0) + assert_equal(hit.start, (1.0, 1.0)) + assert_equal(hit.end, (10.0, 10.0)) + + # Should convert + hit.to_metric() + + assert_equal(hit.tool.settings.units, 'metric') + assert_equal(hit.tool.diameter, 25.4) + assert_equal(hit.start, (25.4, 25.4)) + assert_equal(hit.end, (254.0, 254.0)) + + # No Effect + hit.to_metric() + + assert_equal(hit.tool.settings.units, 'metric') + assert_equal(hit.tool.diameter, 25.4) + assert_equal(hit.start, (25.4, 25.4)) + assert_equal(hit.end, (254.0, 254.0)) + + # Convert back to inch + hit.to_inch() + + assert_equal(hit.tool.settings.units, 'inch') + assert_equal(hit.tool.diameter, 1.0) + assert_equal(hit.start, (1.0, 1.0)) + assert_equal(hit.end, (10.0, 10.0)) + +def test_drill_slot_offset(): + TEST_VECTORS = [ + ((0.0 ,0.0), (1.0, 1.0), (0.0, 0.0), (0.0, 0.0), (1.0, 1.0)), + ((0.0, 0.0), (1.0, 1.0), (1.0, 0.0), (1.0, 0.0), (2.0, 1.0)), + ((0.0, 0.0), (1.0, 1.0), (1.0, 1.0), (1.0, 1.0), (2.0, 2.0)), + ((0.0, 0.0), (1.0, 1.0), (-1.0, 1.0), (-1.0, 1.0), (0.0, 2.0)), + ] + for start, end, offset, expected_start, expected_end in TEST_VECTORS: + settings = FileSettings(units='inch') + tool = ExcellonTool(settings, diameter=1.0) + slot = DrillSlot(tool, start, end, DrillSlot.TYPE_ROUT) + + assert_equal(slot.start, start) + assert_equal(slot.end, end) + + slot.offset(offset[0], offset[1]) + + assert_equal(slot.start, expected_start) + assert_equal(slot.end, expected_end) + +def test_drill_slot_bounds(): + TEST_VECTORS = [ + ((0.0, 0.0), (1.0, 1.0), 1.0, ((-0.5, 1.5), (-0.5, 1.5))), + ((0.0, 0.0), (1.0, 1.0), 0.5, ((-0.25, 1.25), (-0.25, 1.25))), + ] + for start, end, diameter, expected, in TEST_VECTORS: + settings = FileSettings(units='inch') + tool = ExcellonTool(settings, diameter=diameter) + slot = DrillSlot(tool, start, end, DrillSlot.TYPE_ROUT) + + assert_equal(slot.bounding_box, expected) + +#def test_exce diff --git a/gerber/tests/test_primitives.py b/gerber/tests/test_primitives.py index 52d774c..2fe5a4b 100644 --- a/gerber/tests/test_primitives.py +++ b/gerber/tests/test_primitives.py @@ -192,16 +192,53 @@ def test_arc_sweep_angle(): def test_arc_bounds(): """ Test Arc primitive bounding box calculation """ - cases = [((1, 0), (0, 1), (0, 0), 'clockwise', ((-1.5, 1.5), (-1.5, 1.5))), - ((1, 0), (0, 1), (0, 0), 'counterclockwise', - ((-0.5, 1.5), (-0.5, 1.5))), - # TODO: ADD MORE TEST CASES HERE - ] + cases = [ + ((1, 0), (0, 1), (0, 0), 'clockwise', ((-1.5, 1.5), (-1.5, 1.5))), + ((1, 0), (0, 1), (0, 0), 'counterclockwise',((-0.5, 1.5), (-0.5, 1.5))), + + ((0, 1), (-1, 0), (0, 0), 'clockwise', ((-1.5, 1.5), (-1.5, 1.5))), + ((0, 1), (-1, 0), (0, 0), 'counterclockwise', ((-1.5, 0.5), (-0.5, 1.5))), + + ((-1, 0), (0, -1), (0, 0), 'clockwise', ((-1.5, 1.5), (-1.5, 1.5))), + ((-1, 0), (0, -1), (0, 0), 'counterclockwise', ((-1.5, 0.5), (-1.5, 0.5))), + + ((0, -1), (1, 0), (0, 0), 'clockwise', ((-1.5, 1.5), (-1.5, 1.5))), + ((0, -1), (1, 0), (0, 0), 'counterclockwise',((-0.5, 1.5), (-1.5, 0.5))), + + # Arcs with the same start and end point render a full circle + ((1, 0), (1, 0), (0, 0), 'clockwise', ((-1.5, 1.5), (-1.5, 1.5))), + ((1, 0), (1, 0), (0, 0), 'counterclockwise', ((-1.5, 1.5), (-1.5, 1.5))), + ] for start, end, center, direction, bounds in cases: c = Circle((0,0), 1) - a = Arc(start, end, center, direction, c, 'single-quadrant') + a = Arc(start, end, center, direction, c, 'multi-quadrant') assert_equal(a.bounding_box, bounds) +def test_arc_bounds_no_aperture(): + """ Test Arc primitive bounding box calculation ignoring aperture + """ + cases = [ + ((1, 0), (0, 1), (0, 0), 'clockwise', ((-1.0, 1.0), (-1.0, 1.0))), + ((1, 0), (0, 1), (0, 0), 'counterclockwise',((0.0, 1.0), (0.0, 1.0))), + + ((0, 1), (-1, 0), (0, 0), 'clockwise', ((-1.0, 1.0), (-1.0, 1.0))), + ((0, 1), (-1, 0), (0, 0), 'counterclockwise', ((-1.0, 0.0), (0.0, 1.0))), + + ((-1, 0), (0, -1), (0, 0), 'clockwise', ((-1.0, 1.0), (-1.0, 1.0))), + ((-1, 0), (0, -1), (0, 0), 'counterclockwise', ((-1.0, 0.0), (-1.0, 0.0))), + + ((0, -1), (1, 0), (0, 0), 'clockwise', ((-1.0, 1.0), (-1.0, 1.0))), + ((0, -1), (1, 0), (0, 0), 'counterclockwise',((-0.0, 1.0), (-1.0, 0.0))), + + # Arcs with the same start and end point render a full circle + ((1, 0), (1, 0), (0, 0), 'clockwise', ((-1.0, 1.0), (-1.0, 1.0))), + ((1, 0), (1, 0), (0, 0), 'counterclockwise', ((-1.0, 1.0), (-1.0, 1.0))), + ] + for start, end, center, direction, bounds in cases: + c = Circle((0,0), 1) + a = Arc(start, end, center, direction, c, 'multi-quadrant') + assert_equal(a.bounding_box_no_aperture, bounds) + def test_arc_conversion(): c = Circle((0, 0), 25.4, units='metric') @@ -438,6 +475,7 @@ def test_rectangle_ctor(): assert_equal(r.width, width) assert_equal(r.height, height) + def test_rectangle_hole_radius(): """ Test rectangle hole diameter calculation """ @@ -448,7 +486,6 @@ def test_rectangle_hole_radius(): assert_equal(0.5, r.hole_radius) - def test_rectangle_bounds(): """ Test rectangle bounding box calculation """ @@ -461,6 +498,32 @@ def test_rectangle_bounds(): assert_array_almost_equal(xbounds, (-math.sqrt(2), math.sqrt(2))) assert_array_almost_equal(ybounds, (-math.sqrt(2), math.sqrt(2))) +def test_rectangle_vertices(): + sqrt2 = math.sqrt(2.0) + TEST_VECTORS = [ + ((0, 0), 2.0, 2.0, 0.0, ((-1.0, -1.0), (-1.0, 1.0), (1.0, 1.0), (1.0, -1.0))), + ((0, 0), 2.0, 3.0, 0.0, ((-1.0, -1.5), (-1.0, 1.5), (1.0, 1.5), (1.0, -1.5))), + ((0, 0), 2.0, 2.0, 90.0,((-1.0, -1.0), (-1.0, 1.0), (1.0, 1.0), (1.0, -1.0))), + ((0, 0), 3.0, 2.0, 90.0,((-1.0, -1.5), (-1.0, 1.5), (1.0, 1.5), (1.0, -1.5))), + ((0, 0), 2.0, 2.0, 45.0,((-sqrt2, 0.0), (0.0, sqrt2), (sqrt2, 0), (0, -sqrt2))), + ] + for pos, width, height, rotation, expected in TEST_VECTORS: + r = Rectangle(pos, width, height, rotation=rotation) + for test, expect in zip(sorted(r.vertices), sorted(expected)): + assert_array_almost_equal(test, expect) + + r = Rectangle((0, 0), 2.0, 2.0, rotation=0.0) + r.rotation = 45.0 + for test, expect in zip(sorted(r.vertices), sorted(((-sqrt2, 0.0), (0.0, sqrt2), (sqrt2, 0), (0, -sqrt2)))): + assert_array_almost_equal(test, expect) + +def test_rectangle_segments(): + + r = Rectangle((0, 0), 2.0, 2.0) + expected = [vtx for segment in r.segments for vtx in segment] + for vertex in r.vertices: + assert_in(vertex, expected) + def test_rectangle_conversion(): """Test converting rectangles between units""" @@ -697,6 +760,18 @@ def test_chamfer_rectangle_offset(): r.offset(0, 1) assert_equal(r.position, (1., 1.)) +def test_chamfer_rectangle_vertices(): + TEST_VECTORS = [ + (1.0, (True, True, True, True), ((-2.5, -1.5), (-2.5, 1.5), (-1.5, 2.5), (1.5, 2.5), (2.5, 1.5), (2.5, -1.5), (1.5, -2.5), (-1.5, -2.5))), + (1.0, (True, False, False, False), ((-2.5, -2.5), (-2.5, 2.5), (1.5, 2.5), (2.5, 1.5), (2.5, -2.5))), + (1.0, (False, True, False, False), ((-2.5, -2.5), (-2.5, 1.5), (-1.5, 2.5), (2.5, 2.5), (2.5, -2.5))), + (1.0, (False, False, True, False), ((-2.5, -1.5), (-2.5, 2.5), (2.5, 2.5), (2.5, -2.5), (-1.5, -2.5))), + (1.0, (False, False, False, True), ((-2.5, -2.5), (-2.5, 2.5), (2.5, 2.5), (2.5, -1.5), (1.5, -2.5))), + ] + for chamfer, corners, expected in TEST_VECTORS: + r = ChamferRectangle((0, 0), 5, 5, chamfer, corners) + assert_equal(set(r.vertices), set(expected)) + def test_round_rectangle_ctor(): """ Test round rectangle creation @@ -1195,7 +1270,7 @@ def test_drill_ctor(): """ test_cases = (((0, 0), 2), ((1, 1), 3), ((2, 2), 5)) for position, diameter in test_cases: - d = Drill(position, diameter, None) + d = Drill(position, diameter) assert_equal(d.position, position) assert_equal(d.diameter, diameter) assert_equal(d.radius, diameter / 2.) @@ -1204,24 +1279,24 @@ def test_drill_ctor(): def test_drill_ctor_validation(): """ Test drill argument validation """ - assert_raises(TypeError, Drill, 3, 5, None) - assert_raises(TypeError, Drill, (3,4,5), 5, None) + assert_raises(TypeError, Drill, 3, 5) + assert_raises(TypeError, Drill, (3,4,5), 5) def test_drill_bounds(): - d = Drill((0, 0), 2, None) + d = Drill((0, 0), 2) xbounds, ybounds = d.bounding_box assert_array_almost_equal(xbounds, (-1, 1)) assert_array_almost_equal(ybounds, (-1, 1)) - d = Drill((1, 2), 2, None) + d = Drill((1, 2), 2) xbounds, ybounds = d.bounding_box assert_array_almost_equal(xbounds, (0, 2)) assert_array_almost_equal(ybounds, (1, 3)) def test_drill_conversion(): - d = Drill((2.54, 25.4), 254., None, units='metric') + d = Drill((2.54, 25.4), 254., units='metric') #No effect d.to_metric() @@ -1237,7 +1312,7 @@ def test_drill_conversion(): assert_equal(d.position, (0.1, 1.0)) assert_equal(d.diameter, 10.0) - d = Drill((0.1, 1.0), 10., None, units='inch') + d = Drill((0.1, 1.0), 10., units='inch') # No effect d.to_inch() @@ -1255,7 +1330,7 @@ def test_drill_conversion(): def test_drill_offset(): - d = Drill((0, 0), 1., None) + d = Drill((0, 0), 1.) d.offset(1, 0) assert_equal(d.position, (1., 0.)) d.offset(0, 1) @@ -1263,8 +1338,8 @@ def test_drill_offset(): def test_drill_equality(): - d = Drill((2.54, 25.4), 254., None) - d1 = Drill((2.54, 25.4), 254., None) + d = Drill((2.54, 25.4), 254.) + d1 = Drill((2.54, 25.4), 254.) assert_equal(d, d1) - d1 = Drill((2.54, 25.4), 254.2, None) + d1 = Drill((2.54, 25.4), 254.2) assert_not_equal(d, d1) diff --git a/gerber/tests/test_rs274x_backend.py b/gerber/tests/test_rs274x_backend.py index 89512f0..e128841 100644 --- a/gerber/tests/test_rs274x_backend.py +++ b/gerber/tests/test_rs274x_backend.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # Author: Garret Fick <garret@ficksworkshop.com> -import io + import os from ..render.rs274x_backend import Rs274xContext @@ -16,7 +16,7 @@ def test_render_two_boxes(): def _test_render_single_quadrant(): """Umaco exapmle of a single quadrant arc""" - + # TODO there is probably a bug here _test_render('resources/example_single_quadrant.gbr', 'golden/example_single_quadrant.gbr') @@ -25,17 +25,17 @@ def _test_render_simple_contour(): """Umaco exapmle of a simple arrow-shaped contour""" _test_render('resources/example_simple_contour.gbr', 'golden/example_simple_contour.gbr') - + def _test_render_single_contour_1(): """Umaco example of a single contour - + The resulting image for this test is used by other tests because they must generate the same output.""" _test_render('resources/example_single_contour_1.gbr', 'golden/example_single_contour.gbr') def _test_render_single_contour_2(): """Umaco exapmle of a single contour, alternate contour end order - + The resulting image for this test is used by other tests because they must generate the same output.""" _test_render('resources/example_single_contour_2.gbr', 'golden/example_single_contour.gbr') @@ -43,12 +43,12 @@ def _test_render_single_contour_2(): def _test_render_single_contour_3(): """Umaco exapmle of a single contour with extra line""" _test_render('resources/example_single_contour_3.gbr', 'golden/example_single_contour_3.gbr') - - + + def _test_render_not_overlapping_contour(): """Umaco example of D02 staring a second contour""" _test_render('resources/example_not_overlapping_contour.gbr', 'golden/example_not_overlapping_contour.gbr') - + def _test_render_not_overlapping_touching(): """Umaco example of D02 staring a second contour""" @@ -67,7 +67,7 @@ def _test_render_overlapping_contour(): def _DISABLED_test_render_level_holes(): """Umaco example of using multiple levels to create multiple holes""" - + # TODO This is clearly rendering wrong. I'm temporarily checking this in because there are more # rendering fixes in the related repository that may resolve these. _test_render('resources/example_level_holes.gbr', 'golden/example_overlapping_contour.gbr') @@ -96,7 +96,7 @@ def _test_render_cutin_multiple(): """Umaco example of a region with multiple cutins""" _test_render('resources/example_cutin_multiple.gbr', 'golden/example_cutin_multiple.gbr') - + def _test_flash_circle(): """Umaco example a simple circular flash with and without a hole""" @@ -141,7 +141,7 @@ def _resolve_path(path): def _test_render(gerber_path, png_expected_path, create_output_path = None): """Render the gerber file and compare to the expected PNG output. - + Parameters ---------- gerber_path : string @@ -150,14 +150,14 @@ def _test_render(gerber_path, png_expected_path, create_output_path = None): Path to the PNG file to compare to create_output : string|None If not None, write the generated PNG to the specified path. - This is primarily to help with + This is primarily to help with """ - + gerber_path = _resolve_path(gerber_path) png_expected_path = _resolve_path(png_expected_path) if create_output_path: create_output_path = _resolve_path(create_output_path) - + gerber = read(gerber_path) # Create GBR output from the input file @@ -165,7 +165,7 @@ def _test_render(gerber_path, png_expected_path, create_output_path = None): gerber.render(ctx) actual_contents = ctx.dump() - + # If we want to write the file bytes, do it now. This happens if create_output_path: with open(create_output_path, 'wb') as out_file: @@ -174,12 +174,12 @@ def _test_render(gerber_path, png_expected_path, create_output_path = None): # So if we are creating the output, we make the test fail on purpose so you # won't forget to disable this assert_false(True, 'Test created the output %s. This needs to be disabled to make sure the test behaves correctly' % (create_output_path,)) - + # Read the expected PNG file - + with open(png_expected_path, 'r') as expected_file: expected_contents = expected_file.read() - + assert_equal(expected_contents, actual_contents.getvalue()) - + return gerber |