From 5966d7830bda7f37ed5ddcc1bfccb93e7f780eaa Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Wed, 18 Feb 2015 23:13:23 -0500 Subject: Add offset operation --- gerber/excellon.py | 14 +++ gerber/excellon_statements.py | 15 +++ gerber/gerber_statements.py | 25 +++++ gerber/operations.py | 5 +- gerber/primitives.py | 70 ++++++++++++- gerber/rs274x.py | 6 ++ gerber/tests/test_excellon_statements.py | 56 ++++++++--- gerber/tests/test_gerber_statements.py | 58 ++++++----- gerber/tests/test_primitives.py | 166 +++++++++++++++++++++++++++---- 9 files changed, 348 insertions(+), 67 deletions(-) (limited to 'gerber') diff --git a/gerber/excellon.py b/gerber/excellon.py index ebc307f..900e2df 100755 --- a/gerber/excellon.py +++ b/gerber/excellon.py @@ -28,6 +28,7 @@ import math from .excellon_statements import * from .cam import CamFile, FileSettings from .primitives import Drill +from .utils import inch, metric def read(filename): @@ -134,6 +135,9 @@ class ExcellonFile(CamFile): tool.to_inch() for primitive in self.primitives: primitive.to_inch() + self.hits = [(tool, tuple(map(inch, pos))) + for tool, pos in self.hits] + def to_metric(self): """ Convert units to metric @@ -146,6 +150,16 @@ class ExcellonFile(CamFile): tool.to_metric() for primitive in self.primitives: primitive.to_metric() + self.hits = [(tool, tuple(map(metric, pos))) + for tool, pos in self.hits] + + def offset(self, x_offset=0, y_offset=0): + for statement in self.statements: + statement.offset(x_offset, y_offset) + for primitive in self.primitives: + primitive.offset(x_offset, y_offset) + self.hits = [(tool, (pos[0] + x_offset, pos[1] + y_offset)) + for tool, pos in self.hits] class ExcellonParser(object): diff --git a/gerber/excellon_statements.py b/gerber/excellon_statements.py index 356a96b..83a96a0 100644 --- a/gerber/excellon_statements.py +++ b/gerber/excellon_statements.py @@ -54,6 +54,9 @@ class ExcellonStatement(object): def to_metric(self): pass + def offset(self, x_offset=0, y_offset=0): + pass + def __eq__(self, other): return self.__dict__ == other.__dict__ @@ -294,6 +297,12 @@ class CoordinateStmt(ExcellonStatement): if self.y is not None: self.y = metric(self.y) + def offset(self, x_offset=0, y_offset=0): + if self.x is not None: + self.x += x_offset + if self.y is not None: + self.y += y_offset + def __str__(self): coord_str = '' if self.x is not None: @@ -426,6 +435,12 @@ class EndOfProgramStmt(ExcellonStatement): if self.y is not None: self.y = metric(self.y) + def offset(self, x_offset=0, y_offset=0): + if self.x is not None: + self.x += x_offset + if self.y is not None: + self.y += y_offset + class UnitStmt(ExcellonStatement): @classmethod diff --git a/gerber/gerber_statements.py b/gerber/gerber_statements.py index f8385c0..89f4f84 100644 --- a/gerber/gerber_statements.py +++ b/gerber/gerber_statements.py @@ -58,6 +58,9 @@ class Statement(object): def to_metric(self): pass + def offset(self, x_offset=0, y_offset=0): + pass + def __eq__(self, other): return self.__dict__ == other.__dict__ @@ -626,6 +629,12 @@ class OFParamStmt(ParamStmt): if self.b is not None: self.b = metric(self.b) + def offset(self, x_offset=0, y_offset=0): + if self.a is not None: + self.a += x_offset + if self.b is not None: + self.b += y_offset + def __str__(self): offset_str = '' if self.a is not None: @@ -690,6 +699,12 @@ class SFParamStmt(ParamStmt): if self.b is not None: self.b = metric(self.b) + def offset(self, x_offset=0, y_offset=0): + if self.a is not None: + self.a += x_offset + if self.b is not None: + self.b += y_offset + def __str__(self): scale_factor = '' if self.a is not None: @@ -836,6 +851,16 @@ class CoordStmt(Statement): if self.function == "G70": self.function = "G71" + def offset(self, x_offset=0, y_offset=0): + if self.x is not None: + self.x += x_offset + if self.y is not None: + self.y += y_offset + if self.i is not None: + self.i += x_offset + if self.j is not None: + self.j += y_offset + def __str__(self): coord_str = '' if self.function: diff --git a/gerber/operations.py b/gerber/operations.py index 9624a16..50df738 100644 --- a/gerber/operations.py +++ b/gerber/operations.py @@ -75,8 +75,9 @@ def offset(cam_file, x_offset, y_offset): gerber_file : `gerber.cam.CamFile` subclass An offset deep copy of the source file. """ - # TODO - pass + cam_file = copy.deepcopy(cam_file) + cam_file.offset(x_offset, y_offset) + return cam_file def scale(cam_file, x_scale, y_scale): """ Scale a Cam file by a specified amount in the X and Y directions. diff --git a/gerber/primitives.py b/gerber/primitives.py index cb6e4ea..3469880 100644 --- a/gerber/primitives.py +++ b/gerber/primitives.py @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import math -from operator import sub +from operator import add, sub from .utils import validate_coordinates, inch, metric @@ -50,6 +50,15 @@ class Primitive(object): raise NotImplementedError('Bounding box calculation must be ' 'implemented in subclass') + def to_inch(self): + pass + + def to_metric(self): + pass + + def offset(self, x_offset=0, y_offset=0): + pass + def __eq__(self, other): return self.__dict__ == other.__dict__ @@ -141,6 +150,10 @@ class Line(Primitive): self.start = tuple(map(metric, self.start)) self.end = tuple(map(metric, self.end)) + def offset(self, x_offset=0, y_offset=0): + self.start = tuple(map(add, self.start, (x_offset, y_offset))) + self.end = tuple(map(add, self.end, (x_offset, y_offset))) + class Arc(Primitive): """ @@ -230,6 +243,11 @@ class Arc(Primitive): self.end = tuple(map(metric, self.end)) self.center = tuple(map(metric, self.center)) + def offset(self, x_offset=0, y_offset=0): + self.start = tuple(map(add, self.start, (x_offset, y_offset))) + self.end = tuple(map(add, self.end, (x_offset, y_offset))) + self.center = tuple(map(add, self.center, (x_offset, y_offset))) + class Circle(Primitive): """ @@ -262,6 +280,9 @@ class Circle(Primitive): self.position = tuple(map(metric, self.position)) self.diameter = metric(self.diameter) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class Ellipse(Primitive): """ @@ -288,6 +309,19 @@ class Ellipse(Primitive): max_y = self.position[1] + (self._abs_height / 2.0) return ((min_x, max_x), (min_y, max_y)) + def to_inch(self): + self.position = tuple(map(inch, self.position)) + self.width = inch(self.width) + self.height = inch(self.height) + + def to_metric(self): + self.position = tuple(map(metric, self.position)) + self.width = metric(self.width) + self.height = metric(self.height) + + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class Rectangle(Primitive): """ @@ -332,6 +366,9 @@ class Rectangle(Primitive): self.width = metric(self.width) self.height = metric(self.height) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class Diamond(Primitive): """ @@ -376,6 +413,9 @@ class Diamond(Primitive): self.width = metric(self.width) self.height = metric(self.height) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class ChamferRectangle(Primitive): """ @@ -424,6 +464,9 @@ class ChamferRectangle(Primitive): self.height = metric(self.height) self.chamfer = metric(self.chamfer) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class RoundRectangle(Primitive): """ @@ -472,6 +515,9 @@ class RoundRectangle(Primitive): self.height = metric(self.height) self.radius = metric(self.radius) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class Obround(Primitive): """ @@ -538,6 +584,9 @@ class Obround(Primitive): self.width = metric(self.width) self.height = metric(self.height) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class Polygon(Primitive): """ @@ -565,6 +614,9 @@ class Polygon(Primitive): self.position = tuple(map(metric, self.position)) self.radius = metric(self.radius) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class Region(Primitive): """ @@ -588,6 +640,10 @@ class Region(Primitive): def to_metric(self): self.points = [tuple(map(metric, point)) for point in self.points] + def offset(self, x_offset=0, y_offset=0): + self.points = [tuple(map(add, point, (x_offset, y_offset))) + for point in self.points] + class RoundButterfly(Primitive): """ A circle with two diagonally-opposite quadrants removed @@ -618,6 +674,9 @@ class RoundButterfly(Primitive): self.position = tuple(map(metric, self.position)) self.diameter = metric(self.diameter) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class SquareButterfly(Primitive): """ A square with two diagonally-opposite quadrants removed @@ -645,6 +704,9 @@ class SquareButterfly(Primitive): self.position = tuple(map(metric, self.position)) self.side = metric(self.side) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class Donut(Primitive): """ A Shape with an identical concentric shape removed from its center @@ -702,6 +764,9 @@ class Donut(Primitive): self.inner_diameter = metric(self.inner_diameter) self.outer_diaemter = metric(self.outer_diameter) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + class Drill(Primitive): """ A drill hole @@ -733,3 +798,6 @@ class Drill(Primitive): self.position = tuple(map(metric, self.position)) self.diameter = metric(self.diameter) + def offset(self, x_offset=0, y_offset=0): + self.position = tuple(map(add, self.position, (x_offset, y_offset))) + diff --git a/gerber/rs274x.py b/gerber/rs274x.py index 21947e1..2dee7cf 100644 --- a/gerber/rs274x.py +++ b/gerber/rs274x.py @@ -129,6 +129,12 @@ class GerberFile(CamFile): for primitive in self.primitives: primitive.to_metric() + def offset(self, x_offset=0, y_offset=0): + for statement in self.statements: + statement.offset(x_offset, y_offset) + for primitive in self.primitives: + primitive.offset(x_offset, y_offset) + class GerberParser(object): """ GerberParser diff --git a/gerber/tests/test_excellon_statements.py b/gerber/tests/test_excellon_statements.py index 4daeb4b..eb30db1 100644 --- a/gerber/tests/test_excellon_statements.py +++ b/gerber/tests/test_excellon_statements.py @@ -12,6 +12,14 @@ def test_excellon_statement_implementation(): assert_raises(NotImplementedError, stmt.from_excellon, None) assert_raises(NotImplementedError, stmt.to_excellon) +def test_excellontstmt(): + """ Smoke test ExcellonStatement + """ + stmt = ExcellonStatement() + stmt.to_inch() + stmt.to_metric() + stmt.offset() + def test_excellontool_factory(): """ Test ExcellonTool factory methods """ @@ -26,7 +34,7 @@ def test_excellontool_factory(): 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) @@ -93,6 +101,7 @@ def test_excellontool_equality(): assert_equal(t, t1) t1 = ExcellonTool.from_dict(FileSettings(units='metric'), {'number': 8, 'diameter': 0.125}) assert_not_equal(t, t1) + def test_toolselection_factory(): """ Test ToolSelectionStmt factory method """ @@ -103,7 +112,6 @@ def test_toolselection_factory(): assert_equal(stmt.tool, 2) assert_equal(stmt.compensation_index, 23) - def test_toolselection_dump(): """ Test ToolSelectionStmt to_excellon() """ @@ -112,7 +120,6 @@ def test_toolselection_dump(): stmt = ToolSelectionStmt.from_excellon(line) assert_equal(stmt.to_excellon(), line) - def test_coordinatestmt_factory(): """ Test CoordinateStmt factory method """ @@ -163,6 +170,19 @@ def test_coordinatestmt_conversion(): assert_equal(stmt.x, 25.4) assert_equal(stmt.y, 25.4) +def test_coordinatestmt_offset(): + stmt = CoordinateStmt.from_excellon('X01Y01', FileSettings()) + stmt.offset() + assert_equal(stmt.x, 1) + assert_equal(stmt.y, 1) + stmt.offset(1,0) + assert_equal(stmt.x, 2.) + assert_equal(stmt.y, 1.) + stmt.offset(0,1) + assert_equal(stmt.x, 2.) + assert_equal(stmt.y, 2.) + + def test_coordinatestmt_string(): settings = FileSettings(format=(2, 4), zero_suppression='leading', units='inch', notation='absolute') @@ -229,7 +249,7 @@ def test_header_begin_stmt(): 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), '%') @@ -262,6 +282,18 @@ def test_endofprogramstmt_conversion(): assert_equal(stmt.x, 25.4) assert_equal(stmt.y, 254.) +def test_endofprogramstmt_offset(): + stmt = EndOfProgramStmt(1, 1) + stmt.offset() + assert_equal(stmt.x, 1) + assert_equal(stmt.y, 1) + stmt.offset(1,0) + assert_equal(stmt.x, 2.) + assert_equal(stmt.y, 1.) + stmt.offset(0,1) + assert_equal(stmt.x, 2.) + assert_equal(stmt.y, 2.) + def test_unitstmt_factory(): """ Test UnitStmt factory method """ @@ -447,28 +479,20 @@ def test_measmodestmt_conversion(): 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), '') - + def test_unknownstmt_dump(): stmt = UnknownStmt('TEST') assert_equal(stmt.to_excellon(FileSettings()), 'TEST') - - -def test_excellontstmt(): - """ Smoke test ExcellonStatement - """ - stmt = ExcellonStatement() - stmt.to_inch() - stmt.to_metric() \ No newline at end of file diff --git a/gerber/tests/test_gerber_statements.py b/gerber/tests/test_gerber_statements.py index b473cf9..04358eb 100644 --- a/gerber/tests/test_gerber_statements.py +++ b/gerber/tests/test_gerber_statements.py @@ -12,6 +12,7 @@ def test_Statement_smoketest(): assert_equal(stmt.type, 'Test') stmt.to_inch() stmt.to_metric() + stmt.offset(1, 1) assert_equal(str(stmt), '') def test_FSParamStmt_factory(): @@ -31,7 +32,6 @@ def test_FSParamStmt_factory(): assert_equal(fs.notation, 'incremental') assert_equal(fs.format, (2, 7)) - def test_FSParamStmt(): """ Test FSParamStmt initialization """ @@ -45,7 +45,6 @@ def test_FSParamStmt(): assert_equal(stmt.notation, notation) assert_equal(stmt.format, fmt) - def test_FSParamStmt_dump(): """ Test FSParamStmt to_gerber() """ @@ -60,7 +59,6 @@ def test_FSParamStmt_dump(): settings = FileSettings(zero_suppression='leading', notation='absolute') assert_equal(fs.to_gerber(settings), '%FSLAX25Y25*%') - def test_FSParamStmt_string(): """ Test FSParamStmt.__str__() """ @@ -72,7 +70,6 @@ def test_FSParamStmt_string(): fs = FSParamStmt.from_dict(stmt) assert_equal(str(fs), '') - def test_MOParamStmt_factory(): """ Test MOParamStruct factory """ @@ -94,7 +91,6 @@ def test_MOParamStmt_factory(): stmt = {'param': 'MO', 'mo': 'degrees kelvin'} assert_raises(ValueError, MOParamStmt.from_dict, stmt) - def test_MOParamStmt(): """ Test MOParamStmt initialization """ @@ -107,7 +103,6 @@ def test_MOParamStmt(): stmt = MOParamStmt(param, mode) assert_equal(stmt.mode, mode) - def test_MOParamStmt_dump(): """ Test MOParamStmt to_gerber() """ @@ -119,7 +114,6 @@ def test_MOParamStmt_dump(): mo = MOParamStmt.from_dict(stmt) assert_equal(mo.to_gerber(), '%MOMM*%') - def test_MOParamStmt_conversion(): stmt = {'param': 'MO', 'mo': 'MM'} mo = MOParamStmt.from_dict(stmt) @@ -142,7 +136,6 @@ def test_MOParamStmt_string(): mo = MOParamStmt.from_dict(stmt) assert_equal(str(mo), '') - def test_IPParamStmt_factory(): """ Test IPParamStruct factory """ @@ -154,7 +147,6 @@ def test_IPParamStmt_factory(): ip = IPParamStmt.from_dict(stmt) assert_equal(ip.ip, 'negative') - def test_IPParamStmt(): """ Test IPParamStmt initialization """ @@ -164,7 +156,6 @@ def test_IPParamStmt(): assert_equal(stmt.param, param) assert_equal(stmt.ip, ip) - def test_IPParamStmt_dump(): """ Test IPParamStmt to_gerber() """ @@ -201,7 +192,6 @@ def test_IRParamStmt_string(): ir = IRParamStmt.from_dict(stmt) assert_equal(str(ir), '') - def test_OFParamStmt_factory(): """ Test OFParamStmt factory """ @@ -210,7 +200,6 @@ def test_OFParamStmt_factory(): assert_equal(of.a, 0.1234567) assert_equal(of.b, 0.1234567) - def test_OFParamStmt(): """ Test IPParamStmt initialization """ @@ -221,7 +210,6 @@ def test_OFParamStmt(): assert_equal(stmt.a, val) assert_equal(stmt.b, val) - def test_OFParamStmt_dump(): """ Test OFParamStmt to_gerber() """ @@ -229,7 +217,6 @@ def test_OFParamStmt_dump(): of = OFParamStmt.from_dict(stmt) assert_equal(of.to_gerber(), '%OFA0.12345B0.12345*%') - def test_OFParamStmt_conversion(): stmt = {'param': 'OF', 'a': '2.54', 'b': '25.4'} of = OFParamStmt.from_dict(stmt) @@ -243,6 +230,14 @@ def test_OFParamStmt_conversion(): assert_equal(of.a, 2.54) assert_equal(of.b, 25.4) +def test_OFParamStmt_offset(): + s = OFParamStmt('OF', 0, 0) + s.offset(1, 0) + assert_equal(s.a, 1.) + assert_equal(s.b, 0.) + s.offset(0, 1) + assert_equal(s.a, 1.) + assert_equal(s.b, 1.) def test_OFParamStmt_string(): """ Test OFParamStmt __str__ @@ -276,12 +271,20 @@ def test_SFParamStmt_conversion(): assert_equal(of.a, 2.54) assert_equal(of.b, 25.4) +def test_SFParamStmt_offset(): + s = SFParamStmt('OF', 0, 0) + s.offset(1, 0) + assert_equal(s.a, 1.) + assert_equal(s.b, 0.) + s.offset(0, 1) + assert_equal(s.a, 1.) + assert_equal(s.b, 1.) + def test_SFParamStmt_string(): stmt = {'param': 'SF', 'a': '1.4', 'b': '0.9'} sf = SFParamStmt.from_dict(stmt) assert_equal(str(sf), '') - def test_LPParamStmt_factory(): """ Test LPParamStmt factory """ @@ -293,7 +296,6 @@ def test_LPParamStmt_factory(): lp = LPParamStmt.from_dict(stmt) assert_equal(lp.lp, 'dark') - def test_LPParamStmt_dump(): """ Test LPParamStmt to_gerber() """ @@ -305,7 +307,6 @@ def test_LPParamStmt_dump(): lp = LPParamStmt.from_dict(stmt) assert_equal(lp.to_gerber(), '%LPD*%') - def test_LPParamStmt_string(): """ Test LPParamStmt.__str__() """ @@ -317,7 +318,6 @@ def test_LPParamStmt_string(): lp = LPParamStmt.from_dict(stmt) assert_equal(str(lp), '') - def test_AMParamStmt_factory(): name = 'DONUTVAR' macro = ( @@ -469,7 +469,6 @@ def test_quadmodestmt_factory(): stmt = QuadrantModeStmt.from_gerber(line) assert_equal(stmt.mode, 'multi-quadrant') - def test_quadmodestmt_validation(): """ Test QuadrantModeStmt input validation """ @@ -477,7 +476,6 @@ def test_quadmodestmt_validation(): assert_raises(ValueError, QuadrantModeStmt.from_gerber, line) assert_raises(ValueError, QuadrantModeStmt, 'quadrant-ful') - def test_quadmodestmt_dump(): """ Test QuadrantModeStmt.to_gerber() """ @@ -485,7 +483,6 @@ def test_quadmodestmt_dump(): stmt = QuadrantModeStmt.from_gerber(line) assert_equal(stmt.to_gerber(), line) - def test_regionmodestmt_factory(): """ Test RegionModeStmt.from_gerber() """ @@ -498,7 +495,6 @@ def test_regionmodestmt_factory(): stmt = RegionModeStmt.from_gerber(line) assert_equal(stmt.mode, 'off') - def test_regionmodestmt_validation(): """ Test RegionModeStmt input validation """ @@ -506,7 +502,6 @@ def test_regionmodestmt_validation(): assert_raises(ValueError, RegionModeStmt.from_gerber, line) assert_raises(ValueError, RegionModeStmt, 'off-ish') - def test_regionmodestmt_dump(): """ Test RegionModeStmt.to_gerber() """ @@ -514,7 +509,6 @@ def test_regionmodestmt_dump(): stmt = RegionModeStmt.from_gerber(line) assert_equal(stmt.to_gerber(), line) - def test_unknownstmt(): """ Test UnknownStmt """ @@ -523,7 +517,6 @@ def test_unknownstmt(): assert_equal(stmt.type, 'UNKNOWN') assert_equal(stmt.line, line) - def test_unknownstmt_dump(): """ Test UnknownStmt.to_gerber() """ @@ -532,7 +525,6 @@ def test_unknownstmt_dump(): stmt = UnknownStmt(line) assert_equal(stmt.to_gerber(), line) - def test_statement_string(): """ Test Statement.__str__() """ @@ -542,7 +534,6 @@ def test_statement_string(): assert_true('test=PASS' in str(stmt)) assert_true('type=PARAM' in str(stmt)) - def test_ADParamStmt_factory(): """ Test ADParamStmt factory """ @@ -664,6 +655,19 @@ def test_coordstmt_conversion(): assert_equal(cs.j, 25.4) assert_equal(cs.function, 'G71') +def test_coordstmt_offset(): + c = CoordStmt('G71', 0, 0, 0, 0, 'D01', FileSettings()) + c.offset(1, 0) + assert_equal(c.x, 1.) + assert_equal(c.y, 0.) + assert_equal(c.i, 1.) + assert_equal(c.j, 0.) + c.offset(0, 1) + assert_equal(c.x, 1.) + assert_equal(c.y, 1.) + assert_equal(c.i, 1.) + assert_equal(c.j, 1.) + def test_coordstmt_string(): cs = CoordStmt('G04', 0, 1, 2, 3, 'D01', FileSettings()) assert_equal(str(cs), '') diff --git a/gerber/tests/test_primitives.py b/gerber/tests/test_primitives.py index dab0225..2909d8f 100644 --- a/gerber/tests/test_primitives.py +++ b/gerber/tests/test_primitives.py @@ -6,10 +6,12 @@ from ..primitives import * from .tests import * -def test_primitive_implementation_warning(): +def test_primitive_smoketest(): p = Primitive() assert_raises(NotImplementedError, p.bounding_box) - + p.to_metric() + p.to_inch() + p.offset(1, 1) def test_line_angle(): """ Test Line primitive angle calculation @@ -103,6 +105,15 @@ def test_line_conversion(): assert_equal(l.aperture.width, 25.4) assert_equal(l.aperture.height, 254.0) +def test_line_offset(): + c = Circle((0, 0), 1) + l = Line((0, 0), (1, 1), c) + l.offset(1, 0) + assert_equal(l.start,(1., 0.)) + assert_equal(l.end, (2., 1.)) + l.offset(0, 1) + assert_equal(l.start,(1., 1.)) + assert_equal(l.end, (2., 2.)) def test_arc_radius(): """ Test Arc primitive radius calculation @@ -114,7 +125,6 @@ def test_arc_radius(): a = Arc(start, end, center, 'clockwise', 0) assert_equal(a.radius, radius) - def test_arc_sweep_angle(): """ Test Arc primitive sweep angle calculation """ @@ -157,7 +167,17 @@ def test_arc_conversion(): assert_equal(a.center, (25400.0, 254000.0)) assert_equal(a.aperture.diameter, 25.4) - +def test_arc_offset(): + c = Circle((0, 0), 1) + a = Arc((0, 0), (1, 1), (2, 2), 'clockwise', c) + a.offset(1, 0) + assert_equal(a.start,(1., 0.)) + assert_equal(a.end, (2., 1.)) + assert_equal(a.center, (3., 2.)) + a.offset(0, 1) + assert_equal(a.start,(1., 1.)) + assert_equal(a.end, (2., 2.)) + assert_equal(a.center, (3., 3.)) def test_circle_radius(): """ Test Circle primitive radius calculation @@ -165,13 +185,28 @@ def test_circle_radius(): c = Circle((1, 1), 2) assert_equal(c.radius, 1) - def test_circle_bounds(): """ Test Circle bounding box calculation """ c = Circle((1, 1), 2) assert_equal(c.bounding_box, ((0, 2), (0, 2))) +def test_circle_conversion(): + c = Circle((2.54, 25.4), 254.0) + c.to_inch() + assert_equal(c.position, (0.1, 1.)) + assert_equal(c.diameter, 10.) + c = Circle((0.1, 1.0), 10.0) + c.to_metric() + assert_equal(c.position, (2.54, 25.4)) + assert_equal(c.diameter, 254.) + +def test_circle_offset(): + c = Circle((0, 0), 1) + c.offset(1, 0) + assert_equal(c.position,(1., 0.)) + c.offset(0, 1) + assert_equal(c.position,(1., 1.)) def test_ellipse_ctor(): """ Test ellipse creation @@ -181,7 +216,6 @@ def test_ellipse_ctor(): assert_equal(e.width, 3) assert_equal(e.height, 2) - def test_ellipse_bounds(): """ Test ellipse bounding box calculation """ @@ -194,6 +228,26 @@ def test_ellipse_bounds(): e = Ellipse((2, 2), 4, 2, rotation=270) assert_equal(e.bounding_box, ((1, 3), (0, 4))) +def test_ellipse_conversion(): + e = Ellipse((2.54, 25.4), 254.0, 2540.) + e.to_inch() + assert_equal(e.position, (0.1, 1.)) + assert_equal(e.width, 10.) + assert_equal(e.height, 100.) + + e = Ellipse((0.1, 1.), 10.0, 100.) + e.to_metric() + assert_equal(e.position, (2.54, 25.4)) + assert_equal(e.width, 254.) + assert_equal(e.height, 2540.) + +def test_ellipse_offset(): + e = Ellipse((0, 0), 1, 2) + e.offset(1, 0) + assert_equal(e.position,(1., 0.)) + e.offset(0, 1) + assert_equal(e.position,(1., 1.)) + def test_rectangle_ctor(): """ Test rectangle creation """ @@ -216,6 +270,25 @@ def test_rectangle_bounds(): assert_array_almost_equal(xbounds, (-math.sqrt(2), math.sqrt(2))) assert_array_almost_equal(ybounds, (-math.sqrt(2), math.sqrt(2))) +def test_rectangle_conversion(): + r = Rectangle((2.54, 25.4), 254.0, 2540.0) + r.to_inch() + assert_equal(r.position, (0.1, 1.0)) + assert_equal(r.width, 10.0) + assert_equal(r.height, 100.0) + r = Rectangle((0.1, 1.0), 10.0, 100.0) + r.to_metric() + assert_equal(r.position, (2.54,25.4)) + assert_equal(r.width, 254.0) + assert_equal(r.height, 2540.0) + +def test_rectangle_offset(): + r = Rectangle((0, 0), 1, 2) + r.offset(1, 0) + assert_equal(r.position,(1., 0.)) + r.offset(0, 1) + assert_equal(r.position,(1., 1.)) + def test_diamond_ctor(): """ Test diamond creation """ @@ -251,6 +324,12 @@ def test_diamond_conversion(): assert_equal(d.width, 254.0) assert_equal(d.height, 2540.0) +def test_diamond_offset(): + d = Diamond((0, 0), 1, 2) + d.offset(1, 0) + assert_equal(d.position,(1., 0.)) + d.offset(0, 1) + assert_equal(d.position,(1., 1.)) def test_chamfer_rectangle_ctor(): """ Test chamfer rectangle creation @@ -266,7 +345,6 @@ def test_chamfer_rectangle_ctor(): assert_equal(r.chamfer, chamfer) assert_array_almost_equal(r.corners, corners) - def test_chamfer_rectangle_bounds(): """ Test chamfer rectangle bounding box calculation """ @@ -279,7 +357,6 @@ def test_chamfer_rectangle_bounds(): assert_array_almost_equal(xbounds, (-math.sqrt(2), math.sqrt(2))) assert_array_almost_equal(ybounds, (-math.sqrt(2), math.sqrt(2))) - def test_chamfer_rectangle_conversion(): r = ChamferRectangle((2.54, 25.4), 254.0, 2540.0, 0.254, (True, True, False, False)) r.to_inch() @@ -295,6 +372,13 @@ def test_chamfer_rectangle_conversion(): assert_equal(r.height, 2540.0) assert_equal(r.chamfer, 0.254) +def test_chamfer_rectangle_offset(): + r = ChamferRectangle((0, 0), 1, 2, 0.01, (True, True, False, False)) + r.offset(1, 0) + assert_equal(r.position,(1., 0.)) + r.offset(0, 1) + assert_equal(r.position,(1., 1.)) + def test_round_rectangle_ctor(): """ Test round rectangle creation """ @@ -309,7 +393,6 @@ def test_round_rectangle_ctor(): assert_equal(r.radius, radius) assert_array_almost_equal(r.corners, corners) - def test_round_rectangle_bounds(): """ Test round rectangle bounding box calculation """ @@ -322,7 +405,6 @@ def test_round_rectangle_bounds(): assert_array_almost_equal(xbounds, (-math.sqrt(2), math.sqrt(2))) assert_array_almost_equal(ybounds, (-math.sqrt(2), math.sqrt(2))) - def test_round_rectangle_conversion(): r = RoundRectangle((2.54, 25.4), 254.0, 2540.0, 0.254, (True, True, False, False)) r.to_inch() @@ -338,6 +420,13 @@ def test_round_rectangle_conversion(): assert_equal(r.height, 2540.0) assert_equal(r.radius, 0.254) +def test_round_rectangle_offset(): + r = RoundRectangle((0, 0), 1, 2, 0.01, (True, True, False, False)) + r.offset(1, 0) + assert_equal(r.position,(1., 0.)) + r.offset(0, 1) + assert_equal(r.position,(1., 1.)) + def test_obround_ctor(): """ Test obround creation """ @@ -350,7 +439,6 @@ def test_obround_ctor(): assert_equal(o.width, width) assert_equal(o.height, height) - def test_obround_bounds(): """ Test obround bounding box calculation """ @@ -363,14 +451,12 @@ def test_obround_bounds(): assert_array_almost_equal(xbounds, (0, 4)) assert_array_almost_equal(ybounds, (1, 3)) - def test_obround_orientation(): o = Obround((0, 0), 2, 1) assert_equal(o.orientation, 'horizontal') o = Obround((0, 0), 1, 2) assert_equal(o.orientation, 'vertical') - def test_obround_subshapes(): o = Obround((0,0), 1, 4) ss = o.subshapes @@ -383,7 +469,6 @@ def test_obround_subshapes(): assert_array_almost_equal(ss['circle1'].position, (1.5, 0)) assert_array_almost_equal(ss['circle2'].position, (-1.5, 0)) - def test_obround_conversion(): o = Obround((2.54,25.4), 254.0, 2540.0) o.to_inch() @@ -397,6 +482,12 @@ def test_obround_conversion(): assert_equal(o.width, 254.0) assert_equal(o.height, 2540.0) +def test_obround_offset(): + o = Obround((0, 0), 1, 2) + o.offset(1, 0) + assert_equal(o.position,(1., 0.)) + o.offset(0, 1) + assert_equal(o.position,(1., 1.)) def test_polygon_ctor(): """ Test polygon creation @@ -422,7 +513,6 @@ def test_polygon_bounds(): assert_array_almost_equal(xbounds, (-2, 6)) assert_array_almost_equal(ybounds, (-2, 6)) - def test_polygon_conversion(): p = Polygon((2.54, 25.4), 3, 254.0) p.to_inch() @@ -434,6 +524,12 @@ def test_polygon_conversion(): assert_equal(p.position, (2.54, 25.4)) assert_equal(p.radius, 254.0) +def test_polygon_offset(): + p = Polygon((0, 0), 5, 10) + p.offset(1, 0) + assert_equal(p.position,(1., 0.)) + p.offset(0, 1) + assert_equal(p.position,(1., 1.)) def test_region_ctor(): """ Test Region creation @@ -443,7 +539,6 @@ def test_region_ctor(): for i, point in enumerate(points): assert_array_almost_equal(r.points[i], point) - def test_region_bounds(): """ Test region bounding box calculation """ @@ -464,7 +559,13 @@ def test_region_conversion(): r.to_metric() assert_equal(set(r.points), {(2.54, 25.4), (254.0, 2540.0), (25400.0, 254000.0)}) - +def test_region_offset(): + points = ((0, 0), (1,0), (1,1), (0,1)) + r = Region(points) + r.offset(1, 0) + assert_equal(set(r.points), {(1, 0), (2, 0), (2,1), (1, 1)}) + r.offset(0, 1) + assert_equal(set(r.points), {(1, 1), (2, 1), (2,2), (1, 2)}) def test_round_butterfly_ctor(): """ Test round butterfly creation @@ -482,7 +583,6 @@ def test_round_butterfly_ctor_validation(): assert_raises(TypeError, RoundButterfly, 3, 5) assert_raises(TypeError, RoundButterfly, (3,4,5), 5) - def test_round_butterfly_conversion(): b = RoundButterfly((2.54, 25.4), 254.0) b.to_inch() @@ -494,6 +594,13 @@ def test_round_butterfly_conversion(): assert_equal(b.position, (2.54, 25.4)) assert_equal(b.diameter, (254.0)) +def test_round_butterfly_offset(): + b = RoundButterfly((0, 0), 1) + b.offset(1, 0) + assert_equal(b.position,(1., 0.)) + b.offset(0, 1) + assert_equal(b.position,(1., 1.)) + def test_round_butterfly_bounds(): """ Test RoundButterfly bounding box calculation """ @@ -517,7 +624,6 @@ def test_square_butterfly_ctor_validation(): assert_raises(TypeError, SquareButterfly, 3, 5) assert_raises(TypeError, SquareButterfly, (3,4,5), 5) - def test_square_butterfly_bounds(): """ Test SquareButterfly bounding box calculation """ @@ -537,6 +643,13 @@ def test_squarebutterfly_conversion(): assert_equal(b.position, (2.54, 25.4)) assert_equal(b.side, (254.0)) +def test_square_butterfly_offset(): + b = SquareButterfly((0, 0), 1) + b.offset(1, 0) + assert_equal(b.position,(1., 0.)) + b.offset(0, 1) + assert_equal(b.position,(1., 1.)) + def test_donut_ctor(): """ Test Donut primitive creation """ @@ -576,6 +689,12 @@ def test_donut_conversion(): assert_equal(d.inner_diameter, 254.0) assert_equal(d.outer_diaemter, 2540.0) +def test_donut_offset(): + d = Donut((0, 0), 'round', 1, 10) + d.offset(1, 0) + assert_equal(d.position,(1., 0.)) + d.offset(0, 1) + assert_equal(d.position,(1., 1.)) def test_drill_ctor(): """ Test drill primitive creation @@ -587,14 +706,12 @@ def test_drill_ctor(): assert_equal(d.diameter, diameter) assert_equal(d.radius, diameter/2.) - def test_drill_ctor_validation(): """ Test drill argument validation """ assert_raises(TypeError, Drill, 3, 5) assert_raises(TypeError, Drill, (3,4,5), 5) - def test_drill_bounds(): d = Drill((0, 0), 2) xbounds, ybounds = d.bounding_box @@ -616,6 +733,13 @@ def test_drill_conversion(): assert_equal(d.position, (2.54, 25.4)) assert_equal(d.diameter, 254.0) +def test_drill_offset(): + d = Drill((0, 0), 1.) + d.offset(1, 0) + assert_equal(d.position,(1., 0.)) + d.offset(0, 1) + assert_equal(d.position,(1., 1.)) + def test_drill_equality(): d = Drill((2.54, 25.4), 254.) d1 = Drill((2.54, 25.4), 254.) -- cgit