Tests and bugfixes
This commit is contained in:
parent
5e23d07bcb
commit
5cf1fa74b4
10 changed files with 391 additions and 61 deletions
|
|
@ -21,7 +21,6 @@ CAM File
|
|||
|
||||
This module provides common base classes for Excellon/Gerber CNC files
|
||||
"""
|
||||
from operator import mul
|
||||
|
||||
class FileSettings(object):
|
||||
""" CAM File Settings
|
||||
|
|
@ -62,14 +61,14 @@ class FileSettings(object):
|
|||
if units not in ['inch', 'metric']:
|
||||
raise ValueError('Units must be either inch or metric')
|
||||
self.units = units
|
||||
|
||||
|
||||
if zero_suppression is None and zeros is None:
|
||||
self.zero_suppression = 'trailing'
|
||||
|
||||
|
||||
elif zero_suppression == zeros:
|
||||
raise ValueError('Zeros and Zero Suppression must be different. \
|
||||
Best practice is to specify only one.')
|
||||
|
||||
|
||||
elif zero_suppression is not None:
|
||||
if zero_suppression not in ['leading', 'trailing']:
|
||||
raise ValueError('Zero suppression must be either leading or \
|
||||
|
|
|
|||
|
|
@ -95,11 +95,27 @@ class ExcellonFile(CamFile):
|
|||
ymax = max(y + radius, ymax)
|
||||
return ((xmin, xmax), (ymin, ymax))
|
||||
|
||||
def report(self):
|
||||
""" Print drill report
|
||||
def report(self, filename=None):
|
||||
""" Print or save drill report
|
||||
"""
|
||||
pass
|
||||
|
||||
toolfmt = ' T%%02d %%%d.%df %%d\n' % self.settings.format
|
||||
rprt = 'Excellon Drill Report\n\n'
|
||||
if self.filename is not None:
|
||||
rprt += 'NC Drill File: %s\n\n' % self.filename
|
||||
rprt += 'Drill File Info:\n\n'
|
||||
rprt += (' Data Mode %s\n' % 'Absolute'
|
||||
if self.settings.notation == 'absolute' else 'Incremental')
|
||||
rprt += (' Units %s\n' % 'Inches'
|
||||
if self.settings.units == 'inch' else 'Millimeters')
|
||||
rprt += '\nTool List:\n\n'
|
||||
rprt += ' Code Size Hits\n'
|
||||
rprt += ' --------------------------\n'
|
||||
for tool in self.tools.itervalues():
|
||||
rprt += toolfmt % (tool.number, tool.diameter, tool.hit_count)
|
||||
if filename is not None:
|
||||
with open(filename, 'w') as f:
|
||||
f.write(rprt)
|
||||
return rprt
|
||||
|
||||
def write(self, filename):
|
||||
with open(filename, 'w') as f:
|
||||
|
|
@ -195,7 +211,7 @@ class ExcellonParser(object):
|
|||
self.state = 'DRILL'
|
||||
|
||||
elif line[:3] == 'M30':
|
||||
stmt = EndOfProgramStmt.from_excellon(line)
|
||||
stmt = EndOfProgramStmt.from_excellon(line, self._settings())
|
||||
self.statements.append(stmt)
|
||||
|
||||
elif line[:3] == 'G00':
|
||||
|
|
@ -230,8 +246,9 @@ class ExcellonParser(object):
|
|||
stmt = FormatStmt.from_excellon(line)
|
||||
self.statements.append(stmt)
|
||||
|
||||
elif line[:4] == 'G90':
|
||||
elif line[:3] == 'G90':
|
||||
self.statements.append(AbsoluteModeStmt())
|
||||
self.notation = 'absolute'
|
||||
|
||||
elif line[0] == 'T' and self.state == 'HEADER':
|
||||
tool = ExcellonTool.from_excellon(line, self._settings())
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ __all__ = ['ExcellonTool', 'ToolSelectionStmt', 'CoordinateStmt',
|
|||
'RewindStopStmt', 'EndOfProgramStmt', 'UnitStmt',
|
||||
'IncrementalModeStmt', 'VersionStmt', 'FormatStmt', 'LinkToolStmt',
|
||||
'MeasuringModeStmt', 'RouteModeStmt', 'DrillModeStmt', 'AbsoluteModeStmt',
|
||||
'RepeatHoleStmt', 'UnknownStmt',
|
||||
'RepeatHoleStmt', 'UnknownStmt', 'ExcellonStatement'
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -38,10 +38,10 @@ class ExcellonStatement(object):
|
|||
"""
|
||||
@classmethod
|
||||
def from_excellon(cls, line):
|
||||
pass
|
||||
raise NotImplementedError('`from_excellon` must be implemented in a subclass')
|
||||
|
||||
def to_excellon(self, settings=None):
|
||||
pass
|
||||
raise NotImplementedError('`to_excellon` must be implemented in a subclass')
|
||||
|
||||
|
||||
class ExcellonTool(ExcellonStatement):
|
||||
|
|
@ -144,7 +144,7 @@ class ExcellonTool(ExcellonStatement):
|
|||
tool : ExcellonTool
|
||||
An ExcellonTool initialized with the parameters in tool_dict.
|
||||
"""
|
||||
return cls(settings, tool_dict)
|
||||
return cls(settings, **tool_dict)
|
||||
|
||||
def __init__(self, settings, **kwargs):
|
||||
self.settings = settings
|
||||
|
|
@ -159,7 +159,7 @@ class ExcellonTool(ExcellonStatement):
|
|||
|
||||
def to_excellon(self, settings=None):
|
||||
fmt = self.settings.format
|
||||
zs = self.settings.format
|
||||
zs = self.settings.zero_suppression
|
||||
stmt = 'T%02d' % self.number
|
||||
if self.retract_rate is not None:
|
||||
stmt += 'B%s' % write_gerber_value(self.retract_rate, fmt, zs)
|
||||
|
|
@ -171,7 +171,7 @@ class ExcellonTool(ExcellonStatement):
|
|||
if self.rpm < 100000.:
|
||||
stmt += 'S%s' % write_gerber_value(self.rpm / 1000., fmt, zs)
|
||||
else:
|
||||
stmt += 'S%g' % self.rpm / 1000.
|
||||
stmt += 'S%g' % (self.rpm / 1000.)
|
||||
if self.diameter is not None:
|
||||
stmt += 'C%s' % decimal_string(self.diameter, fmt[1], True)
|
||||
if self.depth_offset is not None:
|
||||
|
|
@ -191,7 +191,8 @@ class ExcellonTool(ExcellonStatement):
|
|||
|
||||
def __repr__(self):
|
||||
unit = 'in.' if self.settings.units == 'inch' else 'mm'
|
||||
return '<ExcellonTool %02d: %0.3f%s dia.>' % (self.number, self.diameter, unit)
|
||||
fmtstr = '<ExcellonTool %%02d: %%%d.%dg%%s dia.>' % self.settings.format
|
||||
return fmtstr % (self.number, self.diameter, unit)
|
||||
|
||||
|
||||
class ToolSelectionStmt(ExcellonStatement):
|
||||
|
|
@ -273,9 +274,9 @@ class CoordinateStmt(ExcellonStatement):
|
|||
def __str__(self):
|
||||
coord_str = ''
|
||||
if self.x is not None:
|
||||
coord_str += 'X: %f ' % self.x
|
||||
coord_str += 'X: %g ' % self.x
|
||||
if self.y is not None:
|
||||
coord_str += 'Y: %f ' % self.y
|
||||
coord_str += 'Y: %g ' % self.y
|
||||
|
||||
return '<Coordinate Statement: %s>' % coord_str
|
||||
|
||||
|
|
@ -284,16 +285,32 @@ class RepeatHoleStmt(ExcellonStatement):
|
|||
|
||||
@classmethod
|
||||
def from_excellon(cls, line, settings):
|
||||
return cls(line)
|
||||
match = re.compile(r'R(?P<rcount>[0-9]*)X?(?P<xdelta>\d*\.?\d*)?Y?(?P<ydelta>\d*\.?\d*)?').match(line)
|
||||
stmt = match.groupdict()
|
||||
count = int(stmt['rcount'])
|
||||
xdelta = (parse_gerber_value(stmt['xdelta'], settings.format,
|
||||
settings.zero_suppression)
|
||||
if stmt['xdelta'] is not '' else None)
|
||||
ydelta = (parse_gerber_value(stmt['ydelta'], settings.format,
|
||||
settings.zero_suppression)
|
||||
if stmt['ydelta'] is not '' else None)
|
||||
return cls(count, xdelta, ydelta)
|
||||
|
||||
def __init__(self, line):
|
||||
self.line = line
|
||||
def __init__(self, count, xdelta=None, ydelta=None):
|
||||
self.count = count
|
||||
self.xdelta = xdelta
|
||||
self.ydelta = ydelta
|
||||
|
||||
def to_excellon(self, settings):
|
||||
return self.line
|
||||
stmt = 'R%d' % self.count
|
||||
if self.xdelta is not None:
|
||||
stmt += 'X%s' % write_gerber_value(self.xdelta, settings.format, settings.zero_suppression)
|
||||
if self.ydelta is not None:
|
||||
stmt += 'Y%s' % write_gerber_value(self.ydelta, settings.format, settings.zero_suppression)
|
||||
return stmt
|
||||
|
||||
def __str__(self):
|
||||
return '<Repeat Hole: %s>' % self.line
|
||||
return '<Repeat Hole: %d times>' % self.count
|
||||
|
||||
|
||||
class CommentStmt(ExcellonStatement):
|
||||
|
|
@ -339,8 +356,16 @@ class RewindStopStmt(ExcellonStatement):
|
|||
class EndOfProgramStmt(ExcellonStatement):
|
||||
|
||||
@classmethod
|
||||
def from_excellon(cls, line):
|
||||
return cls()
|
||||
def from_excellon(cls, line, settings):
|
||||
match = re.compile(r'M30X?(?P<x>\d*\.?\d*)?Y?(?P<y>\d*\.?\d*)?').match(line)
|
||||
stmt = match.groupdict()
|
||||
x = (parse_gerber_value(stmt['x'], settings.format,
|
||||
settings.zero_suppression)
|
||||
if stmt['x'] is not '' else None)
|
||||
y = (parse_gerber_value(stmt['y'], settings.format,
|
||||
settings.zero_suppression)
|
||||
if stmt['y'] is not '' else None)
|
||||
return cls(x, y)
|
||||
|
||||
def __init__(self, x=None, y=None):
|
||||
self.x = x
|
||||
|
|
@ -495,7 +520,7 @@ class UnknownStmt(ExcellonStatement):
|
|||
return self.stmt
|
||||
|
||||
def __str__(self):
|
||||
return "<UnknownStmt: %s >" % self.stmt
|
||||
return "<Unknown Statement: %s>" % self.stmt
|
||||
|
||||
|
||||
def pairwise(iterator):
|
||||
|
|
|
|||
|
|
@ -802,13 +802,13 @@ class CoordStmt(Statement):
|
|||
if self.function:
|
||||
coord_str += 'Fn: %s ' % self.function
|
||||
if self.x is not None:
|
||||
coord_str += 'X: %f ' % self.x
|
||||
coord_str += 'X: %g ' % self.x
|
||||
if self.y is not None:
|
||||
coord_str += 'Y: %f ' % self.y
|
||||
coord_str += 'Y: %g ' % self.y
|
||||
if self.i is not None:
|
||||
coord_str += 'I: %f ' % self.i
|
||||
coord_str += 'I: %g ' % self.i
|
||||
if self.j is not None:
|
||||
coord_str += 'J: %f ' % self.j
|
||||
coord_str += 'J: %g ' % self.j
|
||||
if self.op:
|
||||
if self.op == 'D01':
|
||||
op = 'Lights On'
|
||||
|
|
@ -829,7 +829,7 @@ class ApertureStmt(Statement):
|
|||
def __init__(self, d, deprecated=None):
|
||||
Statement.__init__(self, "APERTURE")
|
||||
self.d = int(d)
|
||||
self.deprecated = True if deprecated is not None else False
|
||||
self.deprecated = True if deprecated is not None and deprecated is not False else False
|
||||
|
||||
def to_gerber(self, settings=None):
|
||||
if self.deprecated:
|
||||
|
|
|
|||
|
|
@ -200,10 +200,10 @@ class Arc(Primitive):
|
|||
if theta1 <= math.pi * 1.5 and (theta0 >= math.pi * 1.5 or theta0 < theta1):
|
||||
points.append((self.center[0], self.center[1] - self.radius ))
|
||||
x, y = zip(*points)
|
||||
min_x = min(x)
|
||||
max_x = max(x)
|
||||
min_y = min(y)
|
||||
max_y = max(y)
|
||||
min_x = min(x) - self.aperture.radius
|
||||
max_x = max(x) + self.aperture.radius
|
||||
min_y = min(y) - self.aperture.radius
|
||||
max_y = max(y) + self.aperture.radius
|
||||
return ((min_x, max_x), (min_y, max_y))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class GerberSvgContext(GerberContext):
|
|||
direction = '-' if arc.direction == 'clockwise' else '+'
|
||||
arc_path.push_arc(end, 0, radius, large_arc, direction, True)
|
||||
self.dwg.add(arc_path)
|
||||
|
||||
|
||||
def _render_region(self, region, color):
|
||||
points = [tuple(map(mul, point, self.scale)) for point in region.points]
|
||||
region_path = self.dwg.path(d='M %f, %f' % points[0],
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Author: Hamilton Kibbe <ham@hamiltonkib.be>
|
||||
from ..excellon import read, detect_excellon_format, ExcellonFile
|
||||
from ..cam import FileSettings
|
||||
from ..excellon import read, detect_excellon_format, ExcellonFile, ExcellonParser
|
||||
from tests import *
|
||||
|
||||
import os
|
||||
|
|
@ -25,3 +26,112 @@ def test_read_settings():
|
|||
ncdrill = read(NCDRILL_FILE)
|
||||
assert_equal(ncdrill.settings['format'], (2, 4))
|
||||
assert_equal(ncdrill.settings['zeros'], 'trailing')
|
||||
|
||||
def test_bounds():
|
||||
ncdrill = read(NCDRILL_FILE)
|
||||
xbound, ybound = ncdrill.bounds
|
||||
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)
|
||||
|
||||
def test_parser_hole_count():
|
||||
settings = FileSettings(**detect_excellon_format(NCDRILL_FILE))
|
||||
p = ExcellonParser(settings)
|
||||
p.parse(NCDRILL_FILE)
|
||||
assert_equal(p.hole_count, 36)
|
||||
|
||||
def test_parser_hole_sizes():
|
||||
settings = FileSettings(**detect_excellon_format(NCDRILL_FILE))
|
||||
p = ExcellonParser(settings)
|
||||
p.parse(NCDRILL_FILE)
|
||||
assert_equal(p.hole_sizes, [0.0236, 0.0354, 0.04, 0.126, 0.128])
|
||||
|
||||
def test_parse_whitespace():
|
||||
p = ExcellonParser(FileSettings())
|
||||
assert_equal(p._parse(' '), None)
|
||||
|
||||
def test_parse_comment():
|
||||
p = ExcellonParser(FileSettings())
|
||||
p._parse(';A comment')
|
||||
assert_equal(p.statements[0].comment, 'A comment')
|
||||
|
||||
def test_parse_format_comment():
|
||||
p = ExcellonParser(FileSettings())
|
||||
p._parse('; FILE_FORMAT=9:9 ')
|
||||
assert_equal(p.format, (9, 9))
|
||||
|
||||
def test_parse_header():
|
||||
p = ExcellonParser(FileSettings())
|
||||
p._parse('M48 ')
|
||||
assert_equal(p.state, 'HEADER')
|
||||
p._parse('M95 ')
|
||||
assert_equal(p.state, 'DRILL')
|
||||
|
||||
def test_parse_rout():
|
||||
p = ExcellonParser(FileSettings())
|
||||
p._parse('G00 ')
|
||||
assert_equal(p.state, 'ROUT')
|
||||
p._parse('G05 ')
|
||||
assert_equal(p.state, 'DRILL')
|
||||
|
||||
def test_parse_version():
|
||||
p = ExcellonParser(FileSettings())
|
||||
p._parse('VER,1 ')
|
||||
assert_equal(p.statements[0].version, 1)
|
||||
p._parse('VER,2 ')
|
||||
assert_equal(p.statements[1].version, 2)
|
||||
|
||||
def test_parse_format():
|
||||
p = ExcellonParser(FileSettings())
|
||||
p._parse('FMAT,1 ')
|
||||
assert_equal(p.statements[0].format, 1)
|
||||
p._parse('FMAT,2 ')
|
||||
assert_equal(p.statements[1].format, 2)
|
||||
|
||||
def test_parse_units():
|
||||
settings = FileSettings(units='inch', zeros='trailing')
|
||||
p = ExcellonParser(settings)
|
||||
p._parse(';METRIC,LZ')
|
||||
assert_equal(p.units, 'inch')
|
||||
assert_equal(p.zeros, 'trailing')
|
||||
p._parse('METRIC,LZ')
|
||||
assert_equal(p.units, 'metric')
|
||||
assert_equal(p.zeros, 'leading')
|
||||
|
||||
def test_parse_incremental_mode():
|
||||
settings = FileSettings(units='inch', zeros='trailing')
|
||||
p = ExcellonParser(settings)
|
||||
assert_equal(p.notation, 'absolute')
|
||||
p._parse('ICI,ON ')
|
||||
assert_equal(p.notation, 'incremental')
|
||||
p._parse('ICI,OFF ')
|
||||
assert_equal(p.notation, 'absolute')
|
||||
|
||||
def test_parse_absolute_mode():
|
||||
settings = FileSettings(units='inch', zeros='trailing')
|
||||
p = ExcellonParser(settings)
|
||||
assert_equal(p.notation, 'absolute')
|
||||
p._parse('ICI,ON ')
|
||||
assert_equal(p.notation, 'incremental')
|
||||
p._parse('G90 ')
|
||||
assert_equal(p.notation, 'absolute')
|
||||
|
||||
def test_parse_repeat_hole():
|
||||
p = ExcellonParser(FileSettings())
|
||||
p._parse('R03X1.5Y1.5')
|
||||
assert_equal(p.statements[0].count, 3)
|
||||
|
||||
def test_parse_incremental_position():
|
||||
p = ExcellonParser(FileSettings(notation='incremental'))
|
||||
p._parse('X01Y01')
|
||||
p._parse('X01Y01')
|
||||
assert_equal(p.pos, [2.,2.])
|
||||
|
||||
def test_parse_unknown():
|
||||
p = ExcellonParser(FileSettings())
|
||||
p._parse('Not A Valid Statement')
|
||||
assert_equal(p.statements[0].stmt, 'Not A Valid Statement')
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,17 +7,36 @@ from .tests import assert_equal, assert_raises
|
|||
from ..excellon_statements import *
|
||||
from ..cam import FileSettings
|
||||
|
||||
def test_excellon_statement_implementation():
|
||||
stmt = ExcellonStatement()
|
||||
assert_raises(NotImplementedError, stmt.from_excellon, None)
|
||||
assert_raises(NotImplementedError, stmt.to_excellon)
|
||||
|
||||
def test_excellontool_factory():
|
||||
""" Test ExcellonTool factory method
|
||||
""" Test ExcellonTool factory methods
|
||||
"""
|
||||
exc_line = 'T8F00S00C0.12500'
|
||||
exc_line = 'T8F01B02S00003H04Z05C0.12500'
|
||||
settings = FileSettings(format=(2, 5), zero_suppression='trailing',
|
||||
units='inch', notation='absolute')
|
||||
tool = ExcellonTool.from_excellon(exc_line, settings)
|
||||
assert_equal(tool.number, 8)
|
||||
assert_equal(tool.diameter, 0.125)
|
||||
assert_equal(tool.feed_rate, 0)
|
||||
assert_equal(tool.rpm, 0)
|
||||
assert_equal(tool.feed_rate, 1)
|
||||
assert_equal(tool.retract_rate,2)
|
||||
assert_equal(tool.rpm, 3)
|
||||
assert_equal(tool.max_hit_count, 4)
|
||||
assert_equal(tool.depth_offset, 5)
|
||||
|
||||
stmt = {'number': 8, 'feed_rate': 1, 'retract_rate': 2, 'rpm': 3,
|
||||
'diameter': 0.125, 'max_hit_count': 4, 'depth_offset': 5}
|
||||
tool = ExcellonTool.from_dict(settings, stmt)
|
||||
assert_equal(tool.number, 8)
|
||||
assert_equal(tool.diameter, 0.125)
|
||||
assert_equal(tool.feed_rate, 1)
|
||||
assert_equal(tool.retract_rate,2)
|
||||
assert_equal(tool.rpm, 3)
|
||||
assert_equal(tool.max_hit_count, 4)
|
||||
assert_equal(tool.depth_offset, 5)
|
||||
|
||||
|
||||
def test_excellontool_dump():
|
||||
|
|
@ -25,7 +44,8 @@ def test_excellontool_dump():
|
|||
"""
|
||||
exc_lines = ['T01F0S0C0.01200', 'T02F0S0C0.01500', 'T03F0S0C0.01968',
|
||||
'T04F0S0C0.02800', 'T05F0S0C0.03300', 'T06F0S0C0.03800',
|
||||
'T07F0S0C0.04300', 'T08F0S0C0.12500', 'T09F0S0C0.13000', ]
|
||||
'T07F0S0C0.04300', 'T08F0S0C0.12500', 'T09F0S0C0.13000',
|
||||
'T08B01F02H03S00003C0.12500Z04', 'T01F0S300.999C0.01200']
|
||||
settings = FileSettings(format=(2, 5), zero_suppression='trailing',
|
||||
units='inch', notation='absolute')
|
||||
for line in exc_lines:
|
||||
|
|
@ -44,6 +64,19 @@ def test_excellontool_order():
|
|||
assert_equal(tool1.feed_rate, tool2.feed_rate)
|
||||
assert_equal(tool1.rpm, tool2.rpm)
|
||||
|
||||
def test_excellontool_conversion():
|
||||
tool = ExcellonTool.from_dict(FileSettings(), {'number': 8, 'diameter': 25.4})
|
||||
tool.to_inch()
|
||||
assert_equal(tool.diameter, 1.)
|
||||
tool = ExcellonTool.from_dict(FileSettings(), {'number': 8, 'diameter': 1})
|
||||
tool.to_metric()
|
||||
assert_equal(tool.diameter, 25.4)
|
||||
|
||||
def test_excellontool_repr():
|
||||
tool = ExcellonTool.from_dict(FileSettings(), {'number': 8, 'diameter': 0.125})
|
||||
assert_equal(str(tool), '<ExcellonTool 08: 0.125in. dia.>')
|
||||
tool = ExcellonTool.from_dict(FileSettings(units='metric'), {'number': 8, 'diameter': 0.125})
|
||||
assert_equal(str(tool), '<ExcellonTool 08: 0.125mm dia.>')
|
||||
|
||||
def test_toolselection_factory():
|
||||
""" Test ToolSelectionStmt factory method
|
||||
|
|
@ -93,22 +126,49 @@ def test_coordinatestmt_factory():
|
|||
assert_equal(stmt.y, 0.4639)
|
||||
assert_equal(stmt.to_excellon(settings), "X9660Y4639")
|
||||
|
||||
|
||||
|
||||
def test_coordinatestmt_dump():
|
||||
""" Test CoordinateStmt to_excellon()
|
||||
"""
|
||||
lines = ['X278207Y65293', 'X243795', 'Y82528', 'Y86028',
|
||||
'X251295Y81528', 'X2525Y78', 'X255Y575', 'Y52',
|
||||
'X2675', 'Y575', 'X2425', 'Y52', 'X23', ]
|
||||
|
||||
settings = FileSettings(format=(2, 4), zero_suppression='leading',
|
||||
units='inch', notation='absolute')
|
||||
|
||||
for line in lines:
|
||||
stmt = CoordinateStmt.from_excellon(line, settings)
|
||||
assert_equal(stmt.to_excellon(settings), line)
|
||||
|
||||
def test_coordinatestmt_conversion():
|
||||
stmt = CoordinateStmt.from_excellon('X254Y254', FileSettings())
|
||||
stmt.to_inch()
|
||||
assert_equal(stmt.x, 1.)
|
||||
assert_equal(stmt.y, 1.)
|
||||
stmt = CoordinateStmt.from_excellon('X01Y01', FileSettings())
|
||||
stmt.to_metric()
|
||||
assert_equal(stmt.x, 25.4)
|
||||
assert_equal(stmt.y, 25.4)
|
||||
|
||||
def test_coordinatestmt_string():
|
||||
settings = FileSettings(format=(2, 4), zero_suppression='leading',
|
||||
units='inch', notation='absolute')
|
||||
stmt = CoordinateStmt.from_excellon('X9660Y4639', settings)
|
||||
assert_equal(str(stmt), '<Coordinate Statement: X: 0.966 Y: 0.4639 >')
|
||||
|
||||
|
||||
def test_repeathole_stmt_factory():
|
||||
stmt = RepeatHoleStmt.from_excellon('R0004X015Y32', FileSettings(zeros='leading'))
|
||||
assert_equal(stmt.count, 4)
|
||||
assert_equal(stmt.xdelta, 1.5)
|
||||
assert_equal(stmt.ydelta, 32)
|
||||
|
||||
def test_repeatholestmt_dump():
|
||||
line = 'R4X015Y32'
|
||||
stmt = RepeatHoleStmt.from_excellon(line, FileSettings())
|
||||
assert_equal(stmt.to_excellon(FileSettings()), line)
|
||||
|
||||
def test_repeathole_str():
|
||||
stmt = RepeatHoleStmt.from_excellon('R4X015Y32', FileSettings())
|
||||
assert_equal(str(stmt), '<Repeat Hole: 4 times>')
|
||||
|
||||
def test_commentstmt_factory():
|
||||
""" Test CommentStmt factory method
|
||||
|
|
@ -134,6 +194,35 @@ def test_commentstmt_dump():
|
|||
stmt = CommentStmt.from_excellon(line)
|
||||
assert_equal(stmt.to_excellon(), line)
|
||||
|
||||
def test_header_begin_stmt():
|
||||
stmt = HeaderBeginStmt()
|
||||
assert_equal(stmt.to_excellon(None), 'M48')
|
||||
|
||||
def test_header_end_stmt():
|
||||
stmt = HeaderEndStmt()
|
||||
assert_equal(stmt.to_excellon(None), 'M95')
|
||||
|
||||
def test_rewindstop_stmt():
|
||||
stmt = RewindStopStmt()
|
||||
assert_equal(stmt.to_excellon(None), '%')
|
||||
|
||||
def test_endofprogramstmt_factory():
|
||||
stmt = EndOfProgramStmt.from_excellon('M30X01Y02', FileSettings())
|
||||
assert_equal(stmt.x, 1.)
|
||||
assert_equal(stmt.y, 2.)
|
||||
stmt = EndOfProgramStmt.from_excellon('M30X01', FileSettings())
|
||||
assert_equal(stmt.x, 1.)
|
||||
assert_equal(stmt.y, None)
|
||||
stmt = EndOfProgramStmt.from_excellon('M30Y02', FileSettings())
|
||||
assert_equal(stmt.x, None)
|
||||
assert_equal(stmt.y, 2.)
|
||||
|
||||
def test_endofprogramStmt_dump():
|
||||
lines = ['M30X01Y02',]
|
||||
for line in lines:
|
||||
stmt = EndOfProgramStmt.from_excellon(line, FileSettings())
|
||||
assert_equal(stmt.to_excellon(FileSettings()), line)
|
||||
|
||||
|
||||
def test_unitstmt_factory():
|
||||
""" Test UnitStmt factory method
|
||||
|
|
@ -295,3 +384,25 @@ def test_measmodestmt_validation():
|
|||
"""
|
||||
assert_raises(ValueError, MeasuringModeStmt.from_excellon, 'M70')
|
||||
assert_raises(ValueError, MeasuringModeStmt, 'millimeters')
|
||||
|
||||
|
||||
def test_routemode_stmt():
|
||||
stmt = RouteModeStmt()
|
||||
assert_equal(stmt.to_excellon(FileSettings()), 'G00')
|
||||
|
||||
def test_drillmode_stmt():
|
||||
stmt = DrillModeStmt()
|
||||
assert_equal(stmt.to_excellon(FileSettings()), 'G05')
|
||||
|
||||
def test_absolutemode_stmt():
|
||||
stmt = AbsoluteModeStmt()
|
||||
assert_equal(stmt.to_excellon(FileSettings()), 'G90')
|
||||
|
||||
def test_unknownstmt():
|
||||
stmt = UnknownStmt('TEST')
|
||||
assert_equal(stmt.stmt, 'TEST')
|
||||
assert_equal(str(stmt), '<Unknown Statement: TEST>')
|
||||
|
||||
def test_unknownstmt_dump():
|
||||
stmt = UnknownStmt('TEST')
|
||||
assert_equal(stmt.to_excellon(FileSettings()), 'TEST')
|
||||
|
|
|
|||
|
|
@ -394,6 +394,10 @@ def test_comment_stmt_dump():
|
|||
stmt = CommentStmt('A comment')
|
||||
assert_equal(stmt.to_gerber(), 'G04A comment*')
|
||||
|
||||
def test_comment_stmt_string():
|
||||
stmt = CommentStmt('A comment')
|
||||
assert_equal(str(stmt), '<Comment: A comment>')
|
||||
|
||||
def test_eofstmt():
|
||||
""" Test EofStmt
|
||||
"""
|
||||
|
|
@ -406,6 +410,9 @@ def test_eofstmt_dump():
|
|||
stmt = EofStmt()
|
||||
assert_equal(stmt.to_gerber(), 'M02*')
|
||||
|
||||
def test_eofstmt_string():
|
||||
assert_equal(str(EofStmt()), '<EOF Statement>')
|
||||
|
||||
def test_quadmodestmt_factory():
|
||||
""" Test QuadrantModeStmt.from_gerber()
|
||||
"""
|
||||
|
|
@ -572,8 +579,6 @@ def test_MIParamStmt_string():
|
|||
mi = MIParamStmt.from_dict(stmt)
|
||||
assert_equal(str(mi), '<Image Mirror: A=1 B=0>')
|
||||
|
||||
|
||||
|
||||
def test_coordstmt_ctor():
|
||||
cs = CoordStmt('G04', 0.0, 0.1, 0.2, 0.3, 'D01', FileSettings())
|
||||
assert_equal(cs.function, 'G04')
|
||||
|
|
@ -583,5 +588,67 @@ def test_coordstmt_ctor():
|
|||
assert_equal(cs.j, 0.3)
|
||||
assert_equal(cs.op, 'D01')
|
||||
|
||||
def test_coordstmt_factory():
|
||||
stmt = {'function': 'G04', 'x': '0', 'y': '001', 'i': '002', 'j': '003', 'op': 'D01'}
|
||||
cs = CoordStmt.from_dict(stmt, FileSettings())
|
||||
assert_equal(cs.function, 'G04')
|
||||
assert_equal(cs.x, 0.0)
|
||||
assert_equal(cs.y, 0.1)
|
||||
assert_equal(cs.i, 0.2)
|
||||
assert_equal(cs.j, 0.3)
|
||||
assert_equal(cs.op, 'D01')
|
||||
|
||||
def test_coordstmt_dump():
|
||||
cs = CoordStmt('G04', 0.0, 0.1, 0.2, 0.3, 'D01', FileSettings())
|
||||
assert_equal(cs.to_gerber(FileSettings()), 'G04X0Y001I002J003D01*')
|
||||
|
||||
def test_coordstmt_conversion():
|
||||
cs = CoordStmt('G71', 25.4, 25.4, 25.4, 25.4, 'D01', FileSettings())
|
||||
cs.to_inch()
|
||||
assert_equal(cs.x, 1.)
|
||||
assert_equal(cs.y, 1.)
|
||||
assert_equal(cs.i, 1.)
|
||||
assert_equal(cs.j, 1.)
|
||||
assert_equal(cs.function, 'G70')
|
||||
|
||||
cs = CoordStmt('G70', 1., 1., 1., 1., 'D01', FileSettings())
|
||||
cs.to_metric()
|
||||
assert_equal(cs.x, 25.4)
|
||||
assert_equal(cs.y, 25.4)
|
||||
assert_equal(cs.i, 25.4)
|
||||
assert_equal(cs.j, 25.4)
|
||||
assert_equal(cs.function, 'G71')
|
||||
|
||||
def test_coordstmt_string():
|
||||
cs = CoordStmt('G04', 0, 1, 2, 3, 'D01', FileSettings())
|
||||
assert_equal(str(cs), '<Coordinate Statement: Fn: G04 X: 0 Y: 1 I: 2 J: 3 Op: Lights On>')
|
||||
cs = CoordStmt('G04', None, None, None, None, 'D02', FileSettings())
|
||||
assert_equal(str(cs), '<Coordinate Statement: Fn: G04 Op: Lights Off>')
|
||||
cs = CoordStmt('G04', None, None, None, None, 'D03', FileSettings())
|
||||
assert_equal(str(cs), '<Coordinate Statement: Fn: G04 Op: Flash>')
|
||||
cs = CoordStmt('G04', None, None, None, None, 'TEST', FileSettings())
|
||||
assert_equal(str(cs), '<Coordinate Statement: Fn: G04 Op: TEST>')
|
||||
|
||||
def test_aperturestmt_ctor():
|
||||
ast = ApertureStmt(3, False)
|
||||
assert_equal(ast.d, 3)
|
||||
assert_equal(ast.deprecated, False)
|
||||
ast = ApertureStmt(4, True)
|
||||
assert_equal(ast.d, 4)
|
||||
assert_equal(ast.deprecated, True)
|
||||
ast = ApertureStmt(4, 1)
|
||||
assert_equal(ast.d, 4)
|
||||
assert_equal(ast.deprecated, True)
|
||||
ast = ApertureStmt(3)
|
||||
assert_equal(ast.d, 3)
|
||||
assert_equal(ast.deprecated, False)
|
||||
|
||||
def test_aperturestmt_dump():
|
||||
ast = ApertureStmt(3, False)
|
||||
assert_equal(ast.to_gerber(), 'D3*')
|
||||
ast = ApertureStmt(3, True)
|
||||
assert_equal(ast.to_gerber(), 'G54D3*')
|
||||
assert_equal(str(ast), '<Aperture: 3>')
|
||||
|
||||
|
||||
|
||||
|
|
@ -73,20 +73,21 @@ def test_arc_sweep_angle():
|
|||
((1, 0), (-1, 0), (0, 0), 'counterclockwise', math.radians(180)),]
|
||||
|
||||
for start, end, center, direction, sweep in cases:
|
||||
a = Arc(start, end, center, direction, 0)
|
||||
c = Circle((0,0), 1)
|
||||
a = Arc(start, end, center, direction, c)
|
||||
assert_equal(a.sweep_angle, sweep)
|
||||
|
||||
# Need to update bounds calculation using aperture
|
||||
#def test_arc_bounds():
|
||||
# """ Test Arc primitive bounding box calculation
|
||||
# """
|
||||
# cases = [((1, 0), (0, 1), (0, 0), 'clockwise', ((-1, 1), (-1, 1))),
|
||||
# ((1, 0), (0, 1), (0, 0), 'counterclockwise', ((0, 1), (0, 1))),
|
||||
# #TODO: ADD MORE TEST CASES HERE
|
||||
# ]
|
||||
# for start, end, center, direction, bounds in cases:
|
||||
# a = Arc(start, end, center, direction, 0)
|
||||
# assert_equal(a.bounding_box, bounds)
|
||||
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
|
||||
]
|
||||
for start, end, center, direction, bounds in cases:
|
||||
c = Circle((0,0), 1)
|
||||
a = Arc(start, end, center, direction, c)
|
||||
assert_equal(a.bounding_box, bounds)
|
||||
|
||||
|
||||
def test_circle_radius():
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue