summaryrefslogtreecommitdiff
path: root/gerber/gerber_statements.py
diff options
context:
space:
mode:
authorHamilton Kibbe <hamilton.kibbe@gmail.com>2016-11-05 21:11:09 -0400
committerGitHub <noreply@github.com>2016-11-05 21:11:09 -0400
commitd2fe4441662435e55f2dc481bf94a2729b9d6a48 (patch)
treedd60a0b21e1d1ca7258b9f978ce973354d96062c /gerber/gerber_statements.py
parent318a81382e074a5897489299a58e029815d23492 (diff)
parent5af19af190c1fb0f0c5be029d46d63e657dde4d9 (diff)
downloadgerbonara-d2fe4441662435e55f2dc481bf94a2729b9d6a48.tar.gz
gerbonara-d2fe4441662435e55f2dc481bf94a2729b9d6a48.tar.bz2
gerbonara-d2fe4441662435e55f2dc481bf94a2729b9d6a48.zip
Merge pull request #3 from garretfick/merge-curtacircuitos
Merge curtacircuitos
Diffstat (limited to 'gerber/gerber_statements.py')
-rw-r--r--gerber/gerber_statements.py847
1 files changed, 673 insertions, 174 deletions
diff --git a/gerber/gerber_statements.py b/gerber/gerber_statements.py
index 32d3784..33fb4ec 100644
--- a/gerber/gerber_statements.py
+++ b/gerber/gerber_statements.py
@@ -1,19 +1,32 @@
-#! /usr/bin/env python
+#!/usr/bin/env python
# -*- coding: utf-8 -*-
+
+# copyright 2014 Hamilton Kibbe <ham@hamiltonkib.be>
+#
+# 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
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
"""
Gerber (RS-274X) Statements
===========================
**Gerber RS-274X file statement classes**
"""
-from .utils import parse_gerber_value, write_gerber_value, decimal_string
+from .utils import (parse_gerber_value, write_gerber_value, decimal_string,
+ inch, metric)
-
-__all__ = ['FSParamStmt', 'MOParamStmt', 'IPParamStmt', 'OFParamStmt',
- 'LPParamStmt', 'ADParamStmt', 'AMParamStmt', 'INParamStmt',
- 'LNParamStmt', 'CoordStmt', 'ApertureStmt', 'CommentStmt',
- 'EofStmt', 'QuadrantModeStmt', 'RegionModeStmt', 'UnknownStmt',
- 'ParamStmt']
+from .am_statements import *
+from .am_read import read_macro
+from .am_eval import eval_macro
+from .primitives import AMGroup
class Statement(object):
@@ -31,8 +44,10 @@ class Statement(object):
type : string
String identifying the statement type.
"""
- def __init__(self, stype):
+
+ def __init__(self, stype, units='inch'):
self.type = stype
+ self.units = units
def __str__(self):
s = "<{0} ".format(self.__class__.__name__)
@@ -43,6 +58,18 @@ class Statement(object):
s = s.rstrip() + ">"
return s
+ def to_inch(self):
+ self.units = 'inch'
+
+ def to_metric(self):
+ self.units = 'metric'
+
+ def offset(self, x_offset=0, y_offset=0):
+ pass
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
class ParamStmt(Statement):
""" Gerber parameter statement Base class
@@ -59,6 +86,7 @@ class ParamStmt(Statement):
param : string
Parameter type code
"""
+
def __init__(self, param):
Statement.__init__(self, "PARAM")
self.param = param
@@ -67,16 +95,27 @@ class ParamStmt(Statement):
class FSParamStmt(ParamStmt):
""" FS - Gerber Format Specification Statement
"""
+
+ @classmethod
+ def from_settings(cls, settings):
+
+ return cls('FS', settings.zero_suppression, settings.notation, settings.format)
@classmethod
def from_dict(cls, stmt_dict):
"""
"""
param = stmt_dict.get('param')
- zeros = 'leading' if stmt_dict.get('zero') == 'L' else 'trailing'
+
+ if stmt_dict.get('zero') == 'L':
+ zeros = 'leading'
+ elif stmt_dict.get('zero') == 'T':
+ zeros = 'trailing'
+ else:
+ zeros = 'none'
+
notation = 'absolute' if stmt_dict.get('notation') == 'A' else 'incremental'
- x = map(int, stmt_dict.get('x'))
- fmt = (x[0], x[1])
+ fmt = tuple(map(int, stmt_dict.get('x')))
return cls(param, zeros, notation, fmt)
def __init__(self, param, zero_suppression='leading',
@@ -94,7 +133,7 @@ class FSParamStmt(ParamStmt):
Parameter.
zero_suppression : string
- Zero-suppression mode. May be either 'leading' or 'trailing'
+ Zero-suppression mode. May be either 'leading', 'trailing' or 'none' (all zeros are present)
notation : string
Notation mode. May be either 'absolute' or 'incremental'
@@ -114,32 +153,42 @@ class FSParamStmt(ParamStmt):
self.notation = notation
self.format = format
- def to_gerber(self):
- zero_suppression = 'L' if self.zero_suppression == 'leading' else 'T'
- notation = 'A' if self.notation == 'absolute' else 'I'
- fmt = ''.join(map(str, self.format))
- return '%FS{0}{1}X{2}Y{3}*%'.format(zero_suppression, notation,
- fmt, fmt)
+ def to_gerber(self, settings=None):
+ if settings:
+ zero_suppression = 'L' if settings.zero_suppression == 'leading' else 'T'
+ notation = 'A' if settings.notation == 'absolute' else 'I'
+ fmt = ''.join(map(str, settings.format))
+ else:
+ zero_suppression = 'L' if self.zero_suppression == 'leading' else 'T'
+ notation = 'A' if self.notation == 'absolute' else 'I'
+ fmt = ''.join(map(str, self.format))
+
+ return '%FS{0}{1}X{2}Y{3}*%'.format(zero_suppression, notation, fmt, fmt)
def __str__(self):
return ('<Format Spec: %d:%d %s zero suppression %s notation>' %
- (self.format[0], self.format[1], self.zero_suppression,
- self.notation))
+ (self.format[0], self.format[1], self.zero_suppression, self.notation))
class MOParamStmt(ParamStmt):
""" MO - Gerber Mode (measurement units) Statement.
"""
+
+ @classmethod
+ def from_units(cls, units):
+ return cls(None, units)
@classmethod
def from_dict(cls, stmt_dict):
param = stmt_dict.get('param')
- if stmt_dict.get('mo').lower() == 'in':
+ if stmt_dict.get('mo') is None:
+ mo = None
+ elif stmt_dict.get('mo').lower() not in ('in', 'mm'):
+ raise ValueError('Mode may be mm or in')
+ elif stmt_dict.get('mo').lower() == 'in':
mo = 'inch'
- elif stmt_dict.get('mo').lower() == 'mm':
- mo = 'metric'
else:
- mo = None
+ mo = 'metric'
return cls(param, mo)
def __init__(self, param, mo):
@@ -162,102 +211,19 @@ class MOParamStmt(ParamStmt):
ParamStmt.__init__(self, param)
self.mode = mo
- def to_gerber(self):
+ def to_gerber(self, settings=None):
mode = 'MM' if self.mode == 'metric' else 'IN'
return '%MO{0}*%'.format(mode)
- def __str__(self):
- mode_str = 'millimeters' if self.mode == 'metric' else 'inches'
- return ('<Mode: %s>' % mode_str)
-
+ def to_inch(self):
+ self.mode = 'inch'
-class IPParamStmt(ParamStmt):
- """ IP - Gerber Image Polarity Statement. (Deprecated)
- """
- @classmethod
- def from_dict(cls, stmt_dict):
- param = stmt_dict.get('param')
- ip = 'positive' if stmt_dict.get('ip') == 'POS' else 'negative'
- return cls(param, ip)
-
- def __init__(self, param, ip):
- """ Initialize IPParamStmt class
-
- Parameters
- ----------
- param : string
- Parameter string.
-
- ip : string
- Image polarity. May be either'positive' or 'negative'
-
- Returns
- -------
- ParamStmt : IPParamStmt
- Initialized IPParamStmt class.
-
- """
- ParamStmt.__init__(self, param)
- self.ip = ip
-
- def to_gerber(self):
- ip = 'POS' if self.ip == 'positive' else 'NEG'
- return '%IP{0}*%'.format(ip)
+ def to_metric(self):
+ self.mode = 'metric'
def __str__(self):
- return ('<Image Polarity: %s>' % self.ip)
-
-
-class OFParamStmt(ParamStmt):
- """ OF - Gerber Offset statement (Deprecated)
- """
-
- @classmethod
- def from_dict(cls, stmt_dict):
- param = stmt_dict.get('param')
- a = float(stmt_dict.get('a'))
- b = float(stmt_dict.get('b'))
- return cls(param, a, b)
-
- def __init__(self, param, a, b):
- """ Initialize OFParamStmt class
-
- Parameters
- ----------
- param : string
- Parameter
-
- a : float
- Offset along the output device A axis
-
- b : float
- Offset along the output device B axis
-
- Returns
- -------
- ParamStmt : OFParamStmt
- Initialized OFParamStmt class.
-
- """
- ParamStmt.__init__(self, param)
- self.a = a
- self.b = b
-
- def to_gerber(self):
- ret = '%OF'
- if self.a:
- ret += 'A' + decimal_string(self.a, precision=6)
- if self.b:
- ret += 'B' + decimal_string(self.b, precision=6)
- return ret + '*%'
-
- def __str__(self):
- offset_str = ''
- if self.a:
- offset_str += ('X: %f' % self.a)
- if self.b:
- offset_str += ('Y: %f' % self.b)
- return ('<Offset: %s>' % offset_str)
+ mode_str = 'millimeters' if self.mode == 'metric' else 'inches'
+ return ('<Mode: %s>' % mode_str)
class LPParamStmt(ParamStmt):
@@ -269,6 +235,11 @@ class LPParamStmt(ParamStmt):
param = stmt_dict['param']
lp = 'clear' if stmt_dict.get('lp') == 'C' else 'dark'
return cls(param, lp)
+
+ @classmethod
+ def from_region(cls, region):
+ #todo what is the first param?
+ return cls(None, region.level_polarity)
def __init__(self, param, lp):
""" Initialize LPParamStmt class
@@ -290,7 +261,7 @@ class LPParamStmt(ParamStmt):
ParamStmt.__init__(self, param)
self.lp = lp
- def to_gerber(self):
+ def to_gerber(self, settings=None):
lp = 'C' if self.lp == 'clear' else 'D'
return '%LP{0}*%'.format(lp)
@@ -301,7 +272,34 @@ class LPParamStmt(ParamStmt):
class ADParamStmt(ParamStmt):
""" AD - Gerber Aperture Definition Statement
"""
-
+
+ @classmethod
+ def rect(cls, dcode, width, height):
+ '''Create a rectangular aperture definition statement'''
+ return cls('AD', dcode, 'R', ([width, height],))
+
+ @classmethod
+ def circle(cls, dcode, diameter, hole_diameter):
+ '''Create a circular aperture definition statement'''
+
+ if hole_diameter != None:
+ return cls('AD', dcode, 'C', ([diameter, hole_diameter],))
+ return cls('AD', dcode, 'C', ([diameter],))
+
+ @classmethod
+ def obround(cls, dcode, width, height):
+ '''Create an obround aperture definition statement'''
+ return cls('AD', dcode, 'O', ([width, height],))
+
+ @classmethod
+ def polygon(cls, dcode, diameter, num_vertices, rotation, hole_diameter):
+ '''Create a polygon aperture definition statement'''
+ return cls('AD', dcode, 'P', ([diameter, num_vertices, rotation, hole_diameter],))
+
+ @classmethod
+ def macro(cls, dcode, name):
+ return cls('AD', dcode, name, '')
+
@classmethod
def from_dict(cls, stmt_dict):
param = stmt_dict.get('param')
@@ -329,21 +327,38 @@ class ADParamStmt(ParamStmt):
Returns
-------
- ParamStmt : LPParamStmt
- Initialized LPParamStmt class.
+ ParamStmt : ADParamStmt
+ Initialized ADParamStmt class.
"""
ParamStmt.__init__(self, param)
self.d = d
self.shape = shape
- if modifiers is not None:
- self.modifiers = [[x for x in m.split("X")] for m in modifiers.split(",")]
+ if isinstance(modifiers, tuple):
+ self.modifiers = modifiers
+ elif modifiers:
+ self.modifiers = [tuple([float(x) for x in m.split("X") if len(x)])
+ for m in modifiers.split(",") if len(m)]
else:
- self.modifiers = []
-
- def to_gerber(self, settings):
- return '%ADD{0}{1},{2}*%'.format(self.d, self.shape,
- ','.join(['X'.join(e) for e in self.modifiers]))
+ self.modifiers = [tuple()]
+
+ def to_inch(self):
+ if self.units == 'metric':
+ self.units = 'inch'
+ self.modifiers = [tuple([inch(x) for x in modifier])
+ for modifier in self.modifiers]
+
+ def to_metric(self):
+ if self.units == 'inch':
+ self.units = 'metric'
+ self.modifiers = [tuple([metric(x) for x in modifier])
+ for modifier in self.modifiers]
+
+ def to_gerber(self, settings=None):
+ if any(self.modifiers):
+ return '%ADD{0}{1},{2}*%'.format(self.d, self.shape, ','.join(['X'.join(["%.4g" % x for x in modifier]) for modifier in self.modifiers]))
+ else:
+ return '%ADD{0}{1}*%'.format(self.d, self.shape)
def __str__(self):
if self.shape == 'C':
@@ -351,7 +366,7 @@ class ADParamStmt(ParamStmt):
elif self.shape == 'R':
shape = 'rectangle'
elif self.shape == 'O':
- shape = 'oblong'
+ shape = 'obround'
else:
shape = self.shape
@@ -390,15 +405,97 @@ class AMParamStmt(ParamStmt):
self.name = name
self.macro = macro
- def to_gerber(self):
- return '%AM{0}*{1}*%'.format(self.name, self.macro)
+ self.instructions = self.read(macro)
+ self.primitives = []
+
+ def read(self, macro):
+ return read_macro(macro)
+
+ def build(self, modifiers=[[]]):
+ self.primitives = []
+
+ for primitive in eval_macro(self.instructions, modifiers[0]):
+ if primitive[0] == '0':
+ self.primitives.append(AMCommentPrimitive.from_gerber(primitive))
+ elif primitive[0] == '1':
+ self.primitives.append(AMCirclePrimitive.from_gerber(primitive))
+ elif primitive[0:2] in ('2,', '20'):
+ self.primitives.append(AMVectorLinePrimitive.from_gerber(primitive))
+ elif primitive[0:2] == '21':
+ self.primitives.append(AMCenterLinePrimitive.from_gerber(primitive))
+ elif primitive[0:2] == '22':
+ self.primitives.append(AMLowerLeftLinePrimitive.from_gerber(primitive))
+ elif primitive[0] == '4':
+ self.primitives.append(AMOutlinePrimitive.from_gerber(primitive))
+ elif primitive[0] == '5':
+ self.primitives.append(AMPolygonPrimitive.from_gerber(primitive))
+ elif primitive[0] == '6':
+ self.primitives.append(AMMoirePrimitive.from_gerber(primitive))
+ elif primitive[0] == '7':
+ self.primitives.append(
+ AMThermalPrimitive.from_gerber(primitive))
+ else:
+ self.primitives.append(AMUnsupportPrimitive.from_gerber(primitive))
+
+ return AMGroup(self.primitives, stmt=self, units=self.units)
+
+ def to_inch(self):
+ if self.units == 'metric':
+ self.units = 'inch'
+ for primitive in self.primitives:
+ primitive.to_inch()
+
+ def to_metric(self):
+ if self.units == 'inch':
+ self.units = 'metric'
+ for primitive in self.primitives:
+ primitive.to_metric()
+
+ def to_gerber(self, settings=None):
+ return '%AM{0}*{1}%'.format(self.name, "".join([primitive.to_gerber() for primitive in self.primitives]))
def __str__(self):
return '<Aperture Macro %s: %s>' % (self.name, self.macro)
+class ASParamStmt(ParamStmt):
+ """ AS - Axis Select. (Deprecated)
+ """
+ @classmethod
+ def from_dict(cls, stmt_dict):
+ param = stmt_dict.get('param')
+ mode = stmt_dict.get('mode')
+ return cls(param, mode)
+
+ def __init__(self, param, mode):
+ """ Initialize ASParamStmt class
+
+ Parameters
+ ----------
+ param : string
+ Parameter string.
+
+ mode : string
+ Axis select. May be either 'AXBY' or 'AYBX'
+
+ Returns
+ -------
+ ParamStmt : ASParamStmt
+ Initialized ASParamStmt class.
+
+ """
+ ParamStmt.__init__(self, param)
+ self.mode = mode
+
+ def to_gerber(self, settings=None):
+ return '%AS{0}*%'.format(self.mode)
+
+ def __str__(self):
+ return ('<Axis Select: %s>' % self.mode)
+
+
class INParamStmt(ParamStmt):
- """ IN - Image Name Statement
+ """ IN - Image Name Statement (Deprecated)
"""
@classmethod
def from_dict(cls, stmt_dict):
@@ -424,13 +521,280 @@ class INParamStmt(ParamStmt):
ParamStmt.__init__(self, param)
self.name = name
- def to_gerber(self):
+ def to_gerber(self, settings=None):
return '%IN{0}*%'.format(self.name)
def __str__(self):
return '<Image Name: %s>' % self.name
+class IPParamStmt(ParamStmt):
+ """ IP - Gerber Image Polarity Statement. (Deprecated)
+ """
+ @classmethod
+ def from_dict(cls, stmt_dict):
+ param = stmt_dict.get('param')
+ ip = 'positive' if stmt_dict.get('ip') == 'POS' else 'negative'
+ return cls(param, ip)
+
+ def __init__(self, param, ip):
+ """ Initialize IPParamStmt class
+
+ Parameters
+ ----------
+ param : string
+ Parameter string.
+
+ ip : string
+ Image polarity. May be either'positive' or 'negative'
+
+ Returns
+ -------
+ ParamStmt : IPParamStmt
+ Initialized IPParamStmt class.
+
+ """
+ ParamStmt.__init__(self, param)
+ self.ip = ip
+
+ def to_gerber(self, settings=None):
+ ip = 'POS' if self.ip == 'positive' else 'NEG'
+ return '%IP{0}*%'.format(ip)
+
+ def __str__(self):
+ return ('<Image Polarity: %s>' % self.ip)
+
+
+class IRParamStmt(ParamStmt):
+ """ IR - Image Rotation Param (Deprecated)
+ """
+ @classmethod
+ def from_dict(cls, stmt_dict):
+ angle = int(stmt_dict['angle'])
+ return cls(stmt_dict['param'], angle)
+
+ def __init__(self, param, angle):
+ """ Initialize IRParamStmt class
+
+ Parameters
+ ----------
+ param : string
+ Parameter code
+
+ angle : int
+ Image angle
+
+ Returns
+ -------
+ ParamStmt : IRParamStmt
+ Initialized IRParamStmt class.
+
+ """
+ ParamStmt.__init__(self, param)
+ self.angle = angle
+
+ def to_gerber(self, settings=None):
+ return '%IR{0}*%'.format(self.angle)
+
+ def __str__(self):
+ return '<Image Angle: %s>' % self.angle
+
+
+class MIParamStmt(ParamStmt):
+ """ MI - Image Mirror Param (Deprecated)
+ """
+ @classmethod
+ def from_dict(cls, stmt_dict):
+ param = stmt_dict.get('param')
+ a = int(stmt_dict.get('a', 0))
+ b = int(stmt_dict.get('b', 0))
+ return cls(param, a, b)
+
+ def __init__(self, param, a, b):
+ """ Initialize MIParamStmt class
+
+ Parameters
+ ----------
+ param : string
+ Parameter code
+
+ a : int
+ Mirror for A output devices axis (0=disabled, 1=mirrored)
+
+ b : int
+ Mirror for B output devices axis (0=disabled, 1=mirrored)
+
+ Returns
+ -------
+ ParamStmt : MIParamStmt
+ Initialized MIParamStmt class.
+
+ """
+ ParamStmt.__init__(self, param)
+ self.a = a
+ self.b = b
+
+ def to_gerber(self, settings=None):
+ ret = "%MI"
+ if self.a is not None:
+ ret += "A{0}".format(self.a)
+ if self.b is not None:
+ ret += "B{0}".format(self.b)
+ ret += "*%"
+ return ret
+
+ def __str__(self):
+ return '<Image Mirror: A=%d B=%d>' % (self.a, self.b)
+
+
+class OFParamStmt(ParamStmt):
+ """ OF - Gerber Offset statement (Deprecated)
+ """
+
+ @classmethod
+ def from_dict(cls, stmt_dict):
+ param = stmt_dict.get('param')
+ a = float(stmt_dict.get('a', 0))
+ b = float(stmt_dict.get('b', 0))
+ return cls(param, a, b)
+
+ def __init__(self, param, a, b):
+ """ Initialize OFParamStmt class
+
+ Parameters
+ ----------
+ param : string
+ Parameter
+
+ a : float
+ Offset along the output device A axis
+
+ b : float
+ Offset along the output device B axis
+
+ Returns
+ -------
+ ParamStmt : OFParamStmt
+ Initialized OFParamStmt class.
+
+ """
+ ParamStmt.__init__(self, param)
+ self.a = a
+ self.b = b
+
+ def to_gerber(self, settings=None):
+ ret = '%OF'
+ if self.a is not None:
+ ret += 'A' + decimal_string(self.a, precision=5)
+ if self.b is not None:
+ ret += 'B' + decimal_string(self.b, precision=5)
+ return ret + '*%'
+
+ def to_inch(self):
+ if self.units == 'metric':
+ self.units = 'inch'
+ if self.a is not None:
+ self.a = inch(self.a)
+ if self.b is not None:
+ self.b = inch(self.b)
+
+ def to_metric(self):
+ if self.units == 'inch':
+ self.units = 'metric'
+ if self.a is not None:
+ self.a = metric(self.a)
+ 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:
+ offset_str += ('X: %f ' % self.a)
+ if self.b is not None:
+ offset_str += ('Y: %f ' % self.b)
+ return ('<Offset: %s>' % offset_str)
+
+
+class SFParamStmt(ParamStmt):
+ """ SF - Scale Factor Param (Deprecated)
+ """
+
+ @classmethod
+ def from_dict(cls, stmt_dict):
+ param = stmt_dict.get('param')
+ a = float(stmt_dict.get('a', 1))
+ b = float(stmt_dict.get('b', 1))
+ return cls(param, a, b)
+
+ def __init__(self, param, a, b):
+ """ Initialize OFParamStmt class
+
+ Parameters
+ ----------
+ param : string
+ Parameter
+
+ a : float
+ Scale factor for the output device A axis
+
+ b : float
+ Scale factor for the output device B axis
+
+ Returns
+ -------
+ ParamStmt : SFParamStmt
+ Initialized SFParamStmt class.
+
+ """
+ ParamStmt.__init__(self, param)
+ self.a = a
+ self.b = b
+
+ def to_gerber(self, settings=None):
+ ret = '%SF'
+ if self.a is not None:
+ ret += 'A' + decimal_string(self.a, precision=5)
+ if self.b is not None:
+ ret += 'B' + decimal_string(self.b, precision=5)
+ return ret + '*%'
+
+ def to_inch(self):
+ if self.units == 'metric':
+ self.units = 'inch'
+ if self.a is not None:
+ self.a = inch(self.a)
+ if self.b is not None:
+ self.b = inch(self.b)
+
+ def to_metric(self):
+ if self.units == 'inch':
+ self.units = 'metric'
+ if self.a is not None:
+ self.a = metric(self.a)
+ 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:
+ scale_factor += ('X: %g ' % self.a)
+ if self.b is not None:
+ scale_factor += ('Y: %g' % self.b)
+ return ('<Scale Factor: %s>' % scale_factor)
+
+
class LNParamStmt(ParamStmt):
""" LN - Level Name Statement (Deprecated)
"""
@@ -458,21 +822,58 @@ class LNParamStmt(ParamStmt):
ParamStmt.__init__(self, param)
self.name = name
- def to_gerber(self):
+ def to_gerber(self, settings=None):
return '%LN{0}*%'.format(self.name)
def __str__(self):
return '<Level Name: %s>' % self.name
+class DeprecatedStmt(Statement):
+ """ Unimportant deprecated statement, will be parsed but not emitted.
+ """
+ @classmethod
+ def from_gerber(cls, line):
+ return cls(line)
+
+ def __init__(self, line):
+ """ Initialize DeprecatedStmt class
+
+ Parameters
+ ----------
+ line : string
+ Deprecated statement text
+
+ Returns
+ -------
+ DeprecatedStmt
+ Initialized DeprecatedStmt class.
+
+ """
+ Statement.__init__(self, "DEPRECATED")
+ self.line = line
+
+ def to_gerber(self, settings=None):
+ return self.line
+
+ def __str__(self):
+ return '<Deprecated Statement: \'%s\'>' % self.line
+
+
class CoordStmt(Statement):
""" Coordinate Data Block
"""
+ OP_DRAW = 'D01'
+ OP_MOVE = 'D02'
+ OP_FLASH = 'D03'
+
+ FUNC_LINEAR = 'G01'
+ FUNC_ARC_CW = 'G02'
+ FUNC_ARC_CCW = 'G03'
+
@classmethod
def from_dict(cls, stmt_dict, settings):
- zeros = settings.zero_suppression
- format = settings.format
function = stmt_dict['function']
x = stmt_dict.get('x')
y = stmt_dict.get('y')
@@ -481,18 +882,44 @@ class CoordStmt(Statement):
op = stmt_dict.get('op')
if x is not None:
- x = parse_gerber_value(stmt_dict.get('x'),
- format, zeros)
+ x = parse_gerber_value(stmt_dict.get('x'), settings.format,
+ settings.zero_suppression)
if y is not None:
- y = parse_gerber_value(stmt_dict.get('y'),
- format, zeros)
+ y = parse_gerber_value(stmt_dict.get('y'), settings.format,
+ settings.zero_suppression)
if i is not None:
- i = parse_gerber_value(stmt_dict.get('i'),
- format, zeros)
+ i = parse_gerber_value(stmt_dict.get('i'), settings.format,
+ settings.zero_suppression)
if j is not None:
- j = parse_gerber_value(stmt_dict.get('j'),
- format, zeros)
+ j = parse_gerber_value(stmt_dict.get('j'), settings.format,
+ settings.zero_suppression)
return cls(function, x, y, i, j, op, settings)
+
+ @classmethod
+ def move(cls, func, point):
+ if point:
+ return cls(func, point[0], point[1], None, None, CoordStmt.OP_MOVE, None)
+ # No point specified, so just write the function. This is normally for ending a region (D02*)
+ return cls(func, None, None, None, None, CoordStmt.OP_MOVE, None)
+
+ @classmethod
+ def line(cls, func, point):
+ return cls(func, point[0], point[1], None, None, CoordStmt.OP_DRAW, None)
+
+ @classmethod
+ def mode(cls, func):
+ return cls(func, None, None, None, None, None, None)
+
+ @classmethod
+ def arc(cls, func, point, center):
+ return cls(func, point[0], point[1], center[0], center[1], CoordStmt.OP_DRAW, None)
+
+ @classmethod
+ def flash(cls, point):
+ if point:
+ return cls(None, point[0], point[1], None, None, CoordStmt.OP_FLASH, None)
+ else:
+ return cls(None, None, None, None, None, CoordStmt.OP_FLASH, None)
def __init__(self, function, x, y, i, j, op, settings):
""" Initialize CoordStmt class
@@ -527,8 +954,6 @@ class CoordStmt(Statement):
"""
Statement.__init__(self, "COORD")
- self.zero_suppression = settings.zero_suppression
- self.format = settings.format
self.function = function
self.x = x
self.y = y
@@ -536,38 +961,76 @@ class CoordStmt(Statement):
self.j = j
self.op = op
- def to_gerber(self):
+ def to_gerber(self, settings=None):
ret = ''
if self.function:
ret += self.function
- if self.x:
- ret += 'X{0}'.format(write_gerber_value(self.x, self.zeros,
- self.format))
- if self.y:
- ret += 'Y{0}'.format(write_gerber_value(self.y, self. zeros,
- self.format))
- if self.i:
- ret += 'I{0}'.format(write_gerber_value(self.i, self.zeros,
- self.format))
- if self.j:
- ret += 'J{0}'.format(write_gerber_value(self.j, self.zeros,
- self.format))
+ if self.x is not None:
+ ret += 'X{0}'.format(write_gerber_value(self.x, settings.format,
+ settings.zero_suppression))
+ if self.y is not None:
+ ret += 'Y{0}'.format(write_gerber_value(self.y, settings.format,
+ settings.zero_suppression))
+ if self.i is not None:
+ ret += 'I{0}'.format(write_gerber_value(self.i, settings.format,
+ settings.zero_suppression))
+ if self.j is not None:
+ ret += 'J{0}'.format(write_gerber_value(self.j, settings.format,
+ settings.zero_suppression))
if self.op:
ret += self.op
return ret + '*'
+ def to_inch(self):
+ if self.units == 'metric':
+ self.units = 'inch'
+ if self.x is not None:
+ self.x = inch(self.x)
+ if self.y is not None:
+ self.y = inch(self.y)
+ if self.i is not None:
+ self.i = inch(self.i)
+ if self.j is not None:
+ self.j = inch(self.j)
+ if self.function == "G71":
+ self.function = "G70"
+
+ def to_metric(self):
+ if self.units == 'inch':
+ self.units = 'metric'
+ if self.x is not None:
+ self.x = metric(self.x)
+ if self.y is not None:
+ self.y = metric(self.y)
+ if self.i is not None:
+ self.i = metric(self.i)
+ if self.j is not None:
+ self.j = metric(self.j)
+ 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:
coord_str += 'Fn: %s ' % self.function
- if self.x:
- coord_str += 'X: %f ' % self.x
- if self.y:
- coord_str += 'Y: %f ' % self.y
- if self.i:
- coord_str += 'I: %f ' % self.i
- if self.j:
- coord_str += 'J: %f ' % self.j
+ if self.x is not None:
+ coord_str += 'X: %g ' % self.x
+ if self.y is not None:
+ coord_str += 'Y: %g ' % self.y
+ if self.i is not None:
+ coord_str += 'I: %g ' % self.i
+ if self.j is not None:
+ coord_str += 'J: %g ' % self.j
if self.op:
if self.op == 'D01':
op = 'Lights On'
@@ -580,17 +1043,32 @@ class CoordStmt(Statement):
coord_str += 'Op: %s' % op
return '<Coordinate Statement: %s>' % coord_str
+
+ @property
+ def only_function(self):
+ """
+ Returns if the statement only set the function.
+ """
+
+ # TODO I would like to refactor this so that the function is handled separately and then
+ # TODO this isn't required
+ return self.function != None and self.op == None and self.x == None and self.y == None and self.i == None and self.j == None
class ApertureStmt(Statement):
""" Aperture Statement
"""
- def __init__(self, d):
+
+ def __init__(self, d, deprecated=None):
Statement.__init__(self, "APERTURE")
self.d = int(d)
+ self.deprecated = True if deprecated is not None and deprecated is not False else False
- def to_gerber(self):
- return 'G54D{0}*'.format(self.d)
+ def to_gerber(self, settings=None):
+ if self.deprecated:
+ return 'G54D{0}*'.format(self.d)
+ else:
+ return 'D{0}*'.format(self.d)
def __str__(self):
return '<Aperture: %d>' % self.d
@@ -602,9 +1080,9 @@ class CommentStmt(Statement):
def __init__(self, comment):
Statement.__init__(self, "COMMENT")
- self.comment = comment
+ self.comment = comment if comment is not None else ""
- def to_gerber(self):
+ def to_gerber(self, settings=None):
return 'G04{0}*'.format(self.comment)
def __str__(self):
@@ -614,10 +1092,11 @@ class CommentStmt(Statement):
class EofStmt(Statement):
""" EOF Statement
"""
+
def __init__(self):
Statement.__init__(self, "EOF")
- def to_gerber(self):
+ def to_gerber(self, settings=None):
return 'M02*'
def __str__(self):
@@ -625,6 +1104,14 @@ class EofStmt(Statement):
class QuadrantModeStmt(Statement):
+
+ @classmethod
+ def single(cls):
+ return cls('single-quadrant')
+
+ @classmethod
+ def multi(cls):
+ return cls('multi-quadrant')
@classmethod
def from_gerber(cls, line):
@@ -642,7 +1129,7 @@ class QuadrantModeStmt(Statement):
or "multi-quadrant"')
self.mode = mode
- def to_gerber(self):
+ def to_gerber(self, settings=None):
return 'G74*' if self.mode == 'single-quadrant' else 'G75*'
@@ -653,6 +1140,14 @@ class RegionModeStmt(Statement):
if 'G36' not in line and 'G37' not in line:
raise ValueError('%s is not a valid region mode statement' % line)
return (cls('on') if line[:3] == 'G36' else cls('off'))
+
+ @classmethod
+ def on(cls):
+ return cls('on')
+
+ @classmethod
+ def off(cls):
+ return cls('off')
def __init__(self, mode):
super(RegionModeStmt, self).__init__('RegionMode')
@@ -661,16 +1156,20 @@ class RegionModeStmt(Statement):
raise ValueError('Valid modes are "on" or "off"')
self.mode = mode
- def to_gerber(self):
+ def to_gerber(self, settings=None):
return 'G36*' if self.mode == 'on' else 'G37*'
class UnknownStmt(Statement):
""" Unknown Statement
"""
+
def __init__(self, line):
Statement.__init__(self, "UNKNOWN")
self.line = line
- def to_gerber(self):
+ def to_gerber(self, settings=None):
return self.line
+
+ def __str__(self):
+ return '<Unknown Statement: \'%s\'>' % self.line