Merge pull request #2 from andreika-git/master

sync up
This commit is contained in:
rusefillc 2022-01-14 11:35:09 -05:00 committed by GitHub
commit fa7862ec0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 145 additions and 75 deletions

View File

@ -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')

View File

@ -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):

View File

@ -1337,26 +1337,46 @@ 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
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 +1403,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 +1472,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 +1510,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.maxx - (10*x - job.minx)
newy = 10*y
elif (doFlip == -1):
newx = 10*x
newy = job.maxy - (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.maxx - (10*stop_x - job.minx)
newstop_y = 10*stop_y
elif (doFlip == -1):
newstop_x = 10*stop_x
newstop_y = job.maxy - (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 +1541,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

View File

@ -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"

View File

@ -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)