improve compatibility with RS-274x specification:
- can merge multiple files having different file scope modifier, such as AS, MI, OF, SF, and IR - support modal coordinate notation
This commit is contained in:
parent
13ab9db6e7
commit
2b1c751ff7
19 changed files with 266 additions and 132 deletions
|
|
@ -8,7 +8,7 @@ pcb-tools-extension adds following function to pcb-tools.
|
|||
- Rotate PCB data
|
||||
- Write back loaded PCB data (original pcb-tools does not work in some condition)
|
||||
- Merge multiple PCB data
|
||||
- Translate DXF file to gerber data
|
||||
- Translate DXF file to PCB data
|
||||
|
||||
Only RS-274x format and Excellon drill format data can be handled by current version of this library.
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ def loads(data, filename=None, format=None):
|
|||
|
||||
fmt = detect_file_format(data)
|
||||
if fmt == 'rs274x':
|
||||
file = gerber.rs274x.loads(data, filename=filename)
|
||||
file = gerberex.rs274x.loads(data, filename=filename)
|
||||
return gerberex.rs274x.GerberFile.from_gerber_file(file)
|
||||
elif fmt == 'excellon':
|
||||
return gerberex.excellon.loads(data, filename=filename, format=format)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ class GerberComposition(Composition):
|
|||
|
||||
def __init__(self, settings=None, comments=None):
|
||||
super(GerberComposition, self).__init__(settings, comments)
|
||||
self.param_statements = []
|
||||
self.aperture_macros = {}
|
||||
self.apertures = []
|
||||
self.drawings = []
|
||||
|
|
@ -37,8 +36,6 @@ class GerberComposition(Composition):
|
|||
|
||||
def dump(self, path):
|
||||
def statements():
|
||||
for s in self.param_statements:
|
||||
yield s
|
||||
for k in self.aperture_macros:
|
||||
yield self.aperture_macros[k]
|
||||
for s in self.apertures:
|
||||
|
|
@ -46,12 +43,14 @@ class GerberComposition(Composition):
|
|||
for s in self.drawings:
|
||||
yield s
|
||||
yield EofStmt()
|
||||
self.settings.notation = 'absolute'
|
||||
self.settings.zeros = 'trailing'
|
||||
with open(path, 'w') as f:
|
||||
gerberex.rs274x.write_gerber_header(f, self.settings)
|
||||
for statement in statements():
|
||||
f.write(statement.to_gerber(self.settings) + '\n')
|
||||
|
||||
def _merge_gerber(self, file):
|
||||
param_statements = []
|
||||
aperture_macro_map = {}
|
||||
aperture_map = {}
|
||||
|
||||
|
|
@ -61,34 +60,27 @@ class GerberComposition(Composition):
|
|||
else:
|
||||
file.to_inch()
|
||||
|
||||
for statement in file.statements:
|
||||
if statement.type == 'COMMENT':
|
||||
self.comments.append(statement.comment)
|
||||
elif statement.type == 'PARAM':
|
||||
if statement.param == 'AM':
|
||||
name = statement.name
|
||||
newname = self._register_aperture_macro(statement)
|
||||
aperture_macro_map[name] = newname
|
||||
elif statement.param == 'AD':
|
||||
if not statement.shape in ['C', 'R', 'O']:
|
||||
statement.shape = aperture_macro_map[statement.shape]
|
||||
dnum = statement.d
|
||||
newdnum = self._register_aperture(statement)
|
||||
aperture_map[dnum] = newdnum
|
||||
elif statement.param == 'LP':
|
||||
self.drawings.append(statement)
|
||||
else:
|
||||
param_statements.append(statement)
|
||||
elif statement.type in ['EOF', "DEPRECATED"]:
|
||||
pass
|
||||
else:
|
||||
if statement.type == 'APERTURE':
|
||||
statement.d = aperture_map[statement.d]
|
||||
self.drawings.append(statement)
|
||||
for macro in file.aperture_macros:
|
||||
statement = file.aperture_macros[macro]
|
||||
name = statement.name
|
||||
newname = self._register_aperture_macro(statement)
|
||||
aperture_macro_map[name] = newname
|
||||
|
||||
for statement in file.aperture_defs:
|
||||
if statement.param == 'AD':
|
||||
if statement.shape in aperture_macro_map:
|
||||
statement.shape = aperture_macro_map[statement.shape]
|
||||
dnum = statement.d
|
||||
newdnum = self._register_aperture(statement)
|
||||
aperture_map[dnum] = newdnum
|
||||
|
||||
for statement in file.main_statements:
|
||||
if statement.type == 'APERTURE':
|
||||
statement.d = aperture_map[statement.d]
|
||||
self.drawings.append(statement)
|
||||
|
||||
if not self.settings:
|
||||
self.settings = file.settings
|
||||
self.param_statements = param_statements
|
||||
self.settings = file.context
|
||||
|
||||
def _merge_dxf(self, file):
|
||||
if self.settings:
|
||||
|
|
@ -102,7 +94,6 @@ class GerberComposition(Composition):
|
|||
|
||||
if not self.settings:
|
||||
self.settings = file.settings
|
||||
self.param_statements = [file.header]
|
||||
|
||||
|
||||
def _register_aperture_macro(self, statement):
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from gerber.excellon_statements import CoordinateStmt
|
|||
from gerberex.utility import is_equal_point, is_equal_value
|
||||
from gerberex.dxf_path import generate_closed_paths
|
||||
from gerberex.excellon import write_excellon_header
|
||||
from gerberex.rs274x import write_gerber_header
|
||||
|
||||
ACCEPTABLE_ERROR = 0.001
|
||||
|
||||
|
|
@ -395,6 +396,8 @@ class DxfStatements(object):
|
|||
|
||||
def to_gerber(self, settings=FileSettings()):
|
||||
def gerbers():
|
||||
yield 'G75*'
|
||||
yield '%LPD*%'
|
||||
yield 'D{0}*'.format(self.dcode)
|
||||
if self.draw_mode == DxfFile.DM_FILL:
|
||||
yield 'G36*'
|
||||
|
|
@ -451,29 +454,6 @@ class DxfStatements(object):
|
|||
for statement in self.statements:
|
||||
statement.rotate(angle, center)
|
||||
|
||||
class DxfHeaderStatement(object):
|
||||
def to_gerber(self, settings):
|
||||
return 'G75*\n'\
|
||||
'%MO{0}*%\n'\
|
||||
'%OFA0B0*%\n'\
|
||||
'%FS{1}AX{2}{3}Y{4}{5}*%\n'\
|
||||
'%IPPOS*%\n'\
|
||||
'%LPD*%'.format(
|
||||
'IN' if settings.units == 'inch' else 'MM',
|
||||
'L' if settings.zero_suppression == 'leading' else 'T',
|
||||
settings.format[0], settings.format[1],
|
||||
settings.format[0], settings.format[1]
|
||||
)
|
||||
|
||||
def to_excellon(self, settings):
|
||||
pass
|
||||
|
||||
def to_inch(self):
|
||||
pass
|
||||
|
||||
def to_metric(self):
|
||||
pass
|
||||
|
||||
class DxfFile(CamFile):
|
||||
DM_LINE = 0
|
||||
DM_FILL = 1
|
||||
|
|
@ -531,7 +511,6 @@ class DxfFile(CamFile):
|
|||
|
||||
super(DxfFile, self).__init__(settings=settings, filename=filename)
|
||||
self._draw_mode = draw_mode
|
||||
self.header = DxfHeaderStatement()
|
||||
|
||||
self.aperture = ADParamStmt.circle(dcode=10, diameter=0.0)
|
||||
self.statements = DxfStatements(
|
||||
|
|
@ -579,7 +558,7 @@ class DxfFile(CamFile):
|
|||
filename = filename if filename is not None else self.filename
|
||||
with open(filename, 'w') as f:
|
||||
if filetype == self.FT_RX274X:
|
||||
f.write(self.header.to_gerber(self.settings) + '\n')
|
||||
write_gerber_header(f, self.settings)
|
||||
f.write(self.aperture.to_gerber(self.settings) + '\n')
|
||||
f.write(self.statements.to_gerber(self.settings) + '\n')
|
||||
f.write('M02*\n')
|
||||
|
|
@ -593,7 +572,6 @@ class DxfFile(CamFile):
|
|||
|
||||
def to_inch(self):
|
||||
if self.units == 'metric':
|
||||
self.header.to_inch()
|
||||
self.aperture.to_inch()
|
||||
self.statements.to_inch()
|
||||
self.pitch = inch(self.pitch)
|
||||
|
|
@ -601,7 +579,6 @@ class DxfFile(CamFile):
|
|||
|
||||
def to_metric(self):
|
||||
if self.units == 'inch':
|
||||
self.header.to_metric()
|
||||
self.aperture.to_metric()
|
||||
self.statements.to_metric()
|
||||
self.pitch = metric(self.pitch)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ def loads(data, filename=None, settings=None, tools=None, format=None):
|
|||
return ExcellonFileEx.from_file(file)
|
||||
|
||||
def write_excellon_header(file, settings, tools):
|
||||
file.write('M48\nFMAT,2\nICI,OFF\n%s\n' %
|
||||
file.write('M48\nFMAT,2\nICI,OFF\n%s\n' %
|
||||
UnitStmtEx(settings.units, settings.zeros, settings.format).to_excellon(settings))
|
||||
for tool in tools:
|
||||
file.write(tool.to_excellon(settings) + '\n')
|
||||
|
|
|
|||
|
|
@ -3,10 +3,29 @@
|
|||
|
||||
# Copyright 2019 Hiroshi Murayama <opiopan@gmail.com>
|
||||
|
||||
from gerber.cam import FileSettings
|
||||
import gerber.rs274x
|
||||
from gerber.gerber_statements import ADParamStmt, CoordStmt
|
||||
from gerber.gerber_statements import *
|
||||
from gerberex.gerber_statements import AMParamStmt, AMParamStmtEx, ADParamStmtEx
|
||||
from gerberex.utility import rotate
|
||||
import re
|
||||
|
||||
def loads(data, filename=None):
|
||||
cls = gerber.rs274x.GerberParser
|
||||
cls.SF = \
|
||||
r"(?P<param>SF)(A(?P<a>{decimal}))?(B(?P<b>{decimal}))?".format(decimal=cls.DECIMAL)
|
||||
cls.PARAMS = (cls.FS, cls.MO, cls.LP, cls.AD_CIRCLE,
|
||||
cls.AD_RECT, cls.AD_OBROUND, cls.AD_POLY,
|
||||
cls.AD_MACRO, cls.AM, cls.AS, cls.IF, cls.IN,
|
||||
cls.IP, cls.IR, cls.MI, cls.OF, cls.SF, cls.LN)
|
||||
cls.PARAM_STMT = [re.compile(r"%?{0}\*%?".format(p)) for p in cls.PARAMS]
|
||||
return cls().parse_raw(data, filename)
|
||||
|
||||
def write_gerber_header(file, settings):
|
||||
file.write('%s\n%s\n%%IPPOS*%%\n' % (
|
||||
MOParamStmt('MO', settings.units).to_gerber(settings),
|
||||
FSParamStmt('FS', settings.zero_suppression,
|
||||
settings.notation, settings.format).to_gerber(settings)))
|
||||
|
||||
class GerberFile(gerber.rs274x.GerberFile):
|
||||
@classmethod
|
||||
|
|
@ -14,29 +33,74 @@ class GerberFile(gerber.rs274x.GerberFile):
|
|||
if not isinstance(gerber_file, gerber.rs274x.GerberFile):
|
||||
raise Exception('only gerber.rs274x.GerberFile object is specified')
|
||||
|
||||
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]
|
||||
return cls(statements, gerber_file.settings, gerber_file.primitives,\
|
||||
return cls(gerber_file.statements, gerber_file.settings, gerber_file.primitives,\
|
||||
gerber_file.apertures, gerber_file.filename)
|
||||
|
||||
def __init__(self, statements, settings, primitives, apertures, filename=None):
|
||||
super(GerberFile, self).__init__(statements, settings, primitives, apertures, filename)
|
||||
self.context = GerberContext.from_settings(self.settings)
|
||||
self.aperture_macros = {}
|
||||
self.aperture_defs = []
|
||||
self.main_statements = []
|
||||
for stmt in self.statements:
|
||||
type, stmts = self.context.normalize_statement(stmt)
|
||||
if type == self.context.TYPE_AM:
|
||||
for mdef in stmts:
|
||||
self.aperture_macros[mdef.name] = mdef
|
||||
elif type == self.context.TYPE_AD:
|
||||
self.aperture_defs.extend(stmts)
|
||||
elif type == self.context.TYPE_MAIN:
|
||||
self.main_statements.extend(stmts)
|
||||
if self.context.angle != 0:
|
||||
self.rotate(self.context.angle)
|
||||
self.context.notation = 'absolute'
|
||||
self.context.zeros = 'trailing'
|
||||
|
||||
def write(self, filename=None):
|
||||
self.context.notation = 'absolute'
|
||||
self.context.zeros = 'trailing'
|
||||
self.context.format = self.format
|
||||
self.units = self.units
|
||||
filename=filename if filename is not None else self.filename
|
||||
with open(filename, 'w') as f:
|
||||
write_gerber_header(f, self.context)
|
||||
for macro in self.aperture_macros:
|
||||
f.write(self.aperture_macros[macro].to_gerber(self.context) + '\n')
|
||||
for aperture in self.aperture_defs:
|
||||
f.write(aperture.to_gerber(self.context) + '\n')
|
||||
for statement in self.main_statements:
|
||||
f.write(statement.to_gerber(self.context) + '\n')
|
||||
f.write('M02*\n')
|
||||
|
||||
def to_inch(self):
|
||||
if self.units == 'metric':
|
||||
for macro in self.aperture_macros:
|
||||
self.aperture_macros[macro].to_inch()
|
||||
for aperture in self.aperture_defs:
|
||||
aperture.to_inch()
|
||||
for statement in self.statements:
|
||||
statement.to_inch()
|
||||
self.units = 'inch'
|
||||
self.context.units = 'inch'
|
||||
|
||||
def to_metric(self):
|
||||
if self.units == 'inch':
|
||||
for macro in self.aperture_macros:
|
||||
self.aperture_macros[macro].to_metric()
|
||||
for aperture in self.aperture_defs:
|
||||
aperture.to_metric()
|
||||
for statement in self.statements:
|
||||
statement.to_metric()
|
||||
self.units='metric'
|
||||
self.context.units='metric'
|
||||
|
||||
def offset(self, x_offset=0, y_offset=0):
|
||||
for statement in self.statements:
|
||||
for statement in self.main_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)
|
||||
|
||||
|
|
@ -48,10 +112,10 @@ class GerberFile(gerber.rs274x.GerberFile):
|
|||
last_y = 0
|
||||
last_rx = 0
|
||||
last_ry = 0
|
||||
for statement in self.statements:
|
||||
if isinstance(statement, AMParamStmtEx):
|
||||
statement.rotate(angle, center)
|
||||
elif isinstance(statement, CoordStmt) and statement.x != None and statement.y != None:
|
||||
for name in self.aperture_macros:
|
||||
self.aperture_macros[name].rotate(angle, center)
|
||||
for statement in self.main_statements:
|
||||
if isinstance(statement, CoordStmt) and statement.x != None and statement.y != None:
|
||||
if statement.i != None and statement.j != None:
|
||||
cx = last_x + statement.i
|
||||
cy = last_y + statement.j
|
||||
|
|
@ -77,31 +141,21 @@ class GerberFile(gerber.rs274x.GerberFile):
|
|||
]
|
||||
|
||||
need_to_change = False
|
||||
insert_point = 0
|
||||
last_aperture = 0
|
||||
macros = {}
|
||||
for idx in range(0, len(self.statements)):
|
||||
statement = self.statements[idx]
|
||||
if isinstance(statement, AMParamStmtEx):
|
||||
macros[statement.name] = statement
|
||||
if not need_to_change:
|
||||
insert_point = idx + 1
|
||||
for statement in self.aperture_defs:
|
||||
if isinstance(statement, ADParamStmt) and statement.shape in ['R', 'O', 'P']:
|
||||
need_to_change = True
|
||||
last_aperture = idx
|
||||
|
||||
if need_to_change:
|
||||
for idx in range(0, len(macro_defs)):
|
||||
macro_def = macro_defs[idx]
|
||||
name = macro_def[0]
|
||||
num = 1
|
||||
while name in macros:
|
||||
while name in self.aperture_macros:
|
||||
name = '%s_%d' % (macro_def[0], num)
|
||||
num += 1
|
||||
self.statements.insert(insert_point, macro_def[1](name, self.units))
|
||||
self.aperture_macros[name] = 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]
|
||||
for statement in self.aperture_defs:
|
||||
if isinstance(statement, ADParamStmt):
|
||||
if statement.shape == 'R':
|
||||
statement.shape = macro_defs[RECTANGLE][0]
|
||||
|
|
@ -114,3 +168,128 @@ class GerberFile(gerber.rs274x.GerberFile):
|
|||
if x > y else macro_defs[PORTRATE_OBROUND][0]
|
||||
elif statement.shape == 'P':
|
||||
statement.shape = macro_defs[POLYGON][0]
|
||||
|
||||
class GerberContext(FileSettings):
|
||||
TYPE_NONE = 'none'
|
||||
TYPE_AM = 'am'
|
||||
TYPE_AD = 'ad'
|
||||
TYPE_MAIN = 'main'
|
||||
IP_LINEAR = 'lenear'
|
||||
IP_ARC = 'arc'
|
||||
DIR_CLOCKWISE = 'cw'
|
||||
DIR_COUNTERCLOCKWISE = 'ccw'
|
||||
|
||||
ignored_stmt = ('FSParamStmt', 'MOParamStmt', 'ASParamStmt',
|
||||
'INParamStmt', 'IPParamStmt', 'IRParamStmt',
|
||||
'MIParamStmt', 'OFParamStmt', 'SFParamStmt',
|
||||
'LNParamStmt', 'CommentStmt', 'EofStmt',)
|
||||
|
||||
@classmethod
|
||||
def from_settings(cls, settings):
|
||||
return cls(settings.notation, settings.units, settings.zero_suppression,
|
||||
settings.format, settings.zeros, settings.angle_units)
|
||||
|
||||
def __init__(self, notation='absolute', units='inch',
|
||||
zero_suppression=None, format=(2, 5), zeros=None,
|
||||
angle_units='degrees',
|
||||
name=None,
|
||||
mirror=(False, False), offset=(0., 0.), scale=(1., 1.),
|
||||
angle=0., axis='xy'):
|
||||
super(GerberContext, self).__init__(notation, units, zero_suppression,
|
||||
format, zeros, angle_units)
|
||||
self.name = name
|
||||
self.mirror = mirror
|
||||
self.offset = offset
|
||||
self.scale = scale
|
||||
self.angle = angle
|
||||
self.axis = axis
|
||||
|
||||
self.matrix = (1, 0,
|
||||
1, 0,
|
||||
1, 1)
|
||||
|
||||
self.op = None
|
||||
self.interpolation = self.IP_LINEAR
|
||||
self.direction = self.DIR_CLOCKWISE
|
||||
self.x = 0.
|
||||
self.y = 0.
|
||||
|
||||
def normalize_statement(self, stmt):
|
||||
if isinstance(stmt, INParamStmt):
|
||||
self.name = stmt.name
|
||||
elif isinstance(stmt, MIParamStmt):
|
||||
self.mirror = (stmt.a, stmt.b)
|
||||
self._update_matrix()
|
||||
elif isinstance(stmt, OFParamStmt):
|
||||
self.offset = (stmt.a, stmt.b)
|
||||
self._update_matrix()
|
||||
elif isinstance(stmt, SFParamStmt):
|
||||
self.scale = (stmt.a, stmt.b)
|
||||
self._update_matrix()
|
||||
elif isinstance(stmt, ASParamStmt):
|
||||
self.axis = 'yx' if stmt.mode == 'AYBX' else 'xy'
|
||||
self._update_matrix()
|
||||
elif isinstance(stmt, IRParamStmt):
|
||||
self.angle = stmt.angle
|
||||
elif isinstance(stmt, AMParamStmt) and not isinstance(stmt, AMParamStmtEx):
|
||||
stmt = AMParamStmtEx.from_stmt(stmt)
|
||||
return (self.TYPE_AM, [stmt])
|
||||
elif isinstance(stmt, ADParamStmt) and not isinstance(stmt, AMParamStmtEx):
|
||||
stmt = ADParamStmtEx.from_stmt(stmt)
|
||||
return (self.TYPE_AD, [stmt])
|
||||
elif isinstance(stmt, CoordStmt):
|
||||
self._normalize_coordinate(stmt)
|
||||
|
||||
if type(stmt).__name__ in self.ignored_stmt:
|
||||
return (self.TYPE_NONE, None)
|
||||
else:
|
||||
return (self.TYPE_MAIN, [stmt])
|
||||
|
||||
def _update_matrix(self):
|
||||
if self.axis == 'xy':
|
||||
mx = -1 if self.mirror[0] else 1
|
||||
my = -1 if self.mirror[1] else 1
|
||||
self.matrix = (
|
||||
self.scale[0] * mx, self.offset[0],
|
||||
self.scale[1] * my, self.offset[1],
|
||||
self.scale[0] * mx, self.scale[1] * my)
|
||||
else:
|
||||
mx = -1 if self.mirror[1] else 1
|
||||
my = -1 if self.mirror[0] else 1
|
||||
self.matrix = (
|
||||
self.scale[1] * mx, self.offset[1],
|
||||
self.scale[0] * my, self.offset[0],
|
||||
self.scale[1] * mx, self.scale[0] * my)
|
||||
|
||||
def _normalize_coordinate(self, stmt):
|
||||
if stmt.only_function:
|
||||
if stmt.function == 'G01' or stmt.function == 'G1':
|
||||
self.interpolation = self.IP_LINEAR
|
||||
elif stmt.function == 'G02' or stmt.function == 'G2':
|
||||
self.interpolation = self.IP_ARC
|
||||
self.direction = self.DIR_CLOCKWISE
|
||||
if self.mirror[0] != self.mirror[1]:
|
||||
self.direction = self.DIR_COUNTERCLOCKWISE
|
||||
stmt.function = 'G03'
|
||||
elif stmt.function == 'G03' or stmt.function == 'G3':
|
||||
self.interpolation = self.IP_ARC
|
||||
self.direction = self.DIR_COUNTERCLOCKWISE
|
||||
if self.mirror[0] != self.mirror[1]:
|
||||
self.direction = self.DIR_CLOCKWISE
|
||||
stmt.function = 'G02'
|
||||
return
|
||||
if self.notation == 'absolute':
|
||||
x = stmt.x if stmt.x is not None else self.x
|
||||
y = stmt.y if stmt.y is not None else self.y
|
||||
else:
|
||||
x = self.x + stmt.x if stmt.x is not None else 0
|
||||
y = self.y + stmt.y if stmt.y is not None else 0
|
||||
self.x, self.y = x, y
|
||||
self.op = stmt.op if stmt.op is not None else self.op
|
||||
|
||||
stmt.op = self.op
|
||||
stmt.x = self.matrix[0] * x + self.matrix[1]
|
||||
stmt.y = self.matrix[2] * y + self.matrix[3]
|
||||
if stmt.op == 'D01' and self.interpolation == self.IP_ARC:
|
||||
stmt.i = self.matrix[4] * stmt.i if stmt.i is not None else 0
|
||||
stmt.j = self.matrix[5] * stmt.j if stmt.j is not None else 0
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
%MOMM*%
|
||||
%FSLAX34Y34*%
|
||||
%INTop Layer*%
|
||||
%IPPOS*%
|
||||
%AMCOMP*
|
||||
20,1,0.2,0,0.1,0.4,0.1,$1*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
%MOMM*%
|
||||
%FSLAX34Y34*%
|
||||
%INTop Layer*%
|
||||
%IPPOS*%
|
||||
%AMCOMP*
|
||||
20,1,0.2,0,0.1,0.4,0.1,($1)+(20)*
|
||||
|
|
@ -10,15 +9,8 @@
|
|||
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*
|
||||
%AMMACR*
|
||||
21,1,$1,$2,0,0,20*
|
||||
1,0,$3,0,0,20*%
|
||||
%AMMACLO*
|
||||
$4=($1)-($2)*
|
||||
|
|
@ -27,9 +19,16 @@ $5=($1)-($4)*
|
|||
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*
|
||||
%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*%
|
||||
%AMMACP*
|
||||
5,1,$2,0,0,$1,($3)+(20)*
|
||||
1,0,$4,0,0,20*%
|
||||
%ADD10C,0.01*%
|
||||
%ADD11C,1X0.4*%
|
||||
%ADD12MACR,1X0.5X0.2*%
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
%MOMM*%
|
||||
%FSLAX34Y34*%
|
||||
%INTop Layer*%
|
||||
%IPPOS*%
|
||||
%AMCOMP*
|
||||
20,1,0.2,0,0.1,0.4,0.1,$1*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
%MOIN*%
|
||||
%FSLAX25Y25*%
|
||||
%INTop Layer*%
|
||||
%IPPOS*%
|
||||
%AMCOMP*
|
||||
20,1,0.00787402,0,0.00393701,0.015748,0.00393701,$1*
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
%MOMM*%
|
||||
%FSLAX34Y34*%
|
||||
%INTop Layer*%
|
||||
%IPPOS*%
|
||||
%AMCOMP*
|
||||
20,1,0.2,0,0.1,0.399999,0.1,$1*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
G75*
|
||||
%MOMM*%
|
||||
%OFA0B0*%
|
||||
%FSLAX34Y34*%
|
||||
%IPPOS*%
|
||||
%LPD*%
|
||||
%ADD10C,0*%
|
||||
G75*
|
||||
%LPD*%
|
||||
D10*
|
||||
G01*
|
||||
X200000Y50000D02*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
G75*
|
||||
%MOIN*%
|
||||
%OFA0B0*%
|
||||
%FSLAX25Y25*%
|
||||
%IPPOS*%
|
||||
%LPD*%
|
||||
%ADD10C,0*%
|
||||
G75*
|
||||
%LPD*%
|
||||
D10*
|
||||
G01*
|
||||
X0Y0D02*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
G75*
|
||||
%MOMM*%
|
||||
%OFA0B0*%
|
||||
%FSLAX34Y34*%
|
||||
%IPPOS*%
|
||||
%LPD*%
|
||||
%ADD10C,0*%
|
||||
G75*
|
||||
%LPD*%
|
||||
D10*
|
||||
G01*
|
||||
X0Y0D02*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
G75*
|
||||
%MOMM*%
|
||||
%OFA0B0*%
|
||||
%FSLAX34Y34*%
|
||||
%IPPOS*%
|
||||
%LPD*%
|
||||
%ADD10C,0*%
|
||||
G75*
|
||||
%LPD*%
|
||||
D10*
|
||||
G01*
|
||||
X124805Y2611D02*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
G75*
|
||||
%MOMM*%
|
||||
%OFA0B0*%
|
||||
%FSLAX34Y34*%
|
||||
%IPPOS*%
|
||||
%LPD*%
|
||||
%ADD10C,0*%
|
||||
G75*
|
||||
%LPD*%
|
||||
D10*
|
||||
G36*
|
||||
G01*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
G75*
|
||||
%MOMM*%
|
||||
%OFA0B0*%
|
||||
%FSLAX34Y34*%
|
||||
%IPPOS*%
|
||||
%LPD*%
|
||||
%ADD10C,0*%
|
||||
G75*
|
||||
%LPD*%
|
||||
D10*
|
||||
G01*
|
||||
X90000Y0D02*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
G75*
|
||||
%MOMM*%
|
||||
%OFA0B0*%
|
||||
%FSLAX34Y34*%
|
||||
%IPPOS*%
|
||||
%LPD*%
|
||||
%ADD10C,0.5*%
|
||||
G75*
|
||||
%LPD*%
|
||||
D10*
|
||||
X10000Y90000D03*
|
||||
X10000Y80000D03*
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
G75*
|
||||
%MOIN*%
|
||||
%OFA0B0*%
|
||||
%FSLAX25Y25*%
|
||||
%IPPOS*%
|
||||
%LPD*%
|
||||
%ADD10C,0*%
|
||||
G75*
|
||||
%LPD*%
|
||||
D10*
|
||||
G01*
|
||||
X35433Y0D02*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue