From e3c59e39cf9bc64ce9d76c324b82956a65515f16 Mon Sep 17 00:00:00 2001 From: opiopan Date: Sun, 7 Apr 2019 22:22:33 +0900 Subject: expand test and fix many issues --- README.md | 4 +- gerberex/am_expression.py | 4 +- gerberex/am_primitive.py | 16 +- gerberex/composition.py | 4 +- gerberex/excellon.py | 17 +- gerberex/gerber_statements.py | 115 ++++++++++ gerberex/rs274x.py | 26 ++- gerberex/statements.py | 70 ------ gerberex/utility.py | 3 +- setup.py | 8 +- tests/__init__.py | 0 tests/data/ref_drill_inch.txt | 43 ++++ tests/data/ref_drill_metric.txt | 45 ++++ tests/data/ref_dxf_metric.dxf | 404 +++++++++++++++++++++++++++++++++ tests/data/ref_dxf_mousebites.dxf | 344 ++++++++++++++++++++++++++++ tests/data/ref_gerber_inch.gtl | 79 +++++++ tests/data/ref_gerber_metric.gtl | 84 +++++++ tests/expects/RS2724x_offset.gtl | 79 +++++++ tests/expects/RS2724x_rotate.gtl | 99 ++++++++ tests/expects/RS2724x_save.gtl | 79 +++++++ tests/expects/RS2724x_to_inch.gtl | 79 +++++++ tests/expects/RS2724x_to_metric.gtl | 79 +++++++ tests/expects/dxf_offset.gtl | 42 ++++ tests/expects/dxf_rectangle_inch.gtl | 21 ++ tests/expects/dxf_rectangle_metric.gtl | 21 ++ tests/expects/dxf_rotate.gtl | 42 ++++ tests/expects/dxf_save_fill.gtl | 44 ++++ tests/expects/dxf_save_line.gtl | 42 ++++ tests/expects/dxf_save_mousebites.gtl | 29 +++ tests/expects/dxf_save_mousebites.txt | 29 +++ tests/expects/dxf_to_inch.gtl | 42 ++++ tests/expects/excellon_offset.txt | 43 ++++ tests/expects/excellon_rotate.txt | 43 ++++ tests/expects/excellon_save.txt | 43 ++++ tests/expects/excellon_to_inch.txt | 43 ++++ tests/expects/excellon_to_metric.txt | 43 ++++ tests/test_am_expression.py | 207 +++++++++++++++++ tests/test_dxf.py | 113 +++++++++ tests/test_excellon.py | 72 ++++++ tests/test_rs274x.py | 69 ++++++ tests/test_utility.py | 65 ++++++ 41 files changed, 2634 insertions(+), 100 deletions(-) create mode 100644 gerberex/gerber_statements.py delete mode 100644 gerberex/statements.py create mode 100644 tests/__init__.py create mode 100644 tests/data/ref_drill_inch.txt create mode 100644 tests/data/ref_drill_metric.txt create mode 100644 tests/data/ref_dxf_metric.dxf create mode 100644 tests/data/ref_dxf_mousebites.dxf create mode 100644 tests/data/ref_gerber_inch.gtl create mode 100644 tests/data/ref_gerber_metric.gtl create mode 100644 tests/expects/RS2724x_offset.gtl create mode 100644 tests/expects/RS2724x_rotate.gtl create mode 100644 tests/expects/RS2724x_save.gtl create mode 100644 tests/expects/RS2724x_to_inch.gtl create mode 100644 tests/expects/RS2724x_to_metric.gtl create mode 100644 tests/expects/dxf_offset.gtl create mode 100644 tests/expects/dxf_rectangle_inch.gtl create mode 100644 tests/expects/dxf_rectangle_metric.gtl create mode 100644 tests/expects/dxf_rotate.gtl create mode 100644 tests/expects/dxf_save_fill.gtl create mode 100644 tests/expects/dxf_save_line.gtl create mode 100644 tests/expects/dxf_save_mousebites.gtl create mode 100644 tests/expects/dxf_save_mousebites.txt create mode 100644 tests/expects/dxf_to_inch.gtl create mode 100644 tests/expects/excellon_offset.txt create mode 100644 tests/expects/excellon_rotate.txt create mode 100644 tests/expects/excellon_save.txt create mode 100644 tests/expects/excellon_to_inch.txt create mode 100644 tests/expects/excellon_to_metric.txt create mode 100644 tests/test_am_expression.py create mode 100644 tests/test_dxf.py create mode 100644 tests/test_excellon.py create mode 100644 tests/test_rs274x.py create mode 100644 tests/test_utility.py diff --git a/README.md b/README.md index a2c309d..f992edf 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ In order to fill closed shape, ```DM_FILL``` has to be set to ```draw_mode``` pr import gerberex dxf = gerberex.read('outline.dxf') -dxf.draw_mode = gerberex.DxfFile.DM_FILL +dxf.draw_mode = dxf.DM_FILL dxf.write('outline.gml') ``` @@ -127,7 +127,7 @@ drill = gerberex.read('drill.txt') ctx.merge(drill) dxf = gerberex.read('mousebites.dxf') -dxf.draw_mode = gerberex.DxfFile.DM_MOUSE_BITES +dxf.draw_mode = dxf.DM_MOUSE_BITES dxf.to_metric() dxf.width = 0.5 dxf.pitch = 1 diff --git a/gerberex/am_expression.py b/gerberex/am_expression.py index 7aa95c8..b758df1 100644 --- a/gerberex/am_expression.py +++ b/gerberex/am_expression.py @@ -49,7 +49,7 @@ class AMConstantExpression(AMExpression): return self def to_gerber(self, settings=None): - return str(self._value) + return '%.6g' % self._value def to_instructions(self): return [(OpCode.PUSH, self._value)] @@ -179,5 +179,3 @@ def eval_macro(instructions): elif opcode == OpCode.PRIM: yield (argument, stack) stack = [] - - diff --git a/gerberex/am_primitive.py b/gerberex/am_primitive.py index 82370f6..df55573 100644 --- a/gerberex/am_primitive.py +++ b/gerberex/am_primitive.py @@ -117,14 +117,14 @@ class AMVectorLinePrimitiveDef(AMPrimitiveDef): self.start_x = self.start_x.to_inch().optimize() self.start_y = self.start_y.to_inch().optimize() self.end_x = self.end_x.to_inch().optimize() - self.end_y = self.end_x.to_inch().optimize() + self.end_y = self.end_y.to_inch().optimize() def to_metric(self): self.width = self.width.to_metric().optimize() self.start_x = self.start_x.to_metric().optimize() self.start_y = self.start_y.to_metric().optimize() self.end_x = self.end_x.to_metric().optimize() - self.end_y = self.end_x.to_metric().optimize() + self.end_y = self.end_y.to_metric().optimize() def to_gerber(self, settings=None): data = dict(code = self.code, @@ -197,11 +197,11 @@ class AMCenterLinePrimitiveDef(AMPrimitiveDef): class AMOutlinePrimitiveDef(AMPrimitiveDef): @classmethod def from_modifiers(cls, code, modifiers): - num_points = modifiers[1] + 1 + num_points = int(modifiers[1].value + 1) code = code exposure = 'on' if modifiers[0].value == 1 else 'off' - addrs = modifiers[2:num_points * 2] - rotation = modifiers[3 + num_points * 2] + addrs = modifiers[2:num_points * 2 + 2] + rotation = modifiers[2 + num_points * 2] return cls(code, exposure, addrs, rotation) def __init__(self, code, exposure, addrs, rotation): @@ -209,10 +209,10 @@ class AMOutlinePrimitiveDef(AMPrimitiveDef): self.addrs = addrs def to_inch(self): - self.addrs = [i.to_inch() for i in self.addrs] + self.addrs = [i.to_inch().optimize() for i in self.addrs] def to_metric(self): - self.addrs = [i.to_metric() for i in self.addrs] + self.addrs = [i.to_metric().optimize() for i in self.addrs] def to_gerber(self, settings=None): def strs(): @@ -262,7 +262,7 @@ class AMPolygonPrimitiveDef(AMPrimitiveDef): def to_metric(self): self.x = self.x.to_metric().optimize() self.y = self.y.to_metric().optimize() - self.diameter = self.diameter.to_inch().optimize() + self.diameter = self.diameter.to_metric().optimize() def to_gerber(self, settings=None): data = dict(code = self.code, diff --git a/gerberex/composition.py b/gerberex/composition.py index 73f5702..7abf090 100644 --- a/gerberex/composition.py +++ b/gerberex/composition.py @@ -202,8 +202,8 @@ class DrillComposition(Composition): file.to_inch() if not self.header1_statements: - self.header1_statements = file.header - self.header2_statements = file.header2 + self.header1_statements = [file.header] + self.header2_statements = [file.header2] tool = self._register_tool(ExcellonTool(self.settings, number=1, diameter=file.width)) self.dxf_statements.append((tool.number, file.statements)) diff --git a/gerberex/excellon.py b/gerberex/excellon.py index 90d6742..b72b95b 100644 --- a/gerberex/excellon.py +++ b/gerberex/excellon.py @@ -6,6 +6,7 @@ from gerber.excellon import (ExcellonParser, detect_excellon_format, ExcellonFile) from gerber.excellon_statements import UnitStmt from gerber.cam import FileSettings +from gerber.utils import inch, metric from gerberex.utility import rotate def loads(data, filename=None, settings=None, tools=None, format=None): @@ -33,6 +34,19 @@ class ExcellonFileEx(ExcellonFile): return for hit in self.hits: hit.position = rotate(hit.position[0], hit.position[1], angle, center) + + def to_inch(self): + if self.units == 'metric': + super(ExcellonFileEx, self).to_inch() + for hit in self.hits: + hit.position = (inch(hit.position[0]), inch(hit.position[1])) + + def to_metric(self): + if self.units == 'inch': + super(ExcellonFileEx, self).to_metric() + for hit in self.hits: + hit.position = (metric(hit.position[0]), metric(hit.position[1])) + class UnitStmtEx(UnitStmt): @classmethod @@ -43,7 +57,8 @@ class UnitStmtEx(UnitStmt): super(UnitStmtEx, self).__init__(units, zeros, format, **kwargs) def to_excellon(self, settings=None): + format = settings.format if settings else self.format stmt = '%s,%s,%s.%s' % ('INCH' if self.units == 'inch' else 'METRIC', 'LZ' if self.zeros == 'leading' else 'TZ', - '0' * self.format[0], '0' * self.format[1]) + '0' * format[0], '0' * format[1]) return stmt diff --git a/gerberex/gerber_statements.py b/gerberex/gerber_statements.py new file mode 100644 index 0000000..c2eb565 --- /dev/null +++ b/gerberex/gerber_statements.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright 2019 Hiroshi Murayama + +from gerber.gerber_statements import AMParamStmt, ADParamStmt +from gerber.utils import inch, metric +from gerberex.am_primitive import to_primitive_defs + +class AMParamStmtEx(AMParamStmt): + @classmethod + def from_stmt(cls, stmt): + return cls(stmt.param, stmt.name, stmt.macro, stmt.units) + + @classmethod + def circle(cls, name, units): + return cls('AM', name, '1,1,$1,0,0,0*1,0,$2,0,0,0', units) + + @classmethod + def rectangle(cls, name, units): + return cls('AM', name, '21,1,$1,$2,0,0,0*1,0,$3,0,0,0', units) + + @classmethod + def landscape_obround(cls, name, units): + return cls( + 'AM', name, + '$4=$1-$2*' + '$5=$1-$4*' + '21,1,$5,$2,0,0,0*' + '1,1,$4,$4/2,0,0*' + '1,1,$4,-$4/2,0,0*' + '1,0,$3,0,0,0', units) + + @classmethod + def portrate_obround(cls, name, units): + return cls( + 'AM', name, + '$4=$2-$1*' + '$5=$2-$4*' + '21,1,$1,$5,0,0,0*' + '1,1,$4,0,$4/2,0*' + '1,1,$4,0,-$4/2,0*' + '1,0,$3,0,0,0', units) + + @classmethod + def polygon(cls, name, units): + return cls('AM', name, '5,1,$2,0,0,$1,$3*1,0,$4,0,0,0', units) + + def __init__(self, param, name, macro, units): + super(AMParamStmtEx, self).__init__(param, name, macro) + self.units = units + self.primitive_defs = list(to_primitive_defs(self.instructions)) + + def to_inch(self): + if self.units == 'metric': + self.units = 'inch' + for p in self.primitive_defs: + p.to_inch() + + def to_metric(self): + if self.units == 'inch': + self.units = 'metric' + for p in self.primitive_defs: + p.to_metric() + + def to_gerber(self, settings = None): + def plist(): + for p in self.primitive_defs: + yield p.to_gerber(settings) + return "%%AM%s*\n%s%%" % (self.name, '\n'.join(plist())) + + def rotate(self, angle, center=None): + for primitive_def in self.primitive_defs: + primitive_def.rotate(angle, center) + +class ADParamStmtEx(ADParamStmt): + GEOMETRIES = { + 'C': [0,1], + 'R': [0,1,2], + 'O': [0,1,2], + 'P': [0,3], + } + + @classmethod + def from_stmt(cls, stmt): + modstr = ','.join([ + 'X'.join(['{0}'.format(x) for x in modifier]) + for modifier in stmt.modifiers]) + return cls(stmt.param, stmt.d, stmt.shape, modstr, stmt.units) + + def __init__(self, param, d, shape, modifiers, units): + super(ADParamStmtEx, self).__init__(param, d, shape, modifiers) + self.units = units + + def to_inch(self): + if self.units == 'inch': + return + self.units = 'inch' + if self.shape in self.GEOMETRIES: + indices = self.GEOMETRIES[self.shape] + self.modifiers = [tuple([ + inch(self.modifiers[0][i]) if i in indices else self.modifiers[0][i] \ + for i in range(len(self.modifiers[0])) + ])] + + def to_metric(self): + if self.units == 'metric': + return + self.units = 'metric' + if self.shape in self.GEOMETRIES: + indices = self.GEOMETRIES[self.shape] + self.modifiers = [tuple([ + metric(self.modifiers[0][i]) if i in indices else self.modifiers[0][i] \ + for i in range(len(self.modifiers[0])) + ])] diff --git a/gerberex/rs274x.py b/gerberex/rs274x.py index 4eb317d..13d3421 100644 --- a/gerberex/rs274x.py +++ b/gerberex/rs274x.py @@ -5,7 +5,7 @@ import gerber.rs274x from gerber.gerber_statements import ADParamStmt, CoordStmt -from gerberex.statements import AMParamStmt, AMParamStmtEx +from gerberex.gerber_statements import AMParamStmt, AMParamStmtEx, ADParamStmtEx from gerberex.utility import rotate class GerberFile(gerber.rs274x.GerberFile): @@ -17,6 +17,8 @@ class GerberFile(gerber.rs274x.GerberFile): def swap_statement(statement): if isinstance(statement, AMParamStmt) and not isinstance(statement, AMParamStmtEx): return AMParamStmtEx.from_stmt(statement) + elif isinstance(statement, ADParamStmt) and not isinstance(statement, AMParamStmtEx): + return ADParamStmtEx.from_stmt(statement) else: return statement statements = [swap_statement(statement) for statement in gerber_file.statements] @@ -26,6 +28,18 @@ class GerberFile(gerber.rs274x.GerberFile): def __init__(self, statements, settings, primitives, apertures, filename=None): super(GerberFile, self).__init__(statements, settings, primitives, apertures, filename) + def offset(self, x_offset=0, y_offset=0): + for statement in self.statements: + if isinstance(statement, CoordStmt): + if statement.x is not None: + statement.x += x_offset + if statement.y is not None: + statement.y += y_offset + else: + statement.offset(x_offset, y_offset) + for primitive in self.primitives: + primitive.offset(x_offset, y_offset) + def rotate(self, angle, center=(0,0)): if angle % 360 == 0: return @@ -84,7 +98,7 @@ class GerberFile(gerber.rs274x.GerberFile): while name in macros: name = '%s_%d' % (macro_def[0], num) num += 1 - self.statements.insert(insert_point, macro_def[1](name)) + self.statements.insert(insert_point, macro_def[1](name, self.units)) macro_defs[idx] = (name, macro_def[1]) for idx in range(insert_point, last_aperture + len(macro_defs) + 1): statement = self.statements[idx] @@ -92,10 +106,10 @@ class GerberFile(gerber.rs274x.GerberFile): if statement.shape == 'R': statement.shape = macro_defs[RECTANGLE][0] elif statement.shape == 'O': - x = statement.modifiers[0] \ - if len(statement.modifiers) > 0 else 0 - y = statement.modifiers[1] \ - if len(statement.modifiers) > 1 else 0 + x = statement.modifiers[0][0] \ + if len(statement.modifiers[0]) > 0 else 0 + y = statement.modifiers[0][1] \ + if len(statement.modifiers[0]) > 1 else 0 statement.shape = macro_defs[LANDSCAPE_OBROUND][0] \ if x > y else macro_defs[PORTRATE_OBROUND][0] elif statement.shape == 'P': diff --git a/gerberex/statements.py b/gerberex/statements.py deleted file mode 100644 index c41acb9..0000000 --- a/gerberex/statements.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright 2019 Hiroshi Murayama - -from gerber.gerber_statements import AMParamStmt -from gerberex.am_primitive import to_primitive_defs - -class AMParamStmtEx(AMParamStmt): - @classmethod - def from_stmt(cls, stmt): - return cls(stmt.param, stmt.name, stmt.macro) - - @classmethod - def circle(cls, name): - return cls('AM', name, '1,1,$1,0,0,0*1,0,$2,0,0,0') - - @classmethod - def rectangle(cls, name): - return cls('AM', name, '21,1,$1,$2,0,0,0*1,0,$3,0,0,0') - - @classmethod - def landscape_obround(cls, name): - return cls( - 'AM', name, - '$4=$1-$2*' - '21,1,$1-$4,$2,0,0,0*' - '1,1,$4,$4/2,0,0*' - '1,1,$4,-$4/2,0,0*' - '1,0,$3,0,0,0') - - @classmethod - def portrate_obround(cls, name): - return cls( - 'AM', name, - '$4=$2-$1*' - '21,1,$1,$2-$4,0,0,0*' - '1,1,$4,0,$4/2,0*' - '1,1,$4,0,-$4/2,0*' - '1,0,$3,0,0,0') - - @classmethod - def polygon(cls, name): - return cls('AM', name, '5,1,$2,0,0,$1,$3*1,0,$4,0,0,0') - - def __init__(self, param, name, macro): - super(AMParamStmtEx, self).__init__(param, name, macro) - self.primitive_defs = list(to_primitive_defs(self.instructions)) - - def to_inch(self): - if self.units == 'metric': - self.units = 'inch' - for p in self.primitive_defs: - p.to_inch() - - def to_metric(self): - if self.units == 'inch': - self.units = 'metric' - for p in self.primitive_defs: - p.to_metric() - - def to_gerber(self, settings = None): - def plist(): - for p in self.primitive_defs: - yield p.to_gerber(settings) - return "%%AM%s*\n%s%%" % (self.name, '\n'.join(plist())) - - def rotate(self, angle, center=None): - for primitive_def in self.primitive_defs: - primitive_def.rotate(angle, center) diff --git a/gerberex/utility.py b/gerberex/utility.py index f90df96..4c89fa6 100644 --- a/gerberex/utility.py +++ b/gerberex/utility.py @@ -13,8 +13,7 @@ def rotate(x, y, angle, center): sin(angle) * x0 + cos(angle) * y0 + center[1]) def is_equal_value(a, b, error_range=0): - return a - b <= error_range and a - b >= -error_range - + return (a - b) * (a - b) <= error_range * error_range def is_equal_point(a, b, error_range=0): return is_equal_value(a[0], b[0], error_range) and \ diff --git a/setup.py b/setup.py index eb99d92..72d9c18 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright 2013-2014 Paulo Henrique Silva - -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at +# Copyright 2019 Hiroshi Murayama import os @@ -14,7 +10,7 @@ def read(fname): METADATA = { 'name': 'pcb-tools-extension', - 'version': "0.1.2", + 'version': "0.1.4", 'author': 'Hiroshi Murayama ', 'author_email': "opiopan@gmail.com", 'description': ("Extension for pcb-tools package to panelize gerber files"), diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/data/ref_drill_inch.txt b/tests/data/ref_drill_inch.txt new file mode 100644 index 0000000..8d31df0 --- /dev/null +++ b/tests/data/ref_drill_inch.txt @@ -0,0 +1,43 @@ +M48 +FMAT,2 +ICI,OFF +INCH,TZ,00.0000 +M72 +T01C0.0039 +T02C0.0078 +% +T01 +X1969Y3740 +X2047Y3740 +X2126Y3740 +X2205Y3740 +X2283Y3740 +X2362Y3740 +X2441Y3740 +X2520Y3740 +X2598Y3740 +X2677Y3740 +X2756Y3740 +X2835Y3740 +X2913Y3740 +X2992Y3740 +X3071Y3740 +X3150Y3740 +X3228Y3740 +X3307Y3740 +X3386Y3740 +X3465Y3740 +X3543Y3740 +T02 +X1969Y197 +X2126Y197 +X2283Y197 +X2441Y197 +X2598Y197 +X2756Y197 +X2913Y197 +X3071Y197 +X3228Y197 +X3386Y197 +X3543Y197 +M30 diff --git a/tests/data/ref_drill_metric.txt b/tests/data/ref_drill_metric.txt new file mode 100644 index 0000000..87f20f5 --- /dev/null +++ b/tests/data/ref_drill_metric.txt @@ -0,0 +1,45 @@ +M48 +FMAT,2 +ICI,OFF +METRIC,TZ,000.000 +M71 +T01C0.100 +T02C0.200 +% +T01 +X5000Y9500 +X5200Y9500 +X5400Y9500 +X5600Y9500 +X5800Y9500 +X6000Y9500 +X6200Y9500 +X6400Y9500 +X6600Y9500 +X6800Y9500 +X7000Y9500 +X7200Y9500 +X7400Y9500 +X7600Y9500 +X7800Y9500 +X8000Y9500 +X8200Y9500 +X8400Y9500 +X8600Y9500 +X8800Y9500 +X9000Y9500 + +T02 +X5000Y500 +X5400Y500 +X5800Y500 +X6200Y500 +X6600Y500 +X7000Y500 +X7400Y500 +X7800Y500 +X8200Y500 +X8600Y500 +X9000Y500 + +M30 diff --git a/tests/data/ref_dxf_metric.dxf b/tests/data/ref_dxf_metric.dxf new file mode 100644 index 0000000..89af1e7 --- /dev/null +++ b/tests/data/ref_dxf_metric.dxf @@ -0,0 +1,404 @@ +0 +SECTION +2 +HEADER +9 +$INSUNITS +70 +4 +9 +$ACADVER +1 +AC1014 +9 +$HANDSEED +5 +FFFF +0 +ENDSEC +0 +SECTION +2 +TABLES +0 +TABLE +2 +VPORT +5 +8 +100 +AcDbSymbolTable +0 +ENDTAB +0 +TABLE +2 +LTYPE +5 +5 +100 +AcDbSymbolTable +0 +LTYPE +5 +14 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +2 +BYBLOCK +70 +0 +0 +LTYPE +5 +15 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +2 +BYLAYER +70 +0 +0 +ENDTAB +0 +TABLE +2 +LAYER +5 +2 +100 +AcDbSymbolTable +70 +2 +0 +LAYER +5 +50 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord +2 +0 +70 +0 +6 +CONTINUOUS +0 +ENDTAB +0 +TABLE +2 +STYLE +5 +3 +100 +AcDbSymbolTable +70 +1 +0 +STYLE +5 +11 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord +2 +STANDARD +70 +0 +0 +ENDTAB +0 +TABLE +2 +VIEW +5 +6 +100 +AcDbSymbolTable +70 +0 +0 +ENDTAB +0 +TABLE +2 +UCS +5 +7 +100 +AcDbSymbolTable +70 +0 +0 +ENDTAB +0 +TABLE +2 +APPID +5 +9 +100 +AcDbSymbolTable +70 +2 +0 +APPID +5 +12 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord +2 +ACAD +70 +0 +0 +ENDTAB +0 +TABLE +2 +DIMSTYLE +5 +A +100 +AcDbSymbolTable +70 +1 +0 +ENDTAB +0 +TABLE +2 +BLOCK_RECORD +5 +1 +100 +AcDbSymbolTable +70 +1 +0 +BLOCK_RECORD +5 +1F +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord +2 +*MODEL_SPACE +0 +BLOCK_RECORD +5 +1B +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord +2 +*PAPER_SPACE +0 +ENDTAB +0 +ENDSEC +0 +SECTION +2 +BLOCKS +0 +BLOCK +5 +20 +100 +AcDbEntity +100 +AcDbBlockBegin +2 +*MODEL_SPACE +0 +ENDBLK +5 +21 +100 +AcDbEntity +100 +AcDbBlockEnd +0 +BLOCK +5 +1C +100 +AcDbEntity +100 +AcDbBlockBegin +2 +*PAPER_SPACE +0 +ENDBLK +5 +1D +100 +AcDbEntity +100 +AcDbBlockEnd +0 +ENDSEC +0 +SECTION +2 +ENTITIES +0 +LWPOLYLINE +5 +100 +100 +AcDbEntity +8 +0 +100 +AcDbPolyline +90 +8 +70 +1 +43 +0.0 +10 +9 +20 +0 +10 +1 +20 +0 +42 +-0.41421356237309515 +10 +0 +20 +0.99999999999999978 +10 +6.9388939039072284e-16 +20 +9 +42 +-0.41421356237309548 +10 +0.99999999999999978 +20 +10 +10 +9 +20 +10 +42 +-0.41421356237309509 +10 +10 +20 +9 +10 +10 +20 +1 +42 +-0.41421356237309548 +0 +CIRCLE +5 +101 +100 +AcDbEntity +8 +0 +100 +AcDbCircle +10 +0.61705708382705282 +20 +5 +30 +0 +40 +0.29999999999999999 +0 +LWPOLYLINE +5 +102 +100 +AcDbEntity +8 +0 +100 +AcDbPolyline +90 +3 +70 +1 +43 +0.0 +10 +0.91705708382705309 +20 +7.5106817728417301 +42 +-0.67748879940688445 +10 +0.39955725374872897 +20 +7.3040569342673214 +10 +0.61705708382705282 +20 +7.5106817728417301 +0 +ENDSEC +0 +SECTION +2 +OBJECTS +0 +DICTIONARY +5 +C +100 +AcDbDictionary +3 +ACAD_GROUP +350 +D +3 +ACAD_MLINESTYLE +350 +17 +0 +DICTIONARY +5 +D +100 +AcDbDictionary +0 +DICTIONARY +5 +1A +330 +C +100 +AcDbDictionary +0 +DICTIONARY +5 +17 +100 +AcDbDictionary +0 +ENDSEC +0 +EOF diff --git a/tests/data/ref_dxf_mousebites.dxf b/tests/data/ref_dxf_mousebites.dxf new file mode 100644 index 0000000..fcc56a5 --- /dev/null +++ b/tests/data/ref_dxf_mousebites.dxf @@ -0,0 +1,344 @@ +0 +SECTION +2 +HEADER +9 +$INSUNITS +70 +4 +9 +$ACADVER +1 +AC1014 +9 +$HANDSEED +5 +FFFF +0 +ENDSEC +0 +SECTION +2 +TABLES +0 +TABLE +2 +VPORT +5 +8 +100 +AcDbSymbolTable +0 +ENDTAB +0 +TABLE +2 +LTYPE +5 +5 +100 +AcDbSymbolTable +0 +LTYPE +5 +14 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +2 +BYBLOCK +70 +0 +0 +LTYPE +5 +15 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord +2 +BYLAYER +70 +0 +0 +ENDTAB +0 +TABLE +2 +LAYER +5 +2 +100 +AcDbSymbolTable +70 +2 +0 +LAYER +5 +50 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord +2 +0 +70 +0 +6 +CONTINUOUS +0 +ENDTAB +0 +TABLE +2 +STYLE +5 +3 +100 +AcDbSymbolTable +70 +1 +0 +STYLE +5 +11 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord +2 +STANDARD +70 +0 +0 +ENDTAB +0 +TABLE +2 +VIEW +5 +6 +100 +AcDbSymbolTable +70 +0 +0 +ENDTAB +0 +TABLE +2 +UCS +5 +7 +100 +AcDbSymbolTable +70 +0 +0 +ENDTAB +0 +TABLE +2 +APPID +5 +9 +100 +AcDbSymbolTable +70 +2 +0 +APPID +5 +12 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord +2 +ACAD +70 +0 +0 +ENDTAB +0 +TABLE +2 +DIMSTYLE +5 +A +100 +AcDbSymbolTable +70 +1 +0 +ENDTAB +0 +TABLE +2 +BLOCK_RECORD +5 +1 +100 +AcDbSymbolTable +70 +1 +0 +BLOCK_RECORD +5 +1F +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord +2 +*MODEL_SPACE +0 +BLOCK_RECORD +5 +1B +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord +2 +*PAPER_SPACE +0 +ENDTAB +0 +ENDSEC +0 +SECTION +2 +BLOCKS +0 +BLOCK +5 +20 +100 +AcDbEntity +100 +AcDbBlockBegin +2 +*MODEL_SPACE +0 +ENDBLK +5 +21 +100 +AcDbEntity +100 +AcDbBlockEnd +0 +BLOCK +5 +1C +100 +AcDbEntity +100 +AcDbBlockBegin +2 +*PAPER_SPACE +0 +ENDBLK +5 +1D +100 +AcDbEntity +100 +AcDbBlockEnd +0 +ENDSEC +0 +SECTION +2 +ENTITIES +0 +LINE +5 +100 +100 +AcDbEntity +8 +0 +100 +AcDbLine +10 +0.99999999999999933 +20 +9.0000000000000018 +30 +0 +11 +0.99999999999999967 +21 +0.99999999999999967 +31 +0 +0 +LINE +5 +101 +100 +AcDbEntity +8 +0 +100 +AcDbLine +10 +5 +20 +9.0000000000000018 +30 +0 +11 +5 +21 +0.99999999999999967 +31 +0 +0 +ENDSEC +0 +SECTION +2 +OBJECTS +0 +DICTIONARY +5 +C +100 +AcDbDictionary +3 +ACAD_GROUP +350 +D +3 +ACAD_MLINESTYLE +350 +17 +0 +DICTIONARY +5 +D +100 +AcDbDictionary +0 +DICTIONARY +5 +1A +330 +C +100 +AcDbDictionary +0 +DICTIONARY +5 +17 +100 +AcDbDictionary +0 +ENDSEC +0 +EOF diff --git a/tests/data/ref_gerber_inch.gtl b/tests/data/ref_gerber_inch.gtl new file mode 100644 index 0000000..3ec60d8 --- /dev/null +++ b/tests/data/ref_gerber_inch.gtl @@ -0,0 +1,79 @@ +%MOIN*% +%FSLAX25Y25*% +%INTop Layer*% +%IPPOS*% +%AMCOMP* +20,1,0.00787402,0,0.00393701,0.015748,0.00393701,$1* +21,1,0.015748,0.00787402,-0.00787402,-0.00393701,$1* +1,1,0.015748,-0.0472441,0,$1* +4,1,4,0.0472441,0,0.0551181,-0.00787402,0.0472441,-0.015748,0.0393701,-0.00787402,0.0472441,0,$1* +5,1,6,0.0472441,0.00787402,0.015748,$1* +6,-0.0275591,0,0.019685,0.0019685,0.00590551,2,0.0019685,0.023622,$1* +7,0.0275591,0,0.023622,0.019685,0.00590551,$1*% +%ADD10C,0.0003937*% +%ADD11C,0.03937X0.01575*% +%ADD12R,0.03937X0.01969X0.007874*% +%ADD13O,0.03937X0.01969X0.007874*% +%ADD14O,0.01969X0.03937X0.007874*% +%ADD15P,0.03937X5X90X0.007874*% +%ADD16COMP,0*% +%ADD17COMP,45*% +%ADD18COMP,-45*% +G75* +%LPD*% +D10* +G01* +X3937Y0D02* +X35433Y0D01* +G03* +X39370Y3937I0J3937D01* +G01* +X39370Y35433D01* +G03* +X35433Y39370I-3937J0D01* +G01* +X3937Y39370D01* +G03* +X0Y35433I0J-3937D01* +G01* +X0Y3937D01* +G03* +X3937Y0I3937J0D01* +G01* +G36* +G01* +X17717Y3937D02* +X19685Y3937D01* +G03* +X21654Y5906I0J1969D01* +G01* +X21654Y33465D01* +G03* +X19685Y35433I-1969J0D01* +G01* +X17717Y35433D01* +G03* +X15748Y33465I0J-1969D01* +G01* +X15748Y5906D01* +G03* +X17717Y3937I1969J0D01* +G01* +G37* +D11* +X9843Y3937D03* +D12* +X9843Y11811D03* +D13* +X9843Y19685D03* +D14* +X9843Y27559D03* +D15* +X9843Y35433D03* +D16* +X29528Y19685D03* +D17* +X29528Y29528D03* +D18* +X29528Y9843D03* +M02* diff --git a/tests/data/ref_gerber_metric.gtl b/tests/data/ref_gerber_metric.gtl new file mode 100644 index 0000000..8dfbdd4 --- /dev/null +++ b/tests/data/ref_gerber_metric.gtl @@ -0,0 +1,84 @@ +%MOMM*% +%FSLAX34Y34*% +%INTop Layer*% +%IPPOS*% +%AMCOMP* +20,1,0.2,0,0.1,0.4,0.1,$1* +21,1,0.4,0.2,-0.2,-0.1,$1* +1,1,0.4,-1.2,0,$1* +4,1,4,1.2,0,1.4,-0.2,1.2,-0.4,1,-0.2,1.2,0,$1* +5,1,6,1.2,0.2,0.4,$1* +6,-0.7,0,0.5,0.05,0.15,2,0.05,0.6,$1* +7,0.7,0,0.6,0.5,0.15,$1*% +%ADD10C,0.01*% +%ADD11C,1X0.4*% +%ADD12R,1X0.5X0.2*% +%ADD13O,1X0.5X0.2*% +%ADD14O,0.5X1X0.2*% +%ADD15P,1X5X90X0.2*% +%ADD16COMP,0*% +%ADD17COMP,45*% +%ADD18COMP,-45*% +G75* +%LPD*% + +D10* +G01* +X10000Y0D02* +X90000Y0D01* +G03* +X100000Y10000I0J10000D01* +G01* +X100000Y90000D01* +G03* +X90000Y100000I-10000J0D01* +G01* +X10000Y100000D01* +G03* +X0Y90000I0J-10000D01* +G01* +X0Y10000D01* +G03* +X10000Y0I10000J0D01* +G01* + +G36* +G01* +X45000Y10000D02* +X50000Y10000D01* +G03* +X55000Y15000I0J5000D01* +G01* +X55000Y85000D01* +G03* +X50000Y90000I-5000J0D01* +G01* +X45000Y90000D01* +G03* +X40000Y85000I0J-5000D01* +G01* +X40000Y15000D01* +G03* +X45000Y10000I5000J0D01* +G01* +G37* + +D11* +X25000Y10000D03* +D12* +X25000Y30000D03* +D13* +X25000Y50000D03* +D14* +X25000Y70000D03* +D15* +X25000Y90000D03* + +D16* +X75000Y50000D03* +D17* +X75000Y75000D03* +D18* +X75000Y25000D03* + +M02* diff --git a/tests/expects/RS2724x_offset.gtl b/tests/expects/RS2724x_offset.gtl new file mode 100644 index 0000000..9f15f4c --- /dev/null +++ b/tests/expects/RS2724x_offset.gtl @@ -0,0 +1,79 @@ +%MOMM*% +%FSLAX34Y34*% +%INTop Layer*% +%IPPOS*% +%AMCOMP* +20,1,0.2,0,0.1,0.4,0.1,$1* +21,1,0.4,0.2,-0.2,-0.1,$1* +1,1,0.4,-1.2,0,$1* +4,1,4,1.2,0,1.4,-0.2,1.2,-0.4,1,-0.2,1.2,0,$1* +5,1,6,1.2,0.2,0.4,$1* +6,-0.7,0,0.5,0.05,0.15,2,0.05,0.6,$1* +7,0.7,0,0.6,0.5,0.15,$1*% +%ADD10C,0.01*% +%ADD11C,1X0.4*% +%ADD12R,1X0.5X0.2*% +%ADD13O,1X0.5X0.2*% +%ADD14O,0.5X1X0.2*% +%ADD15P,1X5X90X0.2*% +%ADD16COMP,0*% +%ADD17COMP,45*% +%ADD18COMP,-45*% +G75* +%LPD*% +D10* +G01* +X120000Y50000D02* +X200000Y50000D01* +G03* +X210000Y60000I0J10000D01* +G01* +X210000Y140000D01* +G03* +X200000Y150000I-10000J0D01* +G01* +X120000Y150000D01* +G03* +X110000Y140000I0J-10000D01* +G01* +X110000Y60000D01* +G03* +X120000Y50000I10000J0D01* +G01* +G36* +G01* +X155000Y60000D02* +X160000Y60000D01* +G03* +X165000Y65000I0J5000D01* +G01* +X165000Y135000D01* +G03* +X160000Y140000I-5000J0D01* +G01* +X155000Y140000D01* +G03* +X150000Y135000I0J-5000D01* +G01* +X150000Y65000D01* +G03* +X155000Y60000I5000J0D01* +G01* +G37* +D11* +X135000Y60000D03* +D12* +X135000Y80000D03* +D13* +X135000Y100000D03* +D14* +X135000Y120000D03* +D15* +X135000Y140000D03* +D16* +X185000Y100000D03* +D17* +X185000Y125000D03* +D18* +X185000Y75000D03* +M02* diff --git a/tests/expects/RS2724x_rotate.gtl b/tests/expects/RS2724x_rotate.gtl new file mode 100644 index 0000000..0a2d1aa --- /dev/null +++ b/tests/expects/RS2724x_rotate.gtl @@ -0,0 +1,99 @@ +%MOMM*% +%FSLAX34Y34*% +%INTop Layer*% +%IPPOS*% +%AMCOMP* +20,1,0.2,0,0.1,0.4,0.1,($1)+(20)* +21,1,0.4,0.2,-0.2,-0.1,($1)+(20)* +1,1,0.4,-1.2,0,($1)+(20)* +4,1,4,1.2,0,1.4,-0.2,1.2,-0.4,1,-0.2,1.2,0,($1)+(20)* +5,1,6,1.2,0.2,0.4,($1)+(20)* +6,-0.7,0,0.5,0.05,0.15,2,0.05,0.6,($1)+(20)* +7,0.7,0,0.6,0.5,0.15,($1)+(20)*% +%AMMACP* +5,1,$2,0,0,$1,($3)+(20)* +1,0,$4,0,0,20*% +%AMMACPO* +$4=($2)-($1)* +$5=($2)-($4)* +21,1,$1,$5,0,0,20* +1,1,$4,0,($4)/(2),20* +1,1,$4,0,($4)/(-2),20* +1,0,$3,0,0,20*% +%AMMACLO* +$4=($1)-($2)* +$5=($1)-($4)* +21,1,$5,$2,0,0,20* +1,1,$4,($4)/(2),0,20* +1,1,$4,($4)/(-2),0,20* +1,0,$3,0,0,20*% +%AMMACR* +21,1,$1,$2,0,0,20* +1,0,$3,0,0,20*% +%ADD10C,0.01*% +%ADD11C,1X0.4*% +%ADD12MACR,1X0.5X0.2*% +%ADD13MACLO,1X0.5X0.2*% +%ADD14MACPO,0.5X1X0.2*% +%ADD15MACP,1X5X90X0.2*% +%ADD16COMP,0*% +%ADD17COMP,45*% +%ADD18COMP,-45*% +G75* +%LPD*% +D10* +G01* +X49630Y-24751D02* +X124805Y2611D01* +G03* +X130782Y15428I-3420J9397D01* +G01* +X103420Y90603D01* +G03* +X90603Y96580I-9397J-3420D01* +G01* +X15428Y69218D01* +G03* +X9451Y56401I3420J-9397D01* +G01* +X36813Y-18774D01* +G03* +X49630Y-24751I9397J3420D01* +G01* +G36* +G01* +X79099Y-3383D02* +X83797Y-1673D01* +G03* +X86786Y4735I-1710J4698D01* +G01* +X62844Y70514D01* +G03* +X56436Y73502I-4698J-1710D01* +G01* +X51737Y71792D01* +G03* +X48749Y65383I1710J-4698D01* +G01* +X72690Y-395D01* +G03* +X79099Y-3383I4698J1710D01* +G01* +G37* +D11* +X60305Y-10224D03* +D12* +X53464Y8570D03* +D13* +X46624Y27364D03* +D14* +X39784Y46158D03* +D15* +X32943Y64952D03* +D16* +X93609Y44465D03* +D17* +X85058Y67957D03* +D18* +X102159Y20973D03* +M02* diff --git a/tests/expects/RS2724x_save.gtl b/tests/expects/RS2724x_save.gtl new file mode 100644 index 0000000..02dbaa8 --- /dev/null +++ b/tests/expects/RS2724x_save.gtl @@ -0,0 +1,79 @@ +%MOMM*% +%FSLAX34Y34*% +%INTop Layer*% +%IPPOS*% +%AMCOMP* +20,1,0.2,0,0.1,0.4,0.1,$1* +21,1,0.4,0.2,-0.2,-0.1,$1* +1,1,0.4,-1.2,0,$1* +4,1,4,1.2,0,1.4,-0.2,1.2,-0.4,1,-0.2,1.2,0,$1* +5,1,6,1.2,0.2,0.4,$1* +6,-0.7,0,0.5,0.05,0.15,2,0.05,0.6,$1* +7,0.7,0,0.6,0.5,0.15,$1*% +%ADD10C,0.01*% +%ADD11C,1X0.4*% +%ADD12R,1X0.5X0.2*% +%ADD13O,1X0.5X0.2*% +%ADD14O,0.5X1X0.2*% +%ADD15P,1X5X90X0.2*% +%ADD16COMP,0*% +%ADD17COMP,45*% +%ADD18COMP,-45*% +G75* +%LPD*% +D10* +G01* +X10000Y0D02* +X90000Y0D01* +G03* +X100000Y10000I0J10000D01* +G01* +X100000Y90000D01* +G03* +X90000Y100000I-10000J0D01* +G01* +X10000Y100000D01* +G03* +X0Y90000I0J-10000D01* +G01* +X0Y10000D01* +G03* +X10000Y0I10000J0D01* +G01* +G36* +G01* +X45000Y10000D02* +X50000Y10000D01* +G03* +X55000Y15000I0J5000D01* +G01* +X55000Y85000D01* +G03* +X50000Y90000I-5000J0D01* +G01* +X45000Y90000D01* +G03* +X40000Y85000I0J-5000D01* +G01* +X40000Y15000D01* +G03* +X45000Y10000I5000J0D01* +G01* +G37* +D11* +X25000Y10000D03* +D12* +X25000Y30000D03* +D13* +X25000Y50000D03* +D14* +X25000Y70000D03* +D15* +X25000Y90000D03* +D16* +X75000Y50000D03* +D17* +X75000Y75000D03* +D18* +X75000Y25000D03* +M02* diff --git a/tests/expects/RS2724x_to_inch.gtl b/tests/expects/RS2724x_to_inch.gtl new file mode 100644 index 0000000..3ec60d8 --- /dev/null +++ b/tests/expects/RS2724x_to_inch.gtl @@ -0,0 +1,79 @@ +%MOIN*% +%FSLAX25Y25*% +%INTop Layer*% +%IPPOS*% +%AMCOMP* +20,1,0.00787402,0,0.00393701,0.015748,0.00393701,$1* +21,1,0.015748,0.00787402,-0.00787402,-0.00393701,$1* +1,1,0.015748,-0.0472441,0,$1* +4,1,4,0.0472441,0,0.0551181,-0.00787402,0.0472441,-0.015748,0.0393701,-0.00787402,0.0472441,0,$1* +5,1,6,0.0472441,0.00787402,0.015748,$1* +6,-0.0275591,0,0.019685,0.0019685,0.00590551,2,0.0019685,0.023622,$1* +7,0.0275591,0,0.023622,0.019685,0.00590551,$1*% +%ADD10C,0.0003937*% +%ADD11C,0.03937X0.01575*% +%ADD12R,0.03937X0.01969X0.007874*% +%ADD13O,0.03937X0.01969X0.007874*% +%ADD14O,0.01969X0.03937X0.007874*% +%ADD15P,0.03937X5X90X0.007874*% +%ADD16COMP,0*% +%ADD17COMP,45*% +%ADD18COMP,-45*% +G75* +%LPD*% +D10* +G01* +X3937Y0D02* +X35433Y0D01* +G03* +X39370Y3937I0J3937D01* +G01* +X39370Y35433D01* +G03* +X35433Y39370I-3937J0D01* +G01* +X3937Y39370D01* +G03* +X0Y35433I0J-3937D01* +G01* +X0Y3937D01* +G03* +X3937Y0I3937J0D01* +G01* +G36* +G01* +X17717Y3937D02* +X19685Y3937D01* +G03* +X21654Y5906I0J1969D01* +G01* +X21654Y33465D01* +G03* +X19685Y35433I-1969J0D01* +G01* +X17717Y35433D01* +G03* +X15748Y33465I0J-1969D01* +G01* +X15748Y5906D01* +G03* +X17717Y3937I1969J0D01* +G01* +G37* +D11* +X9843Y3937D03* +D12* +X9843Y11811D03* +D13* +X9843Y19685D03* +D14* +X9843Y27559D03* +D15* +X9843Y35433D03* +D16* +X29528Y19685D03* +D17* +X29528Y29528D03* +D18* +X29528Y9843D03* +M02* diff --git a/tests/expects/RS2724x_to_metric.gtl b/tests/expects/RS2724x_to_metric.gtl new file mode 100644 index 0000000..93adfc1 --- /dev/null +++ b/tests/expects/RS2724x_to_metric.gtl @@ -0,0 +1,79 @@ +%MOMM*% +%FSLAX34Y34*% +%INTop Layer*% +%IPPOS*% +%AMCOMP* +20,1,0.2,0,0.1,0.399999,0.1,$1* +21,1,0.399999,0.2,-0.2,-0.1,$1* +1,1,0.399999,-1.2,0,$1* +4,1,4,1.2,0,1.4,-0.2,1.2,-0.399999,1,-0.2,1.2,0,$1* +5,1,6,1.2,0.2,0.399999,$1* +6,-0.700001,0,0.499999,0.0499999,0.15,2,0.0499999,0.599999,$1* +7,0.700001,0,0.599999,0.499999,0.15,$1*% +%ADD10C,0.01*% +%ADD11C,1X0.4*% +%ADD12R,1X0.5001X0.2*% +%ADD13O,1X0.5001X0.2*% +%ADD14O,0.5001X1X0.2*% +%ADD15P,1X5X90X0.2*% +%ADD16COMP,0*% +%ADD17COMP,45*% +%ADD18COMP,-45*% +G75* +%LPD*% +D10* +G01* +X10000Y0D02* +X90000Y0D01* +G03* +X100000Y10000I0J10000D01* +G01* +X100000Y90000D01* +G03* +X90000Y100000I-10000J0D01* +G01* +X10000Y100000D01* +G03* +X0Y90000I0J-10000D01* +G01* +X0Y10000D01* +G03* +X10000Y0I10000J0D01* +G01* +G36* +G01* +X45001Y10000D02* +X50000Y10000D01* +G03* +X55001Y15001I0J5001D01* +G01* +X55001Y85001D01* +G03* +X50000Y90000I-5001J0D01* +G01* +X45001Y90000D01* +G03* +X40000Y85001I0J-5001D01* +G01* +X40000Y15001D01* +G03* +X45001Y10000I5001J0D01* +G01* +G37* +D11* +X25001Y10000D03* +D12* +X25001Y30000D03* +D13* +X25001Y50000D03* +D14* +X25001Y70000D03* +D15* +X25001Y90000D03* +D16* +X75001Y50000D03* +D17* +X75001Y75001D03* +D18* +X75001Y25001D03* +M02* diff --git a/tests/expects/dxf_offset.gtl b/tests/expects/dxf_offset.gtl new file mode 100644 index 0000000..18d7a62 --- /dev/null +++ b/tests/expects/dxf_offset.gtl @@ -0,0 +1,42 @@ +G75* +%MOMM*% +%OFA0B0*% +%FSLAX34Y34*% +%IPPOS*% +%LPD*% +%ADD10C,0*% +D10* +G01* +X200000Y50000D02* +G75* +G01* +X120000Y50000D01* +G02* +X110000Y60000I0J10000D01* +G01* +X110000Y140000D01* +G02* +X120000Y150000I10000J0D01* +G01* +X200000Y150000D01* +G02* +X210000Y140000I0J-10000D01* +G01* +X210000Y60000D01* +G02* +X200000Y50000I-10000J0D01* +G01* +X119171Y100000D02* +G75* +G03* +X119171Y100000I-3000J0D01* +G01* +X119171Y125107D02* +G75* +G02* +X113996Y123041I-3000J0D01* +G01* +X116171Y125107D01* +G01* +X119171Y125107D01* +M02* diff --git a/tests/expects/dxf_rectangle_inch.gtl b/tests/expects/dxf_rectangle_inch.gtl new file mode 100644 index 0000000..ca99021 --- /dev/null +++ b/tests/expects/dxf_rectangle_inch.gtl @@ -0,0 +1,21 @@ +G75* +%MOIN*% +%OFA0B0*% +%FSLAX25Y25*% +%IPPOS*% +%LPD*% +%ADD10C,0*% +D10* +G01* +X0Y0D02* +X39370Y0D01* +G01* +X39370Y0D02* +X39370Y39370D01* +G01* +X39370Y39370D02* +X0Y39370D01* +G01* +X0Y39370D02* +X0Y0D01* +M02* diff --git a/tests/expects/dxf_rectangle_metric.gtl b/tests/expects/dxf_rectangle_metric.gtl new file mode 100644 index 0000000..db4c439 --- /dev/null +++ b/tests/expects/dxf_rectangle_metric.gtl @@ -0,0 +1,21 @@ +G75* +%MOMM*% +%OFA0B0*% +%FSLAX34Y34*% +%IPPOS*% +%LPD*% +%ADD10C,0*% +D10* +G01* +X0Y0D02* +X100000Y0D01* +G01* +X100000Y0D02* +X100000Y100000D01* +G01* +X100000Y100000D02* +X0Y100000D01* +G01* +X0Y100000D02* +X0Y0D01* +M02* diff --git a/tests/expects/dxf_rotate.gtl b/tests/expects/dxf_rotate.gtl new file mode 100644 index 0000000..912ad60 --- /dev/null +++ b/tests/expects/dxf_rotate.gtl @@ -0,0 +1,42 @@ +G75* +%MOMM*% +%OFA0B0*% +%FSLAX34Y34*% +%IPPOS*% +%LPD*% +%ADD10C,0*% +D10* +G01* +X124805Y2611D02* +G75* +G01* +X49630Y-24751D01* +G02* +X36813Y-18774I-3420J9397D01* +G01* +X9451Y56401D01* +G02* +X15428Y69218I9397J3420D01* +G01* +X90603Y96580D01* +G02* +X103420Y90603I3420J-9397D01* +G01* +X130782Y15428D01* +G02* +X124805Y2611I-9397J-3420D01* +G01* +X31930Y20924D02* +G75* +G03* +X31930Y20924I-3000J0D01* +G01* +X23162Y45543D02* +G75* +G02* +X19006Y41831I-2819J-1026D01* +G01* +X20343Y44517D01* +G01* +X23162Y45543D01* +M02* diff --git a/tests/expects/dxf_save_fill.gtl b/tests/expects/dxf_save_fill.gtl new file mode 100644 index 0000000..c293826 --- /dev/null +++ b/tests/expects/dxf_save_fill.gtl @@ -0,0 +1,44 @@ +G75* +%MOMM*% +%OFA0B0*% +%FSLAX34Y34*% +%IPPOS*% +%LPD*% +%ADD10C,0*% +D10* +G36* +G01* +X90000Y0D02* +G75* +G01* +X10000Y0D01* +G02* +X0Y10000I0J10000D01* +G01* +X0Y90000D01* +G02* +X10000Y100000I10000J0D01* +G01* +X90000Y100000D01* +G02* +X100000Y90000I0J-10000D01* +G01* +X100000Y10000D01* +G02* +X90000Y0I-10000J0D01* +G01* +X9171Y50000D02* +G75* +G03* +X9171Y50000I-3000J0D01* +G01* +X9171Y75107D02* +G75* +G02* +X3996Y73041I-3000J0D01* +G01* +X6171Y75107D01* +G01* +X9171Y75107D01* +G37* +M02* diff --git a/tests/expects/dxf_save_line.gtl b/tests/expects/dxf_save_line.gtl new file mode 100644 index 0000000..e9a931b --- /dev/null +++ b/tests/expects/dxf_save_line.gtl @@ -0,0 +1,42 @@ +G75* +%MOMM*% +%OFA0B0*% +%FSLAX34Y34*% +%IPPOS*% +%LPD*% +%ADD10C,0*% +D10* +G01* +X90000Y0D02* +G75* +G01* +X10000Y0D01* +G02* +X0Y10000I0J10000D01* +G01* +X0Y90000D01* +G02* +X10000Y100000I10000J0D01* +G01* +X90000Y100000D01* +G02* +X100000Y90000I0J-10000D01* +G01* +X100000Y10000D01* +G02* +X90000Y0I-10000J0D01* +G01* +X9171Y50000D02* +G75* +G03* +X9171Y50000I-3000J0D01* +G01* +X9171Y75107D02* +G75* +G02* +X3996Y73041I-3000J0D01* +G01* +X6171Y75107D01* +G01* +X9171Y75107D01* +M02* diff --git a/tests/expects/dxf_save_mousebites.gtl b/tests/expects/dxf_save_mousebites.gtl new file mode 100644 index 0000000..b893454 --- /dev/null +++ b/tests/expects/dxf_save_mousebites.gtl @@ -0,0 +1,29 @@ +G75* +%MOMM*% +%OFA0B0*% +%FSLAX34Y34*% +%IPPOS*% +%LPD*% +%ADD10C,0.5*% +D10* +X10000Y90000D03* +X10000Y80000D03* +X10000Y70000D03* +X10000Y60000D03* +X10000Y50000D03* +X10000Y40000D03* +X10000Y30000D03* +X10000Y20000D03* +X10000Y10000D03* + +X50000Y90000D03* +X50000Y80000D03* +X50000Y70000D03* +X50000Y60000D03* +X50000Y50000D03* +X50000Y40000D03* +X50000Y30000D03* +X50000Y20000D03* +X50000Y10000D03* + +M02* diff --git a/tests/expects/dxf_save_mousebites.txt b/tests/expects/dxf_save_mousebites.txt new file mode 100644 index 0000000..4a371ef --- /dev/null +++ b/tests/expects/dxf_save_mousebites.txt @@ -0,0 +1,29 @@ +M48 +FMAT,2 +ICI,OFF +METRIC,TZ,000.000 +M71 +T01C0.500 +% +T01 +X1000Y9000 +X1000Y8000 +X1000Y7000 +X1000Y6000 +X1000Y5000 +X1000Y4000 +X1000Y3000 +X1000Y2000 +X1000Y1000 + +X5000Y9000 +X5000Y8000 +X5000Y7000 +X5000Y6000 +X5000Y5000 +X5000Y4000 +X5000Y3000 +X5000Y2000 +X5000Y1000 + +M30 diff --git a/tests/expects/dxf_to_inch.gtl b/tests/expects/dxf_to_inch.gtl new file mode 100644 index 0000000..ee630c9 --- /dev/null +++ b/tests/expects/dxf_to_inch.gtl @@ -0,0 +1,42 @@ +G75* +%MOIN*% +%OFA0B0*% +%FSLAX25Y25*% +%IPPOS*% +%LPD*% +%ADD10C,0*% +D10* +G01* +X35433Y0D02* +G75* +G01* +X3937Y0D01* +G02* +X0Y3937I0J3937D01* +G01* +X0Y35433D01* +G02* +X3937Y39370I3937J0D01* +G01* +X35433Y39370D01* +G02* +X39370Y35433I0J-3937D01* +G01* +X39370Y3937D01* +G02* +X35433Y0I-3937J0D01* +G01* +X3610Y19685D02* +G75* +G03* +X3610Y19685I-1181J0D01* +G01* +X3610Y29570D02* +G75* +G02* +X1573Y28756I-1181J0D01* +G01* +X2429Y29570D01* +G01* +X3610Y29570D01* +M02* diff --git a/tests/expects/excellon_offset.txt b/tests/expects/excellon_offset.txt new file mode 100644 index 0000000..2007248 --- /dev/null +++ b/tests/expects/excellon_offset.txt @@ -0,0 +1,43 @@ +M48 +FMAT,2 +ICI,OFF +METRIC,TZ,000.000 +M71 +T01C0.100 +T02C0.200 +% +T01 +X16000Y14500 +X16200Y14500 +X16400Y14500 +X16600Y14500 +X16800Y14500 +X17000Y14500 +X17200Y14500 +X17400Y14500 +X17600Y14500 +X17800Y14500 +X18000Y14500 +X18200Y14500 +X18400Y14500 +X18600Y14500 +X18800Y14500 +X19000Y14500 +X19200Y14500 +X19400Y14500 +X19600Y14500 +X19800Y14500 +X20000Y14500 +T02 +X16000Y5500 +X16400Y5500 +X16800Y5500 +X17200Y5500 +X17600Y5500 +X18000Y5500 +X18400Y5500 +X18800Y5500 +X19200Y5500 +X19600Y5500 +X20000Y5500 +M30 diff --git a/tests/expects/excellon_rotate.txt b/tests/expects/excellon_rotate.txt new file mode 100644 index 0000000..2ef3540 --- /dev/null +++ b/tests/expects/excellon_rotate.txt @@ -0,0 +1,43 @@ +M48 +FMAT,2 +ICI,OFF +METRIC,TZ,000.000 +M71 +T01C0.100 +T02C0.200 +% +T01 +X5473Y7820 +X5660Y7888 +X5848Y7957 +X6036Y8025 +X6224Y8094 +X6412Y8162 +X6600Y8230 +X6788Y8299 +X6976Y8367 +X7164Y8436 +X7352Y8504 +X7540Y8572 +X7728Y8641 +X7916Y8709 +X8104Y8778 +X8292Y8846 +X8480Y8915 +X8668Y8983 +X8855Y9051 +X9043Y9120 +X9231Y9188 +T02 +X8551Y-637 +X8927Y-500 +X9302Y-364 +X9678Y-227 +X10054Y-90 +X10430Y47 +X10806Y184 +X11182Y320 +X11558Y457 +X11934Y594 +X12309Y731 +M30 diff --git a/tests/expects/excellon_save.txt b/tests/expects/excellon_save.txt new file mode 100644 index 0000000..a1d2ba8 --- /dev/null +++ b/tests/expects/excellon_save.txt @@ -0,0 +1,43 @@ +M48 +FMAT,2 +ICI,OFF +METRIC,TZ,000.000 +M71 +T01C0.100 +T02C0.200 +% +T01 +X5000Y9500 +X5200Y9500 +X5400Y9500 +X5600Y9500 +X5800Y9500 +X6000Y9500 +X6200Y9500 +X6400Y9500 +X6600Y9500 +X6800Y9500 +X7000Y9500 +X7200Y9500 +X7400Y9500 +X7600Y9500 +X7800Y9500 +X8000Y9500 +X8200Y9500 +X8400Y9500 +X8600Y9500 +X8800Y9500 +X9000Y9500 +T02 +X5000Y500 +X5400Y500 +X5800Y500 +X6200Y500 +X6600Y500 +X7000Y500 +X7400Y500 +X7800Y500 +X8200Y500 +X8600Y500 +X9000Y500 +M30 diff --git a/tests/expects/excellon_to_inch.txt b/tests/expects/excellon_to_inch.txt new file mode 100644 index 0000000..8d31df0 --- /dev/null +++ b/tests/expects/excellon_to_inch.txt @@ -0,0 +1,43 @@ +M48 +FMAT,2 +ICI,OFF +INCH,TZ,00.0000 +M72 +T01C0.0039 +T02C0.0078 +% +T01 +X1969Y3740 +X2047Y3740 +X2126Y3740 +X2205Y3740 +X2283Y3740 +X2362Y3740 +X2441Y3740 +X2520Y3740 +X2598Y3740 +X2677Y3740 +X2756Y3740 +X2835Y3740 +X2913Y3740 +X2992Y3740 +X3071Y3740 +X3150Y3740 +X3228Y3740 +X3307Y3740 +X3386Y3740 +X3465Y3740 +X3543Y3740 +T02 +X1969Y197 +X2126Y197 +X2283Y197 +X2441Y197 +X2598Y197 +X2756Y197 +X2913Y197 +X3071Y197 +X3228Y197 +X3386Y197 +X3543Y197 +M30 diff --git a/tests/expects/excellon_to_metric.txt b/tests/expects/excellon_to_metric.txt new file mode 100644 index 0000000..a634742 --- /dev/null +++ b/tests/expects/excellon_to_metric.txt @@ -0,0 +1,43 @@ +M48 +FMAT,2 +ICI,OFF +METRIC,TZ,000.000 +M71 +T01C0.099 +T02C0.198 +% +T01 +X5001Y9500 +X5199Y9500 +X5400Y9500 +X5601Y9500 +X5799Y9500 +X5999Y9500 +X6200Y9500 +X6401Y9500 +X6599Y9500 +X6800Y9500 +X7000Y9500 +X7201Y9500 +X7399Y9500 +X7600Y9500 +X7800Y9500 +X8001Y9500 +X8199Y9500 +X8400Y9500 +X8600Y9500 +X8801Y9500 +X8999Y9500 +T02 +X5001Y500 +X5400Y500 +X5799Y500 +X6200Y500 +X6599Y500 +X7000Y500 +X7399Y500 +X7800Y500 +X8199Y500 +X8600Y500 +X8999Y500 +M30 diff --git a/tests/test_am_expression.py b/tests/test_am_expression.py new file mode 100644 index 0000000..6786cc3 --- /dev/null +++ b/tests/test_am_expression.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright 2019 Hiroshi Murayama + +import unittest +from gerberex.am_expression import * +from gerberex.am_expression import AMOperatorExpression as Op +from gerber.utils import inch, metric +from gerber.am_read import read_macro + +class TestAMConstantExpression(unittest.TestCase): + def setUp(self): + self.const_int_value = 7 + self.const_int = AMConstantExpression(self.const_int_value) + self.const_float_value = 1.2345 + self.const_float = AMConstantExpression(self.const_float_value) + + def test_contruct(self): + self.assertEqual(self.const_int.value, self.const_int_value) + self.assertEqual(self.const_float.value, self.const_float_value) + + def test_optimize(self): + ov = self.const_int.optimize() + self.assertEqual(ov.value, self.const_int_value) + ov = self.const_float.optimize() + self.assertEqual(ov.value, self.const_float_value) + + def test_to_gerber(self): + self.assertEqual(self.const_int.to_gerber(), '7') + self.assertEqual(self.const_float.to_gerber(), '1.2345') + + def test_to_instructions(self): + self.const_int.to_instructions() + self.const_float.to_instructions() + +class TestAMVariableExpression(unittest.TestCase): + def setUp(self): + self.var1_num = 1 + self.var1 = AMVariableExpression(self.var1_num) + self.var2_num = 512 + self.var2 = AMVariableExpression(self.var2_num) + + def test_construction(self): + self.assertEqual(self.var1.number, self.var1_num) + self.assertEqual(self.var2.number, self.var2_num) + + def test_optimize(self): + ov = self.var1.optimize() + self.assertTrue(isinstance(ov, AMVariableExpression)) + self.assertEqual(ov.number, self.var1_num) + ov = self.var2.optimize() + self.assertTrue(isinstance(ov, AMVariableExpression)) + self.assertEqual(ov.number, self.var2_num) + + def test_to_gerber(self): + self.assertEqual(self.var1.to_gerber(), '$1') + self.assertEqual(self.var2.to_gerber(), '$512') + + def test_to_instructions(self): + self.var1.to_instructions() + self.var2.to_instructions() + +class TestAMOperatorExpression(unittest.TestCase): + def setUp(self): + self.c1 = 10 + self.c2 = 20 + self.v1 = 5 + self.v2 = 9 + c1 = AMConstantExpression(self.c1) + c2 = AMConstantExpression(self.c2) + v1 = AMVariableExpression(self.v1) + v2 = AMVariableExpression(self.v2) + + self.cc_exps = [ + (Op.ADD, AMOperatorExpression(Op.ADD, c1, c2)), + (Op.SUB, AMOperatorExpression(Op.SUB, c1, c2)), + (Op.MUL, AMOperatorExpression(Op.MUL, c1, c2)), + (Op.DIV, AMOperatorExpression(Op.DIV, c1, c2)), + ] + + self.cv_exps = [ + (Op.ADD, AMOperatorExpression(Op.ADD, c1, v2)), + (Op.SUB, AMOperatorExpression(Op.SUB, c1, v2)), + (Op.MUL, AMOperatorExpression(Op.MUL, c1, v2)), + (Op.DIV, AMOperatorExpression(Op.DIV, c1, v2)), + ] + self.vc_exps = [ + (Op.ADD, AMOperatorExpression(Op.ADD, v1, c2)), + (Op.SUB, AMOperatorExpression(Op.SUB, v1, c2)), + (Op.MUL, AMOperatorExpression(Op.MUL, v1, c2)), + (Op.DIV, AMOperatorExpression(Op.DIV, v1, c2)), + ] + + self.composition = AMOperatorExpression(Op.ADD, + self.cc_exps[0][1], self.cc_exps[0][1]) + + def test_optimize(self): + self.assertEqual(self.cc_exps[0][1].optimize().value, self.c1 + self.c2) + self.assertEqual(self.cc_exps[1][1].optimize().value, self.c1 - self.c2) + self.assertEqual(self.cc_exps[2][1].optimize().value, self.c1 * self.c2) + self.assertEqual(self.cc_exps[3][1].optimize().value, self.c1 / self.c2) + + for op, expression in self.cv_exps: + o = expression.optimize() + self.assertTrue(isinstance(o, AMOperatorExpression)) + self.assertEqual(o.op, op) + self.assertEqual(o.lvalue.value, self.c1) + self.assertEqual(o.rvalue.number, self.v2) + + for op, expression in self.vc_exps: + o = expression.optimize() + self.assertTrue(isinstance(o, AMOperatorExpression)) + self.assertEqual(o.op, op) + self.assertEqual(o.lvalue.number, self.v1) + self.assertEqual(o.rvalue.value, self.c2) + + self.assertEqual(self.composition.optimize().value, (self.c1 + self.c2) * 2) + + def test_to_gerber(self): + for op, expression in self.cc_exps: + self.assertEqual(expression.to_gerber(), + '({0}){1}({2})'.format(self.c1, op, self.c2)) + for op, expression in self.cv_exps: + self.assertEqual(expression.to_gerber(), + '({0}){1}(${2})'.format(self.c1, op, self.v2)) + for op, expression in self.vc_exps: + self.assertEqual(expression.to_gerber(), + '(${0}){1}({2})'.format(self.v1, op, self.c2)) + self.assertEqual(self.composition.to_gerber(), + '(({0})+({1}))+(({2})+({3}))'.format( + self.c1, self.c2, self.c1, self.c2 + )) + + def test_to_instructions(self): + for of, expression in self.vc_exps + self.cv_exps + self.cc_exps: + expression.to_instructions() + self.composition.to_instructions() + +class TestAMExpression(unittest.TestCase): + def setUp(self): + self.c1 = 10 + self.c1_exp = AMConstantExpression(self.c1) + self.v1 = 5 + self.v1_exp = AMVariableExpression(self.v1) + self.op_exp = AMOperatorExpression(Op.ADD, self.c1_exp, self.v1_exp) + + def test_to_inch(self): + o = self.c1_exp.to_inch().optimize() + self.assertEqual(o.value, inch(self.c1)) + o = self.v1_exp.to_inch().optimize() + self.assertTrue(isinstance(o, AMOperatorExpression)) + self.assertEqual(o.op, Op.DIV) + o = self.op_exp.to_inch().optimize() + self.assertTrue(isinstance(o, AMOperatorExpression)) + self.assertEqual(o.op, Op.DIV) + + def test_to_metric(self): + o = self.c1_exp.to_metric().optimize() + self.assertEqual(o.value, metric(self.c1)) + o = self.v1_exp.to_metric().optimize() + self.assertTrue(isinstance(o, AMOperatorExpression)) + self.assertEqual(o.op, Op.MUL) + o = self.op_exp.to_metric().optimize() + self.assertTrue(isinstance(o, AMOperatorExpression)) + self.assertEqual(o.op, Op.MUL) + +class TestEvalMacro(unittest.TestCase): + def test_eval_macro(self): + macros = [ + '$1=5.5*', + '$2=$3*', + '$3=(1.23)+(4.56)*', + '$3=(1.23)-(4.56)*', + '$3=(1.23)X(4.56)*', + '$3=(1.23)/(4.56)*', + '$3=(10.2)X($2)*', + '1,1.2*', + '1,$2*', + '1,($2)+($3)*', + #'1,(2.0)-($3)*', # This doesn't pass due to pcb-tools bug + '1,($2)X($3)*', + '1,($2)/($3)*', + '1,2.1,3.2*2,(3.1)/($1),$2*' + ] + for macro in macros: + self._eval_macro_string(macro) + + def _eval_macro_string(self, macro): + expressions = eval_macro(read_macro(macro)) + gerber = self._to_gerber(expressions) + self.assertEqual(macro, gerber) + + def _to_gerber(self, expressions_list): + gerber = '' + for number, expressions in expressions_list: + self.assertTrue(isinstance(number, int)) + if number > 0: + egerbers = [exp.to_gerber() for exp in expressions] + gerber += '{0},{1}*'.format(number, ','.join(egerbers)) + else: + self.assertEqual(len(expressions), 1) + gerber += '${0}={1}*'.format(-number, expressions[0].to_gerber()) + return gerber + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_dxf.py b/tests/test_dxf.py new file mode 100644 index 0000000..31589da --- /dev/null +++ b/tests/test_dxf.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright 2019 Hiroshi Murayama + +import os +import unittest +import gerberex +from gerber.utils import inch, metric + + +class TestExcellon(unittest.TestCase): + @classmethod + def setUpClass(cls): + os.chdir(os.path.dirname(__file__)) + cls.INDIR = 'data' + cls.OUTDIR = 'outputs' + cls.EXPECTSDIR = 'expects' + cls.OUTPREFIX = 'dxf_' + cls.METRIC_FILE = os.path.join(cls.INDIR, 'ref_dxf_metric.dxf') + cls.INCH_FILE = os.path.join(cls.INDIR, 'ref_dxf_inch.dxf') + cls.MOUSEBITES_FILE = os.path.join(cls.INDIR, 'ref_dxf_mousebites.dxf') + try: + os.mkdir(cls.OUTDIR) + except FileExistsError: + pass + + def _checkResult(self, file): + with open(file, 'r') as f: + data = f.read() + with open(os.path.join(self.EXPECTSDIR, os.path.basename(file)), 'r') as f: + expect = f.read() + self.assertEqual(data, expect) + + def test_save_line(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'save_line.gtl') + dxf = gerberex.read(self.METRIC_FILE) + dxf.draw_mode = dxf.DM_LINE + dxf.write(outfile) + self._checkResult(outfile) + + def test_save_fill(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'save_fill.gtl') + dxf = gerberex.read(self.METRIC_FILE) + dxf.draw_mode = dxf.DM_FILL + dxf.write(outfile) + self._checkResult(outfile) + + def test_save_mousebites(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'save_mousebites.gtl') + dxf = gerberex.read(self.MOUSEBITES_FILE) + dxf.draw_mode = dxf.DM_MOUSE_BITES + dxf.width = 0.5 + dxf.pitch = 1 + dxf.write(outfile) + self._checkResult(outfile) + + def test_save_excellon(self): + outfile = os.path.join( + self.OUTDIR, self.OUTPREFIX + 'save_mousebites.txt') + dxf = gerberex.read(self.MOUSEBITES_FILE) + dxf.draw_mode = dxf.DM_MOUSE_BITES + dxf.format = (3,3) + dxf.width = 0.5 + dxf.pitch = 1 + dxf.write(outfile, filetype=dxf.FT_EXCELLON) + self._checkResult(outfile) + + def test_to_inch(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'to_inch.gtl') + dxf = gerberex.read(self.METRIC_FILE) + dxf.to_inch() + dxf.format = (2, 5) + dxf.write(outfile) + self._checkResult(outfile) + + def _test_to_metric(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'to_metric.gtl') + dxf = gerberex.read(self.INCH_FILE) + dxf.to_metric() + dxf.format = (3, 5) + dxf.write(outfile) + self._checkResult(outfile) + + def test_offset(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'offset.gtl') + dxf = gerberex.read(self.METRIC_FILE) + dxf.offset(11, 5) + dxf.write(outfile) + self._checkResult(outfile) + + def test_rotate(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'rotate.gtl') + dxf = gerberex.read(self.METRIC_FILE) + dxf.rotate(20, (10, 10)) + dxf.write(outfile) + self._checkResult(outfile) + + def test_rectangle_metric(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'rectangle_metric.gtl') + dxf = gerberex.DxfFile.rectangle(width=10, height=10, units='metric') + dxf.write(outfile) + self._checkResult(outfile) + + def test_rectangle_inch(self): + outfile = os.path.join( + self.OUTDIR, self.OUTPREFIX + 'rectangle_inch.gtl') + dxf = gerberex.DxfFile.rectangle(width=inch(10), height=inch(10), units='inch') + dxf.write(outfile) + self._checkResult(outfile) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_excellon.py b/tests/test_excellon.py new file mode 100644 index 0000000..36093cd --- /dev/null +++ b/tests/test_excellon.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright 2019 Hiroshi Murayama + +import os +import unittest +import gerberex + + +class TestExcellon(unittest.TestCase): + @classmethod + def setUpClass(cls): + os.chdir(os.path.dirname(__file__)) + cls.INDIR = 'data' + cls.OUTDIR = 'outputs' + cls.EXPECTSDIR = 'expects' + cls.OUTPREFIX = 'excellon_' + cls.METRIC_FILE = os.path.join(cls.INDIR, 'ref_drill_metric.txt') + cls.INCH_FILE = os.path.join(cls.INDIR, 'ref_drill_inch.txt') + try: + os.mkdir(cls.OUTDIR) + except FileExistsError: + pass + + def _checkResult(self, file): + with open(file, 'r') as f: + data = f.read() + with open(os.path.join(self.EXPECTSDIR, os.path.basename(file)), 'r') as f: + expect = f.read() + self.assertEqual(data, expect) + pass + + def test_save(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'save.txt') + drill = gerberex.read(self.METRIC_FILE) + drill.write(outfile) + self._checkResult(outfile) + + def test_to_inch(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'to_inch.txt') + drill = gerberex.read(self.METRIC_FILE) + drill.to_inch() + drill.format = (2, 4) + drill.write(outfile) + self._checkResult(outfile) + + def test_to_metric(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'to_metric.txt') + drill = gerberex.read(self.INCH_FILE) + drill.to_metric() + drill.format = (3, 3) + drill.write(outfile) + self._checkResult(outfile) + + def test_offset(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'offset.txt') + drill = gerberex.read(self.METRIC_FILE) + drill.offset(11, 5) + drill.write(outfile) + self._checkResult(outfile) + + def test_rotate(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'rotate.txt') + drill = gerberex.read(self.METRIC_FILE) + drill.rotate(20, (10, 10)) + drill.write(outfile) + self._checkResult(outfile) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_rs274x.py b/tests/test_rs274x.py new file mode 100644 index 0000000..3e44066 --- /dev/null +++ b/tests/test_rs274x.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright 2019 Hiroshi Murayama + +import os +import unittest +import gerberex + +class TestRs274x(unittest.TestCase): + @classmethod + def setUpClass(cls): + os.chdir(os.path.dirname(__file__)) + cls.INDIR = 'data' + cls.OUTDIR = 'outputs' + cls.EXPECTSDIR = 'expects' + cls.OUTPREFIX = 'RS2724x_' + cls.METRIC_FILE = os.path.join(cls.INDIR, 'ref_gerber_metric.gtl') + cls.INCH_FILE = os.path.join(cls.INDIR, 'ref_gerber_inch.gtl') + try: + os.mkdir(cls.OUTDIR) + except FileExistsError: + pass + + def _checkResult(self, file): + with open(file, 'r') as f: + data = f.read() + with open(os.path.join(self.EXPECTSDIR, os.path.basename(file)), 'r') as f: + expect = f.read() + self.assertEqual(data, expect) + + def test_save(self): + outfile=os.path.join(self.OUTDIR, self.OUTPREFIX + 'save.gtl') + gerber = gerberex.read(self.METRIC_FILE) + gerber.write(outfile) + self._checkResult(outfile) + + def test_to_inch(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'to_inch.gtl') + gerber = gerberex.read(self.METRIC_FILE) + gerber.to_inch() + gerber.format = (2,5) + gerber.write(outfile) + self._checkResult(outfile) + + def test_to_metric(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'to_metric.gtl') + gerber = gerberex.read(self.INCH_FILE) + gerber.to_metric() + gerber.format = (3, 4) + gerber.write(outfile) + self._checkResult(outfile) + + def test_offset(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'offset.gtl') + gerber = gerberex.read(self.METRIC_FILE) + gerber.offset(11, 5) + gerber.write(outfile) + self._checkResult(outfile) + + def test_rotate(self): + outfile = os.path.join(self.OUTDIR, self.OUTPREFIX + 'rotate.gtl') + gerber = gerberex.read(self.METRIC_FILE) + gerber.rotate(20, (10,10)) + gerber.write(outfile) + self._checkResult(outfile) + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_utility.py b/tests/test_utility.py new file mode 100644 index 0000000..4ede8d5 --- /dev/null +++ b/tests/test_utility.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright 2019 Hiroshi Murayama + +import unittest + +from gerberex.utility import * +from math import sqrt + +class TestUtility(unittest.TestCase): + def test_rotate(self): + x0, y0 = (10, 0) + + x1, y1 = rotate(x0, y0, 60, (0, 0)) + self.assertAlmostEqual(x1, 5) + self.assertAlmostEqual(y1, 10 * sqrt(3) / 2) + + x1, y1 = rotate(x0, y0, 180, (5, 0)) + self.assertAlmostEqual(x1, 0) + self.assertAlmostEqual(y1, 0) + + x1, y1 = rotate(x0, y0, -90, (10, 5)) + self.assertAlmostEqual(x1, 5) + self.assertAlmostEqual(y1, 5) + + def test_is_equal_value(self): + a = 10.0001 + b = 10.01 + + self.assertTrue(is_equal_value(a, b, 0.1)) + self.assertTrue(is_equal_value(a, b, 0.01)) + self.assertFalse(is_equal_value(a, b, 0.001)) + self.assertFalse(is_equal_value(a, b)) + + self.assertTrue(is_equal_value(b, a, 0.1)) + self.assertTrue(is_equal_value(b, a, 0.01)) + self.assertFalse(is_equal_value(b, a, 0.001)) + self.assertFalse(is_equal_value(b, a)) + + def test_is_equal_point(self): + p0 = (10.01, 5.001) + p1 = (10.0001, 5) + self.assertTrue(is_equal_point(p0, p1, 0.1)) + self.assertTrue(is_equal_point(p0, p1, 0.01)) + self.assertFalse(is_equal_point(p0, p1, 0.001)) + self.assertFalse(is_equal_point(p0, p1)) + self.assertTrue(is_equal_point(p1, p0, 0.1)) + self.assertTrue(is_equal_point(p1, p0, 0.01)) + self.assertFalse(is_equal_point(p1, p0, 0.001)) + self.assertFalse(is_equal_point(p1, p0)) + + p0 = (5.001, 10.01) + p1 = (5, 10.0001) + self.assertTrue(is_equal_point(p0, p1, 0.1)) + self.assertTrue(is_equal_point(p0, p1, 0.01)) + self.assertFalse(is_equal_point(p0, p1, 0.001)) + self.assertFalse(is_equal_point(p0, p1)) + self.assertTrue(is_equal_point(p1, p0, 0.1)) + self.assertTrue(is_equal_point(p1, p0, 0.01)) + self.assertFalse(is_equal_point(p1, p0, 0.001)) + self.assertFalse(is_equal_point(p1, p0)) + +if __name__ == '__main__': + unittest.main() -- cgit