Bunch of small fixes to improve Gerber read/write.

This commit is contained in:
Paulo Henrique Silva 2014-11-10 12:24:09 -02:00
parent f5abd5b0bd
commit ab69ee0172
6 changed files with 53 additions and 42 deletions

View file

@ -215,8 +215,8 @@ class OFParamStmt(ParamStmt):
@classmethod
def from_dict(cls, stmt_dict):
param = stmt_dict.get('param')
a = float(stmt_dict.get('a'))
b = float(stmt_dict.get('b'))
a = float(stmt_dict.get('a', 0))
b = float(stmt_dict.get('b', 0))
return cls(param, a, b)
def __init__(self, param, a, b):
@ -245,17 +245,17 @@ class OFParamStmt(ParamStmt):
def to_gerber(self):
ret = '%OF'
if self.a:
ret += 'A' + decimal_string(self.a, precision=6)
if self.b:
ret += 'B' + decimal_string(self.b, precision=6)
if self.a is not None:
ret += 'A' + decimal_string(self.a, precision=5)
if self.b is not None:
ret += 'B' + decimal_string(self.b, precision=5)
return ret + '*%'
def __str__(self):
offset_str = ''
if self.a:
if self.a is not None:
offset_str += ('X: %f' % self.a)
if self.b:
if self.b is not None:
offset_str += ('Y: %f' % self.b)
return ('<Offset: %s>' % offset_str)
@ -341,7 +341,7 @@ class ADParamStmt(ParamStmt):
else:
self.modifiers = []
def to_gerber(self, settings):
def to_gerber(self):
return '%ADD{0}{1},{2}*%'.format(self.d, self.shape,
','.join(['X'.join(e) for e in self.modifiers]))
@ -540,18 +540,14 @@ class CoordStmt(Statement):
ret = ''
if self.function:
ret += self.function
if self.x:
ret += 'X{0}'.format(write_gerber_value(self.x, self.zeros,
self.format))
if self.y:
ret += 'Y{0}'.format(write_gerber_value(self.y, self. zeros,
self.format))
if self.i:
ret += 'I{0}'.format(write_gerber_value(self.i, self.zeros,
self.format))
if self.j:
ret += 'J{0}'.format(write_gerber_value(self.j, self.zeros,
self.format))
if self.x is not None:
ret += 'X{0}'.format(write_gerber_value(self.x, self.format, self.zero_suppression))
if self.y is not None:
ret += 'Y{0}'.format(write_gerber_value(self.y, self.format, self.zero_suppression))
if self.i is not None:
ret += 'I{0}'.format(write_gerber_value(self.i, self.format, self.zero_suppression))
if self.j is not None:
ret += 'J{0}'.format(write_gerber_value(self.j, self.format, self.zero_suppression))
if self.op:
ret += self.op
return ret + '*'
@ -560,13 +556,13 @@ class CoordStmt(Statement):
coord_str = ''
if self.function:
coord_str += 'Fn: %s ' % self.function
if self.x:
if self.x is not None:
coord_str += 'X: %f ' % self.x
if self.y:
if self.y is not None:
coord_str += 'Y: %f ' % self.y
if self.i:
if self.i is not None:
coord_str += 'I: %f ' % self.i
if self.j:
if self.j is not None:
coord_str += 'J: %f ' % self.j
if self.op:
if self.op == 'D01':
@ -585,12 +581,16 @@ class CoordStmt(Statement):
class ApertureStmt(Statement):
""" Aperture Statement
"""
def __init__(self, d):
def __init__(self, d, deprecated=None):
Statement.__init__(self, "APERTURE")
self.d = int(d)
self.deprecated = True if deprecated is not None else False
def to_gerber(self):
return 'G54D{0}*'.format(self.d)
if self.deprecated:
return 'G54D{0}*'.format(self.d)
else:
return 'D{0}*'.format(self.d)
def __str__(self):
return '<Aperture: %d>' % self.d

View file

