summaryrefslogtreecommitdiff
path: root/gerber/tests
diff options
context:
space:
mode:
Diffstat (limited to 'gerber/tests')
-rw-r--r--gerber/tests/test_excellon.py154
-rw-r--r--gerber/tests/test_primitives.py111
-rw-r--r--gerber/tests/test_rs274x_backend.py38
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