mirror of https://github.com/rusefi/gerbmerge.git
commit
e6f439b14e
|
@ -165,8 +165,8 @@ class ApertureMacroPrimitive:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def rotate(self):
|
def rotate(self):
|
||||||
if self.code == 1: # Circle: nothing to do
|
if self.code == 1: # Circle: [andreika]: FIX circle rotation
|
||||||
pass
|
rotatexypair(self.parms, 2)
|
||||||
elif self.code in (2,20): # Line (vector): fields (2,3) and (4,5) must be rotated, no need to
|
elif self.code in (2,20): # Line (vector): fields (2,3) and (4,5) must be rotated, no need to
|
||||||
# rotate field 6
|
# rotate field 6
|
||||||
rotatexypair(self.parms, 2)
|
rotatexypair(self.parms, 2)
|
||||||
|
|
|
@ -217,6 +217,8 @@ def constructApertureTable(fileList):
|
||||||
#print 'Reading apertures from %s ...' % fname
|
#print 'Reading apertures from %s ...' % fname
|
||||||
|
|
||||||
knownMacroNames = {}
|
knownMacroNames = {}
|
||||||
|
# [andreika]: units conversion
|
||||||
|
units_div = 1.0
|
||||||
|
|
||||||
fid = file(fname,'rt')
|
fid = file(fname,'rt')
|
||||||
for line in fid:
|
for line in fid:
|
||||||
|
@ -231,6 +233,13 @@ def constructApertureTable(fileList):
|
||||||
# Ignore %AMOC8* from Eagle for now as it uses a macro parameter.
|
# Ignore %AMOC8* from Eagle for now as it uses a macro parameter.
|
||||||
if line[:7]=='%AMOC8*':
|
if line[:7]=='%AMOC8*':
|
||||||
continue
|
continue
|
||||||
|
# [andreika]: units conversion
|
||||||
|
if line[:7]=='%MOMM*%' and config.Config['measurementunits'] == 'inch':
|
||||||
|
units_div = 1.0 / 25.4
|
||||||
|
continue
|
||||||
|
if line[:7]=='%MOIN*%' and config.Config['measurementunits'] == 'mm':
|
||||||
|
units_div = 25.4
|
||||||
|
continue
|
||||||
|
|
||||||
# parseApertureMacro() sucks up all macro lines up to terminating '%'
|
# parseApertureMacro() sucks up all macro lines up to terminating '%'
|
||||||
AM = amacro.parseApertureMacro(line, fid)
|
AM = amacro.parseApertureMacro(line, fid)
|
||||||
|
@ -255,6 +264,11 @@ def constructApertureTable(fileList):
|
||||||
# If this is an aperture definition, add the string representation
|
# If this is an aperture definition, add the string representation
|
||||||
# to the dictionary. It might already exist.
|
# to the dictionary. It might already exist.
|
||||||
if A:
|
if A:
|
||||||
|
# [andreika]: apply units
|
||||||
|
if type(A.dimx) == float or type(A.dimx) == int:
|
||||||
|
A.dimx *= units_div
|
||||||
|
if type(A.dimy) == float or type(A.dimy) == int:
|
||||||
|
A.dimy *= units_div
|
||||||
AT[A.hash()] = A
|
AT[A.hash()] = A
|
||||||
|
|
||||||
fid.close()
|
fid.close()
|
||||||
|
|
|
@ -52,6 +52,7 @@ Config = {
|
||||||
'fiducialpoints': None, # List of X,Y co-ordinates at which to draw fiducials
|
'fiducialpoints': None, # List of X,Y co-ordinates at which to draw fiducials
|
||||||
'fiducialcopperdiameter': 0.08, # Diameter of copper part of fiducial
|
'fiducialcopperdiameter': 0.08, # Diameter of copper part of fiducial
|
||||||
'fiducialmaskdiameter': 0.32, # Diameter of fiducial soldermask opening
|
'fiducialmaskdiameter': 0.32, # Diameter of fiducial soldermask opening
|
||||||
|
'fixedrotationorigin': 0, # [andreika]: add settings to disable shifting of the rotating origin
|
||||||
}
|
}
|
||||||
|
|
||||||
# This dictionary is indexed by lowercase layer name and has as values a file
|
# This dictionary is indexed by lowercase layer name and has as values a file
|
||||||
|
|
|
@ -172,6 +172,7 @@ def writeExcellonHeader(fid):
|
||||||
fid.write("INCH,%s\n" % zerosDef)
|
fid.write("INCH,%s\n" % zerosDef)
|
||||||
else: # metric - mm
|
else: # metric - mm
|
||||||
fid.write("METRIC,%s\n" % zerosDef)
|
fid.write("METRIC,%s\n" % zerosDef)
|
||||||
|
def writeExcellonHeaderEnd(fid):
|
||||||
fid.write('%\n')
|
fid.write('%\n')
|
||||||
|
|
||||||
def writeExcellonFooter(fid):
|
def writeExcellonFooter(fid):
|
||||||
|
@ -180,6 +181,9 @@ def writeExcellonFooter(fid):
|
||||||
def writeExcellonTool(fid, tool, size):
|
def writeExcellonTool(fid, tool, size):
|
||||||
fid.write('%sC%f\n' % (tool, size))
|
fid.write('%sC%f\n' % (tool, size))
|
||||||
|
|
||||||
|
def writeExcellonToolSelection(fid, tool, size):
|
||||||
|
fid.write('%s\n' % (tool))
|
||||||
|
|
||||||
def writeFiducials(fid, drawcode, OriginX, OriginY, MaxXExtent, MaxYExtent):
|
def writeFiducials(fid, drawcode, OriginX, OriginY, MaxXExtent, MaxYExtent):
|
||||||
"""Place fiducials at arbitrary points. The FiducialPoints list in the config specifies
|
"""Place fiducials at arbitrary points. The FiducialPoints list in the config specifies
|
||||||
sets of X,Y co-ordinates. Positive values of X/Y represent offsets from the lower left
|
sets of X,Y co-ordinates. Positive values of X/Y represent offsets from the lower left
|
||||||
|
@ -706,9 +710,13 @@ def merge(opts, args, gui = None):
|
||||||
size = config.GlobalToolMap[tool]
|
size = config.GlobalToolMap[tool]
|
||||||
except:
|
except:
|
||||||
raise RuntimeError, "INTERNAL ERROR: Tool code %s not found in global tool map" % tool
|
raise RuntimeError, "INTERNAL ERROR: Tool code %s not found in global tool map" % tool
|
||||||
|
|
||||||
writeExcellonTool(fid, tool, size)
|
writeExcellonTool(fid, tool, size)
|
||||||
|
|
||||||
|
writeExcellonHeaderEnd(fid)
|
||||||
|
|
||||||
|
for tool in Tools:
|
||||||
|
size = config.GlobalToolMap[tool]
|
||||||
|
writeExcellonToolSelection(fid, tool, size)
|
||||||
#for row in Layout:
|
#for row in Layout:
|
||||||
# row.writeExcellon(fid, size)
|
# row.writeExcellon(fid, size)
|
||||||
for job in Place.jobs:
|
for job in Place.jobs:
|
||||||
|
|
|
@ -80,7 +80,7 @@ IgnoreList = ( \
|
||||||
re.compile(r'\*'), # Empty statement
|
re.compile(r'\*'), # Empty statement
|
||||||
re.compile(r'^%IN.*\*%'),
|
re.compile(r'^%IN.*\*%'),
|
||||||
re.compile(r'^%ICAS\*%'), # Not in RS274X spec.
|
re.compile(r'^%ICAS\*%'), # Not in RS274X spec.
|
||||||
re.compile(r'^%MOIN\*%'),
|
#re.compile(r'^%MOIN\*%'), # [andreika]: don't ignore
|
||||||
re.compile(r'^%ASAXBY\*%'),
|
re.compile(r'^%ASAXBY\*%'),
|
||||||
re.compile(r'^%AD\*%'), # GerbTool empty aperture definition
|
re.compile(r'^%AD\*%'), # GerbTool empty aperture definition
|
||||||
re.compile(r'^%LN.*\*%') # Layer name
|
re.compile(r'^%LN.*\*%') # Layer name
|
||||||
|
@ -88,7 +88,8 @@ IgnoreList = ( \
|
||||||
|
|
||||||
# Patterns for Excellon interpretation
|
# Patterns for Excellon interpretation
|
||||||
xtool_pat = re.compile(r'^(T\d+)$') # Tool selection
|
xtool_pat = re.compile(r'^(T\d+)$') # Tool selection
|
||||||
xydraw_pat = re.compile(r'^X([+-]?\d+)Y([+-]?\d+)$') # Plunge command
|
xydraw_pat = re.compile(r'^X([+-]?\d+)Y([+-]?\d+)(?:G85X([+-]?\d+)Y([+-]?\d+))?$') # Plunge command with optional G85
|
||||||
|
xydraw_pat2 = re.compile(r'^X([+-]?\d+\.\d*)Y([+-]?\d+\.\d*)(?:G85X([+-]?\d+\.\d*)Y([+-]?\d+\.\d*))?$') # Plunge command with optional G85
|
||||||
xdraw_pat = re.compile(r'^X([+-]?\d+)$') # Plunge command, repeat last Y value
|
xdraw_pat = re.compile(r'^X([+-]?\d+)$') # Plunge command, repeat last Y value
|
||||||
ydraw_pat = re.compile(r'^Y([+-]?\d+)$') # Plunge command, repeat last X value
|
ydraw_pat = re.compile(r'^Y([+-]?\d+)$') # Plunge command, repeat last X value
|
||||||
xtdef_pat = re.compile(r'^(T\d+)(?:F\d+)?(?:S\d+)?C([0-9.]+)$') # Tool+diameter definition with optional
|
xtdef_pat = re.compile(r'^(T\d+)(?:F\d+)?(?:S\d+)?C([0-9.]+)$') # Tool+diameter definition with optional
|
||||||
|
@ -172,8 +173,9 @@ class Job:
|
||||||
# This is to help sorting all jobs and writing out all plunge
|
# This is to help sorting all jobs and writing out all plunge
|
||||||
# commands for a single tool.
|
# commands for a single tool.
|
||||||
#
|
#
|
||||||
# The key to this dictionary is the full tool name, e.g., T03
|
# The key to this dictionary is the full tool name, e.g., T03 as a
|
||||||
# as a string. Each command is an (X,Y) integer tuple.
|
# string. Each command is an (X,Y,STOP_X,STOP_Y) integer tuple.
|
||||||
|
# STOP_X and STOP_Y are not none only if this is a G85 command.
|
||||||
self.xcommands = {}
|
self.xcommands = {}
|
||||||
|
|
||||||
# This is a dictionary mapping LOCAL tool names (e.g., T03) to diameters
|
# This is a dictionary mapping LOCAL tool names (e.g., T03) to diameters
|
||||||
|
@ -263,6 +265,11 @@ class Job:
|
||||||
and ( type( command_list[1] ) == types.IntType ): ## ensure that first two elemenst are integers
|
and ( type( command_list[1] ) == types.IntType ): ## ensure that first two elemenst are integers
|
||||||
command_list[0] += x_shift / 10
|
command_list[0] += x_shift / 10
|
||||||
command_list[1] += y_shift / 10
|
command_list[1] += y_shift / 10
|
||||||
|
if ( type( command_list[2] ) == types.IntType ) \
|
||||||
|
and ( type( command_list[3] ) == types.IntType ): ## ensure that first two elemenst are integerslen(command_list) == 4:
|
||||||
|
# G85 command, need to shift the second pair of xy, too.
|
||||||
|
command_list[2] += x_shift / 10
|
||||||
|
command_list[3] += y_shift / 10
|
||||||
command[index] = tuple(command_list) ## convert list back to tuple
|
command[index] = tuple(command_list) ## convert list back to tuple
|
||||||
|
|
||||||
self.xcommands[tool] = command ## set modified command
|
self.xcommands[tool] = command ## set modified command
|
||||||
|
@ -294,6 +301,12 @@ class Job:
|
||||||
x_div = 1.0
|
x_div = 1.0
|
||||||
y_div = 1.0
|
y_div = 1.0
|
||||||
|
|
||||||
|
# [andreika]: use local units conversion
|
||||||
|
units_div = 1.0
|
||||||
|
|
||||||
|
# [andreika]: store fill mode separately because of G01 can be inside G36/37
|
||||||
|
in_fill_mode = False
|
||||||
|
|
||||||
# Drawing commands can be repeated with X or Y omitted if they are
|
# Drawing commands can be repeated with X or Y omitted if they are
|
||||||
# the same as before. These variables store the last X/Y value as
|
# the same as before. These variables store the last X/Y value as
|
||||||
# integers in hundred-thousandths of an inch.
|
# integers in hundred-thousandths of an inch.
|
||||||
|
@ -346,6 +359,11 @@ class Job:
|
||||||
A = aptable.parseAperture(line, self.apmxlat[layername])
|
A = aptable.parseAperture(line, self.apmxlat[layername])
|
||||||
if not A:
|
if not A:
|
||||||
raise RuntimeError, "Unknown aperture definition in file %s" % fullname
|
raise RuntimeError, "Unknown aperture definition in file %s" % fullname
|
||||||
|
# [andreika]: apply units
|
||||||
|
if type(A.dimx) == float or type(A.dimx) == int:
|
||||||
|
A.dimx *= units_div
|
||||||
|
if type(A.dimy) == float or type(A.dimy) == int:
|
||||||
|
A.dimy *= units_div
|
||||||
|
|
||||||
hash = A.hash()
|
hash = A.hash()
|
||||||
if not RevGAT.has_key(hash):
|
if not RevGAT.has_key(hash):
|
||||||
|
@ -367,11 +385,21 @@ class Job:
|
||||||
# DipTrace specific fixes, but could be emitted by any CAD program. They are Standard Gerber RS-274X
|
# DipTrace specific fixes, but could be emitted by any CAD program. They are Standard Gerber RS-274X
|
||||||
# a hack to fix lack of recognition for metric direction from DipTrace - %MOMM*%
|
# a hack to fix lack of recognition for metric direction from DipTrace - %MOMM*%
|
||||||
if (line[:7] == '%MOMM*%'):
|
if (line[:7] == '%MOMM*%'):
|
||||||
|
# [andreika]: just set units to mm, no error
|
||||||
if (config.Config['measurementunits'] == 'inch'):
|
if (config.Config['measurementunits'] == 'inch'):
|
||||||
raise RuntimeError, "File %s units do match config file" % fullname
|
#raise RuntimeError, "File %s units do match config file" % fullname
|
||||||
|
units_div = 1.0 / 25.4
|
||||||
|
continue
|
||||||
else:
|
else:
|
||||||
#print "ignoring metric directive: " + line
|
#print "ignoring metric directive: " + line
|
||||||
continue # ignore it so func doesn't choke on it
|
continue # ignore it so func doesn't choke on it
|
||||||
|
# [andreika]: add reciprocal conversion
|
||||||
|
if (line[:7] == '%MOIN*%'):
|
||||||
|
if (config.Config['measurementunits'] == 'mm'):
|
||||||
|
units_div = 25.4
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
continue # ignore it so func doesn't choke on it
|
||||||
|
|
||||||
if line[:3] == '%SF': # scale factor - we will ignore it
|
if line[:3] == '%SF': # scale factor - we will ignore it
|
||||||
print 'Scale factor parameter ignored: ' + line
|
print 'Scale factor parameter ignored: ' + line
|
||||||
|
@ -425,6 +453,7 @@ class Job:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# allow for metric - scale to 1/1000 mm
|
# allow for metric - scale to 1/1000 mm
|
||||||
|
# [andreika]: use local units
|
||||||
if config.Config['measurementunits'] == 'inch':
|
if config.Config['measurementunits'] == 'inch':
|
||||||
if item[0]=='X': # M.N specification for X-axis.
|
if item[0]=='X': # M.N specification for X-axis.
|
||||||
fracpart = int(item[2])
|
fracpart = int(item[2])
|
||||||
|
@ -471,6 +500,12 @@ class Job:
|
||||||
elif gcode==75:
|
elif gcode==75:
|
||||||
circ_signed = True
|
circ_signed = True
|
||||||
|
|
||||||
|
# [andreika]: we store fill mode separately
|
||||||
|
if gcode==36:
|
||||||
|
in_fill_mode = True
|
||||||
|
elif gcode==37:
|
||||||
|
in_fill_mode = False
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
raise RuntimeError, "G-Code 'G%02d' is not supported" % gcode
|
raise RuntimeError, "G-Code 'G%02d' is not supported" % gcode
|
||||||
|
@ -564,7 +599,9 @@ class Job:
|
||||||
# It's also OK if we're in the middle of a G36 polygon fill as we're only defining
|
# It's also OK if we're in the middle of a G36 polygon fill as we're only defining
|
||||||
# the polygon extents.
|
# the polygon extents.
|
||||||
if (d != 2) and (last_gmode != 36):
|
if (d != 2) and (last_gmode != 36):
|
||||||
raise RuntimeError, 'File %s has draw command %s with no aperture chosen' % (fullname, sub_line)
|
# [andreika]: check for fill mode more accurately
|
||||||
|
if not in_fill_mode:
|
||||||
|
raise RuntimeError, 'File %s has draw command %s with no aperture chosen' % (fullname, sub_line)
|
||||||
|
|
||||||
# Save last_x/y BEFORE scaling to 2.5 format else subsequent single-ordinate
|
# Save last_x/y BEFORE scaling to 2.5 format else subsequent single-ordinate
|
||||||
# flashes (e.g., Y with no X) will be scaled twice!
|
# flashes (e.g., Y with no X) will be scaled twice!
|
||||||
|
@ -582,11 +619,12 @@ class Job:
|
||||||
self.miny = min(self.miny,0)
|
self.miny = min(self.miny,0)
|
||||||
self.maxy = max(self.maxy,0)
|
self.maxy = max(self.maxy,0)
|
||||||
|
|
||||||
x = int(round(x*x_div))
|
# [andreika]: add units_div
|
||||||
y = int(round(y*y_div))
|
x = int(round(x*x_div*units_div))
|
||||||
|
y = int(round(y*y_div*units_div))
|
||||||
if I is not None:
|
if I is not None:
|
||||||
I = int(round(I*x_div))
|
I = int(round(I*x_div*units_div))
|
||||||
J = int(round(J*y_div))
|
J = int(round(J*y_div*units_div))
|
||||||
self.commands[layername].append((x,y,I,J,d,circ_signed))
|
self.commands[layername].append((x,y,I,J,d,circ_signed))
|
||||||
else:
|
else:
|
||||||
self.commands[layername].append((x,y,d))
|
self.commands[layername].append((x,y,d))
|
||||||
|
@ -650,9 +688,22 @@ class Job:
|
||||||
def xln2tenthou(L, divisor=divisor, zeropadto=zeropadto):
|
def xln2tenthou(L, divisor=divisor, zeropadto=zeropadto):
|
||||||
V = []
|
V = []
|
||||||
for s in L:
|
for s in L:
|
||||||
if not suppress_leading:
|
if s is not None:
|
||||||
s = s + '0'*(zeropadto-len(s))
|
if not suppress_leading:
|
||||||
V.append(int(round(int(s)*divisor)))
|
s = s + '0'*(zeropadto-len(s))
|
||||||
|
V.append(int(round(int(s)*divisor)))
|
||||||
|
else:
|
||||||
|
V.append(None)
|
||||||
|
return tuple(V)
|
||||||
|
|
||||||
|
# Helper function to convert X/Y strings into integers in units of ten-thousandth of an inch.
|
||||||
|
def xln2tenthou2 (L, divisor=divisor, zeropadto=zeropadto):
|
||||||
|
V = []
|
||||||
|
for s in L:
|
||||||
|
if s is not None:
|
||||||
|
V.append(int(float(s)*1000*divisor))
|
||||||
|
else:
|
||||||
|
V.append(None)
|
||||||
return tuple(V)
|
return tuple(V)
|
||||||
|
|
||||||
for line in fid.xreadlines():
|
for line in fid.xreadlines():
|
||||||
|
@ -742,26 +793,30 @@ class Job:
|
||||||
# Plunge command?
|
# Plunge command?
|
||||||
match = xydraw_pat.match(line)
|
match = xydraw_pat.match(line)
|
||||||
if match:
|
if match:
|
||||||
x, y = xln2tenthou(match.groups())
|
x, y, stop_x, stop_y = xln2tenthou(match.groups())
|
||||||
else:
|
else:
|
||||||
match = xdraw_pat.match(line)
|
match = xydraw_pat2.match(line)
|
||||||
if match:
|
if match:
|
||||||
x = xln2tenthou(match.groups())[0]
|
x, y, stop_x, stop_y = xln2tenthou2(match.groups())
|
||||||
y = last_y
|
|
||||||
else:
|
else:
|
||||||
match = ydraw_pat.match(line)
|
match = xdraw_pat.match(line)
|
||||||
if match:
|
if match:
|
||||||
y = xln2tenthou(match.groups())[0]
|
x = xln2tenthou(match.groups())[0]
|
||||||
x = last_x
|
y = last_y
|
||||||
|
else:
|
||||||
|
match = ydraw_pat.match(line)
|
||||||
|
if match:
|
||||||
|
y = xln2tenthou(match.groups())[0]
|
||||||
|
x = last_x
|
||||||
|
|
||||||
if match:
|
if match:
|
||||||
if currtool is None:
|
if currtool is None:
|
||||||
raise RuntimeError, 'File %s has plunge command without previous tool selection' % fullname
|
raise RuntimeError, 'File %s has plunge command without previous tool selection' % fullname
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.xcommands[currtool].append((x,y))
|
self.xcommands[currtool].append((x,y,stop_x,stop_y))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.xcommands[currtool] = [(x,y)]
|
self.xcommands[currtool] = [(x,y,stop_x,stop_y)]
|
||||||
|
|
||||||
last_x = x
|
last_x = x
|
||||||
last_y = y
|
last_y = y
|
||||||
|
@ -874,10 +929,17 @@ class Job:
|
||||||
for ltool in ltools:
|
for ltool in ltools:
|
||||||
if self.xcommands.has_key(ltool):
|
if self.xcommands.has_key(ltool):
|
||||||
for cmd in self.xcommands[ltool]:
|
for cmd in self.xcommands[ltool]:
|
||||||
x, y = cmd
|
x, y, stop_x, stop_y = cmd
|
||||||
new_x = x+DX
|
new_x = x+DX
|
||||||
new_y = y+DY
|
new_y = y+DY
|
||||||
fid.write('X%sY%s\n' % (formatForXln(new_x), formatForXln(new_y)))
|
if stop_x is None:
|
||||||
|
fid.write('X%sY%s\n' % (formatForXln(new_x), formatForXln(new_y)))
|
||||||
|
else:
|
||||||
|
new_stop_x = stop_x+DX
|
||||||
|
new_stop_y = stop_y+DY
|
||||||
|
fid.write('X%sY%sG85X%sY%s\n' %
|
||||||
|
(formatForXln(new_x), formatForXln(new_y),
|
||||||
|
formatForXln(new_stop_x), formatForXln(new_stop_y)))
|
||||||
|
|
||||||
def writeDrillHits(self, fid, diameter, toolNum, Xoff, Yoff):
|
def writeDrillHits(self, fid, diameter, toolNum, Xoff, Yoff):
|
||||||
"""Write a drill hit pattern. diameter is tool diameter in inches, while toolNum is
|
"""Write a drill hit pattern. diameter is tool diameter in inches, while toolNum is
|
||||||
|
@ -905,10 +967,12 @@ class Job:
|
||||||
for ltool in ltools:
|
for ltool in ltools:
|
||||||
if self.xcommands.has_key(ltool):
|
if self.xcommands.has_key(ltool):
|
||||||
for cmd in self.xcommands[ltool]:
|
for cmd in self.xcommands[ltool]:
|
||||||
x, y = cmd
|
x, y, stop_x, stop_y = cmd
|
||||||
# add metric support (1/1000 mm vs. 1/100,000 inch)
|
# add metric support (1/1000 mm vs. 1/100,000 inch)
|
||||||
# TODO - verify metric scaling is correct???
|
# TODO - verify metric scaling is correct???
|
||||||
makestroke.drawDrillHit(fid, 10*x+DX, 10*y+DY, toolNum)
|
makestroke.drawDrillHit(fid, 10*x+DX, 10*y+DY, toolNum)
|
||||||
|
if stop_x is not None:
|
||||||
|
makestroke.drawDrillHit(fid, 10*stop_x+DX, 10*stop_y+DY, toolNum)
|
||||||
|
|
||||||
def aperturesAndMacros(self, layername):
|
def aperturesAndMacros(self, layername):
|
||||||
"Return dictionaries whose keys are all necessary aperture names and macro names for this layer"
|
"Return dictionaries whose keys are all necessary aperture names and macro names for this layer"
|
||||||
|
@ -1124,8 +1188,9 @@ class Job:
|
||||||
keys = self.xcommands.keys()
|
keys = self.xcommands.keys()
|
||||||
for toolname in keys:
|
for toolname in keys:
|
||||||
# Remember Excellon is 2.4 format while Gerber data is 2.5 format
|
# Remember Excellon is 2.4 format while Gerber data is 2.5 format
|
||||||
validList = [(x,y) for x,y in self.xcommands[toolname] if self.inBorders(10*x,10*y)]
|
validList = [tup for tup in self.xcommands[toolname]
|
||||||
|
if (self.inBorders(10*tup[0],10*tup[1]) and
|
||||||
|
(tup[2] is None or self.inBorders(10*tup[2],10*tup[3])))]
|
||||||
if validList:
|
if validList:
|
||||||
self.xcommands[toolname] = validList
|
self.xcommands[toolname] = validList
|
||||||
else:
|
else:
|
||||||
|
@ -1348,7 +1413,11 @@ def rotateJob(job, degrees = 90, firstpass = True):
|
||||||
# We also have to take aperture change commands and
|
# We also have to take aperture change commands and
|
||||||
# replace them with the new aperture code if we have
|
# replace them with the new aperture code if we have
|
||||||
# a rotation.
|
# a rotation.
|
||||||
offset = job.maxy-job.miny
|
# [andreika]: add 'fixedrotationorigin' setting to disable shifting
|
||||||
|
if config.Config['fixedrotationorigin']:
|
||||||
|
offset = 0
|
||||||
|
else:
|
||||||
|
offset = job.maxy-job.miny
|
||||||
for layername in job.commands.keys():
|
for layername in job.commands.keys():
|
||||||
J.commands[layername] = []
|
J.commands[layername] = []
|
||||||
J.apertures[layername] = []
|
J.apertures[layername] = []
|
||||||
|
@ -1410,7 +1479,7 @@ def rotateJob(job, degrees = 90, firstpass = True):
|
||||||
for tool in job.xcommands.keys():
|
for tool in job.xcommands.keys():
|
||||||
J.xcommands[tool] = []
|
J.xcommands[tool] = []
|
||||||
|
|
||||||
for x,y in job.xcommands[tool]:
|
for x,y,stop_x,stop_y in job.xcommands[tool]:
|
||||||
# add metric support (1/1000 mm vs. 1/100,000 inch)
|
# add metric support (1/1000 mm vs. 1/100,000 inch)
|
||||||
# NOTE: There don't appear to be any need for a change. The usual x10 factor seems to apply
|
# NOTE: There don't appear to be any need for a change. The usual x10 factor seems to apply
|
||||||
|
|
||||||
|
@ -1420,8 +1489,16 @@ def rotateJob(job, degrees = 90, firstpass = True):
|
||||||
newx = int(round(newx/10.0))
|
newx = int(round(newx/10.0))
|
||||||
newy = int(round(newy/10.0))
|
newy = int(round(newy/10.0))
|
||||||
|
|
||||||
|
if stop_x is not None:
|
||||||
|
newstop_x = -(10*stop_y - job.miny) + job.minx + offset
|
||||||
|
newstop_y = (10*stop_x - job.minx) + job.miny
|
||||||
|
|
||||||
J.xcommands[tool].append((newx,newy))
|
newstop_x = int(round(newstop_x/10.0))
|
||||||
|
newstop_y = int(round(newstop_y/10.0))
|
||||||
|
else:
|
||||||
|
newstop_x = None
|
||||||
|
newstop_y = None
|
||||||
|
J.xcommands[tool].append((newx,newy,newstop_x,newstop_y))
|
||||||
|
|
||||||
# Rotate some more if required
|
# Rotate some more if required
|
||||||
degrees -= 90
|
degrees -= 90
|
||||||
|
|
Loading…
Reference in New Issue