@ -109,7 +109,7 @@ class GerberFile(CamFile):
"""
with open(filename, 'w') as f:
for statement in self.statements:
f.write(statement.to_gerber())
f.write(statement.to_gerber() + "\n")
class GerberParser(object):
@ -149,7 +149,7 @@ class GerberParser(object):
r"(I(?P<i>{number}))?(J(?P<j>{number}))?"
r"(?P<op>{op})?\*".format(number=NUMBER, function=FUNCTION, op=COORD_OP)))
APERTURE_STMT = re.compile(r"(G54)?D(?P<d>\d+)\*")
APERTURE_STMT = re.compile(r"(?P<deprecated>G54)?D(?P<d>\d+)\*")
COMMENT_STMT = re.compile(r"G04(?P<comment>[^*]*)(\*)?")

View file

@ -23,9 +23,9 @@ def test_excellontool_factory():
def test_excellontool_dump():
""" Test ExcellonTool to_excellon()
"""
exc_lines = ['T1F00S00C0.01200', 'T2F00S00C0.01500', 'T3F00S00C0.01968',
'T4F00S00C0.02800', 'T5F00S00C0.03300', 'T6F00S00C0.03800',
'T7F00S00C0.04300', 'T8F00S00C0.12500', 'T9F00S00C0.13000', ]
exc_lines = ['T1F0S0C0.01200', 'T2F0S0C0.01500', 'T3F0S0C0.01968',
'T4F0S0C0.02800', 'T5F0S0C0.03300', 'T6F0S0C0.03800',
'T7F0S0C0.04300', 'T8F0S0C0.12500', 'T9F0S0C0.13000', ]
settings = FileSettings(format=(2, 5), zero_suppression='trailing',
units='inch', notation='absolute')
for line in exc_lines:

View file

@ -123,7 +123,7 @@ def test_IPParamStmt_dump():
def test_OFParamStmt_factory():
""" Test OFParamStmt factory
""" Test OFParamStmt factory
"""
stmt = {'param': 'OF', 'a': '0.1234567', 'b': '0.1234567'}
of = OFParamStmt.from_dict(stmt)
@ -139,13 +139,13 @@ def test_OFParamStmt():
assert_equal(stmt.param, param)
assert_equal(stmt.a, val)
assert_equal(stmt.b, val)
def test_OFParamStmt_dump():
""" Test OFParamStmt to_gerber()
"""
stmt = {'param': 'OF', 'a': '0.1234567', 'b': '0.1234567'}
stmt = {'param': 'OF', 'a': '0.123456', 'b': '0.123456'}
of = OFParamStmt.from_dict(stmt)
assert_equal(of.to_gerber(), '%OFA0.123456B0.123456*%')
assert_equal(of.to_gerber(), '%OFA0.12345B0.12345*%')
def test_LPParamStmt_factory():

View file

@ -19,7 +19,8 @@ def test_zero_suppression():
('1000', 0.01), ('10000', 0.1), ('100000', 1.0),
('1000000', 10.0), ('-1', -0.00001), ('-10', -0.0001),
('-100', -0.001), ('-1000', -0.01), ('-10000', -0.1),
('-100000', -1.0), ('-1000000', -10.0), ]
('-100000', -1.0), ('-1000000', -10.0),
('0', 0.0)]
for string, value in test_cases:
assert(value == parse_gerber_value(string, fmt, zero_suppression))
assert(string == write_gerber_value(value, fmt, zero_suppression))
@ -30,7 +31,8 @@ def test_zero_suppression():
('00001', 0.001), ('000001', 0.0001),
('0000001', 0.00001), ('-1', -10.0), ('-01', -1.0),
('-001', -0.1), ('-0001', -0.01), ('-00001', -0.001),
('-000001', -0.0001), ('-0000001', -0.00001)]
('-000001', -0.0001), ('-0000001', -0.00001),
('0', 0.0)]
for string, value in test_cases:
assert(value == parse_gerber_value(string, fmt, zero_suppression))
assert(string == write_gerber_value(value, fmt, zero_suppression))
@ -46,7 +48,8 @@ def test_format():
((2, 1), '1', 0.1), ((2, 7), '-1', -0.0000001),
((2, 6), '-1', -0.000001), ((2, 5), '-1', -0.00001),
((2, 4), '-1', -0.0001), ((2, 3), '-1', -0.001),
((2, 2), '-1', -0.01), ((2, 1), '-1', -0.1), ]
((2, 2), '-1', -0.01), ((2, 1), '-1', -0.1),
((2, 6), '0', 0) ]
for fmt, string, value in test_cases:
assert(value == parse_gerber_value(string, fmt, zero_suppression))
assert(string == write_gerber_value(value, fmt, zero_suppression))
@ -57,7 +60,8 @@ def test_format():
((2, 5), '1', 10.0), ((1, 5), '1', 1.0),
((6, 5), '-1', -100000.0), ((5, 5), '-1', -10000.0),
((4, 5), '-1', -1000.0), ((3, 5), '-1', -100.0),
((2, 5), '-1', -10.0), ((1, 5), '-1', -1.0), ]
((2, 5), '-1', -10.0), ((1, 5), '-1', -1.0),
((2, 5), '0', 0)]
for fmt, string, value in test_cases:
assert(value == parse_gerber_value(string, fmt, zero_suppression))
assert(string == write_gerber_value(value, fmt, zero_suppression))
@ -81,3 +85,6 @@ def test_decimal_padding():
assert_equal(decimal_string(value, precision=4, padding=True), '1.1230')
assert_equal(decimal_string(value, precision=5, padding=True), '1.12300')
assert_equal(decimal_string(value, precision=6, padding=True), '1.123000')
assert_equal(decimal_string(0, precision=6, padding=True), '0.000000')

View file

@ -125,9 +125,9 @@ def write_gerber_value(value, format=(2, 5), zero_suppression='trailing'):
if MAX_DIGITS > 13 or integer_digits > 6 or decimal_digits > 7:
raise ValueError('Parser only supports precision up to 6:7 format')
# Edge case...
# Edge case... (per Gerber spec we should return 0 in all cases, see page 77)
if value == 0:
return '00'
return '0'
# negative sign affects padding, so deal with it at the end...
negative = value < 0.0
@ -173,10 +173,14 @@ def decimal_string(value, precision=6, padding=False):
integer, decimal = floatstr.split('.')
elif ',' in floatstr:
integer, decimal = floatstr.split(',')
else:
integer, decimal = floatstr, "0"
if len(decimal) > precision:
decimal = decimal[:precision]
elif padding:
decimal = decimal + (precision - len(decimal)) * '0'
if integer or decimal:
return ''.join([integer, '.', decimal])
else: