From b495d51354eff7b858dbbd41740865eba7f39100 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Sun, 25 Jan 2015 14:19:48 -0500 Subject: Changed zeros/zero suppression conventions to match file format specs --- gerber/cam.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 6 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 051c3b5..a4057bc 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -27,9 +27,34 @@ class FileSettings(object): """ CAM File Settings Provides a common representation of gerber/excellon file settings + + Parameters + ---------- + notation: string + notation format. either 'absolute' or 'incremental' + + units : string + Measurement units. 'inch' or 'metric' + + zero_suppression: string + 'leading' to suppress leading zeros, 'trailing' to suppress trailing zeros. + This is the convention used in Gerber files. + + format : tuple (int, int) + Decimal format + + zeros : string + 'leading' to include leading zeros, 'trailing to include trailing zeros. + This is the convention used in Excellon files + + Notes + ----- + Either `zeros` or `zero_suppression` should be specified, there is no need to + specify both. `zero_suppression` will take on the opposite value of `zeros` + and vice versa """ def __init__(self, notation='absolute', units='inch', - zero_suppression='trailing', format=(2, 5)): + zero_suppression=None, format=(2, 5), zeros=None): if notation not in ['absolute', 'incremental']: raise ValueError('Notation must be either absolute or incremental') self.notation = notation @@ -38,15 +63,52 @@ class FileSettings(object): raise ValueError('Units must be either inch or metric') self.units = units - if zero_suppression not in ['leading', 'trailing']: - raise ValueError('Zero suppression must be either leading or \ - trailling') - self.zero_suppression = zero_suppression + + if zero_suppression is None and zeros is None: + self.zero_suppression = 'trailing' + + elif zero_suppression == zeros: + raise ValueError('Zeros and Zero Suppression must be different. \ + Best practice is to specify only one.') + + elif zero_suppression is not None: + if zero_suppression not in ['leading', 'trailing']: + raise ValueError('Zero suppression must be either leading or \ + trailling') + self.zero_suppression = zero_suppression + + + elif zeros is not None: + if zeros not in ['leading', 'trailing']: + raise ValueError('Zeros must be either leading or trailling') + self.zeros = zeros + else: + self.zeros = 'leading' + if len(format) != 2: raise ValueError('Format must be a tuple(n=2) of integers') self.format = format + @property + def zero_suppression(self): + return self._zero_suppression + + @zero_suppression.setter + def zero_suppression(self, value): + self._zero_suppression = value + self._zeros = 'leading' if value == 'trailing' else 'trailing' + + @property + def zeros(self): + return self._zeros + + @zeros.setter + def zeros(self, value): + + self._zeros = value + self._zero_suppression = 'leading' if value == 'trailing' else 'trailing' + def __getitem__(self, key): if key == 'notation': return self.notation @@ -54,6 +116,8 @@ class FileSettings(object): return self.units elif key == 'zero_suppression': return self.zero_suppression + elif key == 'zeros': + return self.zeros elif key == 'format': return self.format else: @@ -69,11 +133,18 @@ class FileSettings(object): if value not in ['inch', 'metric']: raise ValueError('Units must be either inch or metric') self.units = value + elif key == 'zero_suppression': if value not in ['leading', 'trailing']: raise ValueError('Zero suppression must be either leading or \ trailling') self.zero_suppression = value + + elif key == 'zeros': + if value not in ['leading', 'trailing']: + raise ValueError('Zeros must be either leading or trailling') + self.zeros = value + elif key == 'format': if len(value) != 2: raise ValueError('Format must be a tuple(n=2) of integers') @@ -86,7 +157,6 @@ class FileSettings(object): self.format == other.format) - class CamFile(object): """ Base class for Gerber/Excellon files. @@ -131,11 +201,13 @@ class CamFile(object): self.notation = settings['notation'] self.units = settings['units'] self.zero_suppression = settings['zero_suppression'] + self.zeros = settings['zeros'] self.format = settings['format'] else: self.notation = 'absolute' self.units = 'inch' self.zero_suppression = 'trailing' + self.zeros = 'leading' self.format = (2, 5) self.statements = statements if statements is not None else [] self.primitives = primitives -- cgit From d98d23f8b5d61bb9d20e743a3c44bf04b6b2330a Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Mon, 2 Feb 2015 00:43:08 -0500 Subject: More tests and bugfixes --- gerber/cam.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index a4057bc..9c731aa 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -62,29 +62,24 @@ class FileSettings(object): if units not in ['inch', 'metric']: raise ValueError('Units must be either inch or metric') self.units = units - - + if zero_suppression is None and zeros is None: self.zero_suppression = 'trailing' - + elif zero_suppression == zeros: raise ValueError('Zeros and Zero Suppression must be different. \ Best practice is to specify only one.') - + elif zero_suppression is not None: if zero_suppression not in ['leading', 'trailing']: raise ValueError('Zero suppression must be either leading or \ trailling') self.zero_suppression = zero_suppression - elif zeros is not None: if zeros not in ['leading', 'trailing']: raise ValueError('Zeros must be either leading or trailling') self.zeros = zeros - else: - self.zeros = 'leading' - if len(format) != 2: raise ValueError('Format must be a tuple(n=2) of integers') @@ -150,6 +145,9 @@ class FileSettings(object): raise ValueError('Format must be a tuple(n=2) of integers') self.format = value + else: + raise KeyError('%s is not a valid key' % key) + def __eq__(self, other): return (self.notation == other.notation and self.units == other.units and @@ -230,7 +228,7 @@ class CamFile(object): def bounds(self): """ File baundaries """ - pass + raise NotImplementedError('bounds must be implemented in a subclass') def render(self, ctx, filename=None): """ Generate image of layer. -- cgit From 5e23d07bcb5103b4607c6ad591a2a547c97ee1f6 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Fri, 13 Feb 2015 09:37:27 -0500 Subject: Fix rendering for line with rectangular aperture per #12. Still need to do the same for arcs. --- gerber/cam.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 9c731aa..f49f5dd 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -21,7 +21,7 @@ CAM File This module provides common base classes for Excellon/Gerber CNC files """ - +from operator import mul class FileSettings(object): """ CAM File Settings @@ -241,7 +241,8 @@ class CamFile(object): filename : string If provided, save the rendered image to `filename` """ - ctx.set_bounds(self.bounds) + bounds = [tuple([x * 1.2, y*1.2]) for x, y in self.bounds] + ctx.set_bounds(bounds) for p in self.primitives: ctx.render(p) if filename is not None: -- cgit From 5cf1fa74b42eb8feaab23078bef6f31f6d647c33 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Sun, 15 Feb 2015 02:20:02 -0500 Subject: Tests and bugfixes --- gerber/cam.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index f49f5dd..caca517 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -21,7 +21,6 @@ CAM File This module provides common base classes for Excellon/Gerber CNC files """ -from operator import mul class FileSettings(object): """ CAM File Settings @@ -62,14 +61,14 @@ class FileSettings(object): if units not in ['inch', 'metric']: raise ValueError('Units must be either inch or metric') self.units = units - + if zero_suppression is None and zeros is None: self.zero_suppression = 'trailing' - + elif zero_suppression == zeros: raise ValueError('Zeros and Zero Suppression must be different. \ Best practice is to specify only one.') - + elif zero_suppression is not None: if zero_suppression not in ['leading', 'trailing']: raise ValueError('Zero suppression must be either leading or \ -- cgit From 288ac27084b47166ac662402ea340d0aa25d8f56 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Wed, 18 Feb 2015 04:31:23 -0500 Subject: Get unit conversion working for Gerber/Excellon files Started operations module for file operations/transforms --- gerber/cam.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index caca517..243070d 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -225,9 +225,9 @@ class CamFile(object): @property def bounds(self): - """ File baundaries + """ File boundaries """ - raise NotImplementedError('bounds must be implemented in a subclass') + pass def render(self, ctx, filename=None): """ Generate image of layer. -- cgit From b3e0ceb5c3ec755b09d2f005b8e3dcbed22d45a1 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Fri, 20 Feb 2015 22:24:34 -0500 Subject: Add IPC-D-356 Netlist Parsing --- gerber/cam.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 243070d..31b6d2f 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -53,7 +53,8 @@ class FileSettings(object): and vice versa """ def __init__(self, notation='absolute', units='inch', - zero_suppression=None, format=(2, 5), zeros=None): + zero_suppression=None, format=(2, 5), zeros=None, + angle_units='degrees'): if notation not in ['absolute', 'incremental']: raise ValueError('Notation must be either absolute or incremental') self.notation = notation @@ -84,6 +85,10 @@ class FileSettings(object): raise ValueError('Format must be a tuple(n=2) of integers') self.format = format + if angle_units not in ('degrees', 'radians'): + raise ValueError('Angle units may be degrees or radians') + self.angle_units = angle_units + @property def zero_suppression(self): return self._zero_suppression @@ -114,6 +119,8 @@ class FileSettings(object): return self.zeros elif key == 'format': return self.format + elif key == 'angle_units': + return self.angle_units else: raise KeyError() @@ -144,6 +151,11 @@ class FileSettings(object): raise ValueError('Format must be a tuple(n=2) of integers') self.format = value + elif key == 'angle_units': + if value not in ('degrees', 'radians'): + raise ValueError('Angle units may be degrees or radians') + self.angle_units = value + else: raise KeyError('%s is not a valid key' % key) @@ -151,7 +163,8 @@ class FileSettings(object): return (self.notation == other.notation and self.units == other.units and self.zero_suppression == other.zero_suppression and - self.format == other.format) + self.format == other.format and + self.angle_units == other.angle_units) class CamFile(object): -- cgit From 94f3976915d64a77135a1fdc8983085ee8d2e1f9 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Thu, 11 Jun 2015 11:20:56 -0400 Subject: Add keys to statements for linking to primitives. Add some API features to ExcellonFile, such as getting a tool path length and changing tool parameters. Excellonfiles write method generates statements based on the drill hits in the hits member, so drill hits in a generated file can be re-ordered by re-ordering the drill hits in ExcellonFile.hits. see #30 --- gerber/cam.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 31b6d2f..23d8214 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -220,7 +220,8 @@ class CamFile(object): self.zeros = 'leading' self.format = (2, 5) self.statements = statements if statements is not None else [] - self.primitives = primitives + if primitives is not None: + self.primitives = primitives self.filename = filename self.layer_name = layer_name -- cgit From 5aaf18889c3cdc31ae61b9593bf5848bc57ec09a Mon Sep 17 00:00:00 2001 From: Paulo Henrique Silva Date: Thu, 9 Jul 2015 03:54:47 -0300 Subject: Initial patch to unify our render towards cairo This branch allows a pure cairo based render for both PNG and SVG. Cairo backend is mostly the same but with improved support for configurable scale, orientation and inverted color drawing. API is not yet final. --- gerber/cam.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 31b6d2f..91ffb9a 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -253,8 +253,9 @@ class CamFile(object): filename : string If provided, save the rendered image to `filename` """ - bounds = [tuple([x * 1.2, y*1.2]) for x, y in self.bounds] - ctx.set_bounds(bounds) + if ctx.invert: + ctx._paint_inverted_layer() + for p in self.primitives: ctx.render(p) if filename is not None: -- cgit From b3f6ec558ca35a19bd60440f2a114eb98c0a4263 Mon Sep 17 00:00:00 2001 From: Paulo Henrique Silva Date: Thu, 9 Jul 2015 04:05:15 -0300 Subject: Fix arcs and ackground painting --- gerber/cam.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 91ffb9a..804e366 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -253,9 +253,11 @@ class CamFile(object): filename : string If provided, save the rendered image to `filename` """ + ctx._paint_background() + if ctx.invert: ctx._paint_inverted_layer() - + for p in self.primitives: ctx.render(p) if filename is not None: -- cgit From 39726e3936c5fa5c50158727e8eb7f5d01cb1b49 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Wed, 22 Jul 2015 22:13:09 -0400 Subject: Fix multiple layer issue in cairo-unification branch (see #33) --- gerber/cam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 804e366..0a68b23 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -253,8 +253,8 @@ class CamFile(object): filename : string If provided, save the rendered image to `filename` """ + ctx.set_bounds(self.bounds) ctx._paint_background() - if ctx.invert: ctx._paint_inverted_layer() -- cgit From 1cb269131bc52f0b1a1e69cef0466f2d994d52a8 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Sat, 19 Dec 2015 21:54:29 -0500 Subject: Allow negative render of soldermask per #50 Update example code and rendering to show change --- gerber/cam.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index c567055..cf06ec9 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -243,7 +243,7 @@ class CamFile(object): """ pass - def render(self, ctx, filename=None): + def render(self, ctx, invert=False, filename=None): """ Generate image of layer. Parameters @@ -256,10 +256,14 @@ class CamFile(object): """ ctx.set_bounds(self.bounds) ctx._paint_background() - if ctx.invert: + if invert: + ctx.invert = True ctx._paint_inverted_layer() - for p in self.primitives: ctx.render(p) + if invert: + ctx.invert = False + ctx._render_mask() + if filename is not None: ctx.dump(filename) -- cgit From af5541ac93b222c05229ee05c9def8dbae5f6e25 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Sun, 20 Dec 2015 23:54:20 -0500 Subject: Allow renderer to write to memory per #38 Some updates to rendering colors/themes --- gerber/cam.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index cf06ec9..92ce83d 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -256,9 +256,10 @@ class CamFile(object): """ ctx.set_bounds(self.bounds) ctx._paint_background() + if invert: ctx.invert = True - ctx._paint_inverted_layer() + ctx._clear_mask() for p in self.primitives: ctx.render(p) if invert: -- cgit From 3fce700ef289d16053b0f60cccdfd4d5956daf5c Mon Sep 17 00:00:00 2001 From: Garret Fick Date: Mon, 15 Feb 2016 23:53:52 +0800 Subject: Don't throw an exception for missing zero suppress, even though it is wrong --- gerber/cam.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index c567055..08d80de 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -72,9 +72,10 @@ class FileSettings(object): elif zero_suppression is not None: if zero_suppression not in ['leading', 'trailing']: - raise ValueError('Zero suppression must be either leading or \ - trailling') - self.zero_suppression = zero_suppression + # This is a common problem in Eagle files, so just suppress it + self.zero_suppression = 'leading' + else: + self.zero_suppression = zero_suppression elif zeros is not None: if zeros not in ['leading', 'trailing']: -- cgit From 223a010831f0d9dae4bd6d2e626a603a78eb0b1d Mon Sep 17 00:00:00 2001 From: Garret Fick Date: Sat, 27 Feb 2016 18:18:04 +0800 Subject: Fix critical issue with rotatin points (when the angle is zero the y would be flipped). Render AM with outline to gerber --- gerber/cam.py | 1 + 1 file changed, 1 insertion(+) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 08d80de..53f5c0d 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -255,6 +255,7 @@ class CamFile(object): filename : string If provided, save the rendered image to `filename` """ + ctx.set_bounds(self.bounds) ctx._paint_background() if ctx.invert: -- cgit From 20a9af279ac2217a39b73903ff94b916a3025be2 Mon Sep 17 00:00:00 2001 From: Garret Fick Date: Tue, 1 Mar 2016 00:06:14 +0800 Subject: More rendering of AMGroup to statements --- gerber/cam.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 53f5c0d..8e31bf0 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -166,6 +166,10 @@ class FileSettings(object): self.zero_suppression == other.zero_suppression and self.format == other.format and self.angle_units == other.angle_units) + + def __str__(self): + return ('' % + (self.units, self.notation, self.zero_suppression, self.format, self.angle_units)) class CamFile(object): -- cgit From 7cd6acf12670f3773113f67ed2acb35cb21c32a0 Mon Sep 17 00:00:00 2001 From: Garret Fick Date: Sun, 24 Jul 2016 17:08:47 +0800 Subject: Add many render tests based on the Umaco gerger specification. Fix multiple rendering bugs, especially related to holes in flashed apertures --- gerber/cam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 28918cb..f64aa34 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -260,7 +260,7 @@ class CamFile(object): If provided, save the rendered image to `filename` """ - ctx.set_bounds(self.bounds) + ctx.set_bounds(self.bounding_box) ctx._paint_background() if invert: -- cgit From 8cd842a41a55ab3d8f558a2e3e198beba7da58a1 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Thu, 21 Jan 2016 03:57:44 -0500 Subject: Manually mere rendering changes --- gerber/cam.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index f64aa34..0e19b05 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -22,6 +22,7 @@ CAM File This module provides common base classes for Excellon/Gerber CNC files """ + class FileSettings(object): """ CAM File Settings @@ -52,6 +53,7 @@ class FileSettings(object): specify both. `zero_suppression` will take on the opposite value of `zeros` and vice versa """ + def __init__(self, notation='absolute', units='inch', zero_suppression=None, format=(2, 5), zeros=None, angle_units='degrees'): @@ -248,6 +250,12 @@ class CamFile(object): """ pass + def to_inch(self): + pass + + def to_metric(self): + pass + def render(self, ctx, invert=False, filename=None): """ Generate image of layer. @@ -262,15 +270,11 @@ class CamFile(object): ctx.set_bounds(self.bounding_box) ctx._paint_background() - - if invert: - ctx.invert = True - ctx._clear_mask() + ctx.invert = invert + ctx._new_render_layer() for p in self.primitives: ctx.render(p) - if invert: - ctx.invert = False - ctx._render_mask() + ctx._flatten() if filename is not None: ctx.dump(filename) -- cgit From 5af19af190c1fb0f0c5be029d46d63e657dde4d9 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Thu, 21 Jan 2016 03:57:44 -0500 Subject: Commit partial merge so I can work on the plane --- gerber/cam.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gerber/cam.py') diff --git a/gerber/cam.py b/gerber/cam.py index 0e19b05..c5b8938 100644 --- a/gerber/cam.py +++ b/gerber/cam.py @@ -267,8 +267,7 @@ class CamFile(object): filename : string If provided, save the rendered image to `filename` """ - - ctx.set_bounds(self.bounding_box) + ctx.set_bounds(self.bounds) ctx._paint_background() ctx.invert = invert ctx._new_render_layer() -- cgit