mirror of https://github.com/rusefi/gerbmerge.git
flipping support
This commit is contained in:
parent
fea2bf8868
commit
73eafd9543
|
@ -63,9 +63,16 @@ def rotatexy(x,y):
|
|||
# Rotate point (x,y) counterclockwise 90 degrees about the origin
|
||||
return (-y,x)
|
||||
|
||||
def rotatexypair(L, ix):
|
||||
# Rotate list items L[ix],L[ix+1] by 90 degrees
|
||||
L[ix],L[ix+1] = rotatexy(L[ix],L[ix+1])
|
||||
def rotatexypair(L, flip, ix):
|
||||
if (flip == 1):
|
||||
# flip horizontally
|
||||
L[ix],L[ix+1] = (-L[ix], L[ix+1])
|
||||
elif (flip == -1):
|
||||
# flip vertically
|
||||
L[ix],L[ix+1] = (L[ix], -L[ix+1])
|
||||
else:
|
||||
# Rotate list items L[ix],L[ix+1] by 90 degrees
|
||||
L[ix],L[ix+1] = rotatexy(L[ix],L[ix+1])
|
||||
|
||||
def swapxypair(L, ix):
|
||||
# Swap two list elements
|
||||
|
@ -79,9 +86,10 @@ def rotatetheta(th):
|
|||
th -= 360
|
||||
return th
|
||||
|
||||
def rotatethelem(L, ix):
|
||||
def rotatethelem(L, flip, ix):
|
||||
# Increase angle th by +90 degrees for a list element
|
||||
L[ix] = rotatetheta(L[ix])
|
||||
if (flip == 0):
|
||||
L[ix] = rotatetheta(L[ix])
|
||||
|
||||
class ApertureMacroPrimitive:
|
||||
def __init__(self, code=-1, fields=None):
|
||||
|
@ -164,34 +172,34 @@ class ApertureMacroPrimitive:
|
|||
print '='*20
|
||||
raise
|
||||
|
||||
def rotate(self):
|
||||
def rotate(self, flip):
|
||||
if self.code == 1: # Circle: [andreika]: FIX circle rotation
|
||||
rotatexypair(self.parms, 2)
|
||||
rotatexypair(self.parms, flip, 2)
|
||||
elif self.code in (2,20): # Line (vector): fields (2,3) and (4,5) must be rotated, no need to
|
||||
# rotate field 6
|
||||
rotatexypair(self.parms, 2)
|
||||
rotatexypair(self.parms, 4)
|
||||
rotatexypair(self.parms, flip, 2)
|
||||
rotatexypair(self.parms, flip, 4)
|
||||
elif self.code == 21: # Line (center): fields (3,4) must be rotated, and field 5 incremented by +90
|
||||
rotatexypair(self.parms, 3)
|
||||
rotatethelem(self.parms, 5)
|
||||
rotatexypair(self.parms, flip, 3)
|
||||
rotatethelem(self.parms, flip, 5)
|
||||
elif self.code == 22: # Line (lower-left): fields (3,4) must be rotated, and field 5 incremented by +90
|
||||
rotatexypair(self.parms, 3)
|
||||
rotatethelem(self.parms, 5)
|
||||
rotatexypair(self.parms, flip, 3)
|
||||
rotatethelem(self.parms, flip, 5)
|
||||
elif self.code == 4: # Outline: fields (2,3), (4,5), etc. must be rotated, the last field need not be incremented
|
||||
ix = 2
|
||||
for pts in range(self.parms[1]): # parms[1] is the number of points
|
||||
rotatexypair(self.parms, ix)
|
||||
rotatexypair(self.parms, flip, ix)
|
||||
ix += 2
|
||||
#rotatethelem(self.parms, ix)
|
||||
elif self.code == 5: # Polygon: fields (2,3) must be rotated, and field 5 incremented by +90
|
||||
rotatexypair(self.parms, 2)
|
||||
rotatethelem(self.parms, 5)
|
||||
rotatexypair(self.parms, flip, 2)
|
||||
rotatethelem(self.parms, flip, 5)
|
||||
elif self.code == 6: # Moire: fields (0,1) must be rotated, and field 8 incremented by +90
|
||||
rotatexypair(self.parms, 0)
|
||||
rotatethelem(self.parms, 8)
|
||||
rotatexypair(self.parms, flip, 0)
|
||||
rotatethelem(self.parms, flip, 8)
|
||||
elif self.code == 7: # Thermal: fields (0,1) must be rotated, and field 5 incremented by +90
|
||||
rotatexypair(self.parms, 0)
|
||||
rotatethelem(self.parms, 5)
|
||||
rotatexypair(self.parms, flip, 0)
|
||||
rotatethelem(self.parms, flip, 5)
|
||||
|
||||
def __str__(self):
|
||||
# Construct a string with ints as ints and floats as floats
|
||||
|
@ -221,17 +229,22 @@ class ApertureMacro:
|
|||
def add(self, prim):
|
||||
self.prim.append(prim)
|
||||
|
||||
def rotate(self):
|
||||
def rotate(self, flip):
|
||||
for prim in self.prim:
|
||||
prim.rotate()
|
||||
prim.rotate(flip)
|
||||
|
||||
def rotated(self):
|
||||
def rotated(self, flip):
|
||||
# Return copy of ourselves, rotated. Replace 'R' as the first letter of the
|
||||
# macro name. We don't append because we like to be able to count the
|
||||
# number of aperture macros by stripping off the leading character.
|
||||
M = copy.deepcopy(self)
|
||||
M.rotate()
|
||||
M.name = 'R'+M.name[1:]
|
||||
M.rotate(flip)
|
||||
if (flip == 1):
|
||||
M.name = 'FH'+M.name[1:]
|
||||
elif (flip == -1):
|
||||
M.name = 'FV'+M.name[1:]
|
||||
else:
|
||||
M.name = 'R'+M.name[1:]
|
||||
return M
|
||||
|
||||
def dump(self, fid=sys.stdout):
|
||||
|
@ -322,7 +335,7 @@ if __name__=="__main__":
|
|||
# A thermal in the second quadrant, beyond the right triangle
|
||||
M.add(ApertureMacroPrimitive(7, ('-0.07', '0.07', '0.03', '0.02', '0.005', '15')))
|
||||
|
||||
MR = M.rotated()
|
||||
MR = M.rotated(0)
|
||||
|
||||
# Generate the Gerber so we can view it
|
||||
fid = file('amacro.ger', 'wt')
|
||||
|
|
|
@ -97,14 +97,14 @@ class Aperture:
|
|||
else:
|
||||
return False ## no new aperture needs to be created
|
||||
|
||||
def rotate(self, RevGAMT):
|
||||
def rotate(self, RevGAMT, flip):
|
||||
if self.apname in ('Macro',):
|
||||
# Construct a rotated macro, see if it's in the GAMT, and set self.dimx
|
||||
# to its name if so. If not, add the rotated macro to the GAMT and set
|
||||
# self.dimx to the new name. Recall that GAMT maps name to macro
|
||||
# (e.g., GAMT['M9'] = ApertureMacro(...)) while RevGAMT maps hash to
|
||||
# macro name (e.g., RevGAMT[hash] = 'M9')
|
||||
AMR = config.GAMT[self.dimx].rotated()
|
||||
AMR = config.GAMT[self.dimx].rotated(flip)
|
||||
hash = AMR.hash()
|
||||
try:
|
||||
self.dimx = RevGAMT[hash]
|
||||
|
@ -113,14 +113,15 @@ class Aperture:
|
|||
self.dimx = RevGAMT[hash] = AMR.name
|
||||
|
||||
elif self.dimy is not None: # Rectangles and Ovals have a dimy setting and need to be rotated
|
||||
t = self.dimx
|
||||
self.dimx = self.dimy
|
||||
self.dimy = t
|
||||
if (flip == 0):
|
||||
t = self.dimx
|
||||
self.dimx = self.dimy
|
||||
self.dimy = t
|
||||
|
||||
def rotated(self, RevGAMT):
|
||||
def rotated(self, RevGAMT, flip):
|
||||
# deepcopy doesn't work on re patterns for some reason so we copy ourselves manually
|
||||
APR = Aperture((self.apname, self.pat, self.format), self.code, self.dimx, self.dimy)
|
||||
APR.rotate(RevGAMT)
|
||||
APR.rotate(RevGAMT, flip)
|
||||
return APR
|
||||
|
||||
def dump(self, fid=sys.stdout):
|
||||
|
|
|
@ -1337,26 +1337,48 @@ class JobLayout:
|
|||
def jobarea(self):
|
||||
return self.job.jobarea()
|
||||
|
||||
def rotateJob(job, degrees = 90, firstpass = True):
|
||||
def rotateJob(job, degrees = 90, flip = 0, firstpass = True):
|
||||
"""Create a new job from an existing one, rotating by specified degrees in 90 degree passes"""
|
||||
GAT = config.GAT
|
||||
GAMT = config.GAMT
|
||||
##print "rotating job:", job.name, degrees, firstpass
|
||||
#!!!!!!!
|
||||
print "rotating job:", job.name, degrees, flip, firstpass
|
||||
##print "rotating job:", job.name, degrees, flip, firstpass
|
||||
if firstpass:
|
||||
rotatedFlipped = ""
|
||||
if degrees == 270:
|
||||
J = Job(job.name+'*rotated270')
|
||||
rotatedFlipped += '*rotated270'
|
||||
elif degrees == 180:
|
||||
J = Job(job.name+'*rotated180')
|
||||
else:
|
||||
J = Job(job.name+'*rotated90')
|
||||
rotatedFlipped += '*rotated180'
|
||||
elif degrees == 90:
|
||||
rotatedFlipped += '*rotated90'
|
||||
if flip == 1:
|
||||
rotatedFlipped += '*flippedH'
|
||||
elif flip == -1:
|
||||
rotatedFlipped += '*flippedV'
|
||||
J = Job(job.name + rotatedFlipped)
|
||||
else:
|
||||
J = Job(job.name)
|
||||
|
||||
# Keep the origin (lower-left) in the same place
|
||||
J.maxx = job.minx + job.maxy-job.miny
|
||||
J.maxy = job.miny + job.maxx-job.minx
|
||||
J.minx = job.minx
|
||||
J.miny = job.miny
|
||||
if degrees != 0:
|
||||
J.maxx = job.minx + job.maxy-job.miny
|
||||
J.maxy = job.miny + job.maxx-job.minx
|
||||
J.minx = job.minx
|
||||
J.miny = job.miny
|
||||
doFlip = 0
|
||||
else:
|
||||
doFlip = flip
|
||||
if flip == 1:
|
||||
J.minx = job.maxx
|
||||
J.maxx = job.minx
|
||||
J.miny = job.miny
|
||||
J.maxy = job.maxy
|
||||
elif flip == -1:
|
||||
J.minx = job.minx
|
||||
J.maxx = job.maxx
|
||||
J.miny = job.maxy
|
||||
J.maxy = job.miny
|
||||
|
||||
RevGAT = config.buildRevDict(GAT) # RevGAT[hash] = aperturename
|
||||
RevGAMT = config.buildRevDict(GAMT) # RevGAMT[hash] = aperturemacroname
|
||||
|
@ -1383,7 +1405,7 @@ def rotateJob(job, degrees = 90, firstpass = True):
|
|||
continue
|
||||
|
||||
# Must rotate the aperture
|
||||
APR = A.rotated(RevGAMT)
|
||||
APR = A.rotated(RevGAMT, doFlip)
|
||||
|
||||
# Does it already exist in the GAT?
|
||||
hash = APR.hash()
|
||||
|
@ -1452,10 +1474,17 @@ def rotateJob(job, degrees = 90, firstpass = True):
|
|||
J.apertures[layername].append(cmd)
|
||||
continue
|
||||
|
||||
# (X,Y) --> (-Y,X) effects a 90-degree counterclockwise shift
|
||||
# Adding 'offset' to -Y maintains the lower-left origin of (minx,miny).
|
||||
newx = -(y - job.miny) + job.minx + offset
|
||||
newy = (x-job.minx) + job.miny
|
||||
if (doFlip == 1):
|
||||
newx = job.maxx - (x - job.minx)
|
||||
newy = y
|
||||
elif (doFlip == -1):
|
||||
newx = x
|
||||
newy = job.maxy - (y - job.miny)
|
||||
else:
|
||||
# (X,Y) --> (-Y,X) effects a 90-degree counterclockwise shift
|
||||
# Adding 'offset' to -Y maintains the lower-left origin of (minx,miny).
|
||||
newx = -(y - job.miny) + job.minx + offset
|
||||
newy = (x-job.minx) + job.miny
|
||||
|
||||
# For circular interpolation commands, (I,J) components are always relative
|
||||
# so we do not worry about offsets, just reverse their sense, i.e., I becomes J
|
||||
|
@ -1483,15 +1512,29 @@ def rotateJob(job, degrees = 90, firstpass = True):
|
|||
# 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
|
||||
|
||||
newx = -(10*y - job.miny) + job.minx + offset
|
||||
newy = (10*x - job.minx) + job.miny
|
||||
if (doFlip == 1):
|
||||
newx = job.minx - (10*x - job.minx)
|
||||
newy = 10*y
|
||||
elif (doFlip == -1):
|
||||
newx = 10*x
|
||||
newy = job.miny - (10*y - job.miny)
|
||||
else:
|
||||
newx = -(10*y - job.miny) + job.minx + offset
|
||||
newy = (10*x - job.minx) + job.miny
|
||||
|
||||
newx = int(round(newx/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
|
||||
if (doFlip == 1):
|
||||
newstop_x = job.minx - (stop_x - job.minx)
|
||||
newstop_y = 10*stop_y
|
||||
elif (doFlip == -1):
|
||||
newstop_x = 10*stop_x
|
||||
newstop_y = job.miny - (10*stop_y - job.miny)
|
||||
else:
|
||||
newstop_x = -(10*stop_y - job.miny) + job.minx + offset
|
||||
newstop_y = (10*stop_x - job.minx) + job.miny
|
||||
|
||||
newstop_x = int(round(newstop_x/10.0))
|
||||
newstop_y = int(round(newstop_y/10.0))
|
||||
|
@ -1500,10 +1543,12 @@ def rotateJob(job, degrees = 90, firstpass = True):
|
|||
newstop_y = None
|
||||
J.xcommands[tool].append((newx,newy,newstop_x,newstop_y))
|
||||
|
||||
# Rotate some more if required
|
||||
if (degrees == 0):
|
||||
flip = 0
|
||||
# Rotate or flip some more if required
|
||||
degrees -= 90
|
||||
if degrees > 0:
|
||||
return rotateJob(J, degrees, False)
|
||||
if degrees > 0 or flip != 0:
|
||||
return rotateJob(J, degrees, flip, False)
|
||||
else:
|
||||
##print "rotated:", J.name
|
||||
return J
|
||||
|
|
|
@ -163,21 +163,25 @@ def canonicalizePanel(panel):
|
|||
L = L + job.canonicalize()
|
||||
return L
|
||||
|
||||
def findJob(jobname, rotated, Jobs=config.Jobs):
|
||||
def findJob(jobname, rotatedFlipped, Jobs=config.Jobs):
|
||||
"""
|
||||
Find a job in config.Jobs, possibly rotating it
|
||||
If job not in config.Jobs add it for future reference
|
||||
Return found job
|
||||
"""
|
||||
|
||||
if rotated == 90:
|
||||
fullname = jobname + '*rotated90'
|
||||
elif rotated == 180:
|
||||
fullname = jobname + '*rotated180'
|
||||
elif rotated == 270:
|
||||
fullname = jobname + '*rotated270'
|
||||
else:
|
||||
fullname = jobname
|
||||
fullname = jobname
|
||||
if rotatedFlipped[0] == 90:
|
||||
fullname += '*rotated90'
|
||||
elif rotatedFlipped[0] == 180:
|
||||
fullname += '*rotated180'
|
||||
elif rotatedFlipped[0] == 270:
|
||||
fullname += '*rotated270'
|
||||
if rotatedFlipped[1] == 1:
|
||||
fullname += '*flippedH'
|
||||
elif rotatedFlipped[1] == -1:
|
||||
fullname += '*flippedV'
|
||||
|
||||
|
||||
try:
|
||||
for existingjob in Jobs.keys():
|
||||
|
@ -187,8 +191,8 @@ def findJob(jobname, rotated, Jobs=config.Jobs):
|
|||
except:
|
||||
pass
|
||||
|
||||
# Perhaps we just don't have a rotated job yet
|
||||
if rotated:
|
||||
# Perhaps we just don't have a rotated or flipped job yet
|
||||
if rotatedFlipped[0] or rotatedFlipped[1]:
|
||||
try:
|
||||
for existingjob in Jobs.keys():
|
||||
if existingjob.lower() == jobname.lower(): ## job names are case insensitive
|
||||
|
@ -198,8 +202,8 @@ def findJob(jobname, rotated, Jobs=config.Jobs):
|
|||
else:
|
||||
raise RuntimeError, "Job name '%s' not found" % jobname
|
||||
|
||||
# Make a rotated job
|
||||
job = jobs.rotateJob(job, rotated)
|
||||
# Make a rotated/flipped job
|
||||
job = jobs.rotateJob(job, rotatedFlipped[0], rotatedFlipped[1])
|
||||
Jobs[fullname] = job
|
||||
|
||||
return jobs.JobLayout(job)
|
||||
|
@ -229,7 +233,7 @@ def parseJobSpec(spec, data):
|
|||
else:
|
||||
rotated = 0
|
||||
|
||||
return findJob(jobname, rotated)
|
||||
return findJob(jobname, [rotated, 0])
|
||||
else:
|
||||
raise RuntimeError, "Matrix panels not yet supported"
|
||||
|
||||
|
|
|
@ -89,22 +89,31 @@ class Placement:
|
|||
print 'Illegal (X,Y) co-ordinates in placement file:\n %s' % line
|
||||
sys.exit(1)
|
||||
|
||||
rotated = 0
|
||||
# rotated or flipped
|
||||
rotatedFlipped = [0, 0]
|
||||
|
||||
if len(jobname) > 9:
|
||||
if jobname[-9:] == '*flippedH':
|
||||
rotatedFlipped[1] = 1
|
||||
jobname = jobname[:-9]
|
||||
elif jobname[-9:] == '*flippedV':
|
||||
rotatedFlipped[1] = -1
|
||||
jobname = jobname[:-9]
|
||||
if len(jobname) > 8:
|
||||
if jobname[-8:] == '*rotated':
|
||||
rotated = 90
|
||||
rotatedFlipped[0] = 90
|
||||
jobname = jobname[:-8]
|
||||
elif jobname[-10:] == '*rotated90':
|
||||
rotated = 90
|
||||
rotatedFlipped[0] = 90
|
||||
jobname = jobname[:-10]
|
||||
elif jobname[-11:] == '*rotated180':
|
||||
rotated = 180
|
||||
rotatedFlipped[0] = 180
|
||||
jobname = jobname[:-11]
|
||||
elif jobname[-11:] == '*rotated270':
|
||||
rotated = 270
|
||||
rotatedFlipped[0] = 270
|
||||
jobname = jobname[:-11]
|
||||
|
||||
addjob = parselayout.findJob(jobname, rotated, Jobs)
|
||||
addjob = parselayout.findJob(jobname, rotatedFlipped, Jobs)
|
||||
addjob.setPosition(X,Y)
|
||||
self.jobs.append(addjob)
|
||||
|
||||
|
|
Loading…
Reference in New Issue