Commit 762b76f7 authored by Travis Howse's avatar Travis Howse

Added new autoplate function

Crudely arranges the added STLs on the bed. Does not attempt to optimise for
space or anything, just arranges them in a rough grid.
parent 2704c88d
...@@ -3,262 +3,294 @@ import wx,time,random,threading,os,math ...@@ -3,262 +3,294 @@ import wx,time,random,threading,os,math
import stltool import stltool
class stlwrap: class stlwrap:
def __init__(self,obj,name=None): def __init__(self,obj,name=None):
self.obj=obj self.obj=obj
self.name=name self.name=name
if name is None: if name is None:
self.name=obj.name self.name=obj.name
def __repr__(self): def __repr__(self):
return self.name return self.name
class showstl(wx.Window): class showstl(wx.Window):
def __init__(self,parent,size,pos): def __init__(self,parent,size,pos):
wx.Window.__init__(self,parent,size=size,pos=pos) wx.Window.__init__(self,parent,size=size,pos=pos)
self.l=wx.ListCtrl(self,style=wx.LC_LIST,size=(300,130),pos=(0,size[1]-130)) self.l=wx.ListCtrl(self,style=wx.LC_LIST,size=(300,130),pos=(0,size[1]-130))
self.eb=wx.Button(self,label="Export",pos=(300,size[1]-130)) self.eb=wx.Button(self,label="Export",pos=(300,size[1]-130))
self.sb=wx.Button(self,label="Snap to Z=0",pos=(300,size[1]-100)) self.sb=wx.Button(self,label="Snap to Z=0",pos=(300,size[1]-105))
self.cb=wx.Button(self,label="Put at 100,100",pos=(300,size[1]-70)) self.cb=wx.Button(self,label="Put at 100,100",pos=(300,size[1]-80))
self.db=wx.Button(self,label="Delete",pos=(300,size[1]-40)) self.db=wx.Button(self,label="Delete",pos=(300,size[1]-55))
self.eb.Bind(wx.EVT_BUTTON,self.export) self.ab=wx.Button(self,label="Auto",pos=(300,size[1]-30))
self.sb.Bind(wx.EVT_BUTTON,self.snap) self.eb.Bind(wx.EVT_BUTTON,self.export)
self.cb.Bind(wx.EVT_BUTTON,self.center) self.sb.Bind(wx.EVT_BUTTON,self.snap)
self.db.Bind(wx.EVT_BUTTON,self.delete) self.cb.Bind(wx.EVT_BUTTON,self.center)
#self.SetBackgroundColour((0,0,0)) self.db.Bind(wx.EVT_BUTTON,self.delete)
#wx.FutureCall(200,self.paint) self.ab.Bind(wx.EVT_BUTTON,self.autoplate)
self.i=0 #self.SetBackgroundColour((0,0,0))
self.previ=0 #wx.FutureCall(200,self.paint)
self.Bind(wx.EVT_MOUSEWHEEL,self.rot) self.i=0
self.Bind(wx.EVT_MOUSE_EVENTS,self.move) self.previ=0
self.Bind(wx.EVT_PAINT,self.repaint) self.Bind(wx.EVT_MOUSEWHEEL,self.rot)
#self.s=stltool.stl("sphere.stl").scale([2,1,1]) self.Bind(wx.EVT_MOUSE_EVENTS,self.move)
self.triggered=0 self.Bind(wx.EVT_PAINT,self.repaint)
self.models={} #self.s=stltool.stl("sphere.stl").scale([2,1,1])
self.basedir="." self.triggered=0
self.initpos=None self.models={}
self.prevsel=-1 self.basedir="."
self.initpos=None
self.prevsel=-1
def center(self,event): def center(self,event):
i=self.l.GetFirstSelected() i=self.l.GetFirstSelected()
if i != -1: if i != -1:
m=self.models[self.l.GetItemText(i)] m=self.models[self.l.GetItemText(i)]
m.offsets=[100,100,m.offsets[2]] m.offsets=[100,100,m.offsets[2]]
self.Refresh() self.Refresh()
def snap(self,event): def snap(self,event):
i=self.l.GetFirstSelected() i=self.l.GetFirstSelected()
if i != -1: if i != -1:
m=self.models[self.l.GetItemText(i)] m=self.models[self.l.GetItemText(i)]
m.offsets[2]=-1.0*min(m.facetsminz)[0] m.offsets[2]=-1.0*min(m.facetsminz)[0]
#print m.offsets[2] #print m.offsets[2]
self.Refresh() self.Refresh()
def delete(self,event): def delete(self,event):
i=self.l.GetFirstSelected() i=self.l.GetFirstSelected()
if i != -1: if i != -1:
del self.models[self.l.GetItemText(i)] del self.models[self.l.GetItemText(i)]
self.l.DeleteItem(i) self.l.DeleteItem(i)
self.l.Select(self.l.GetItemCount()-1) self.l.Select(self.l.GetItemCount()-1)
self.Refresh() self.Refresh()
def export(self,event): def export(self,event):
dlg=wx.FileDialog(self,"Pick file to save to",self.basedir,style=wx.FD_SAVE) dlg=wx.FileDialog(self,"Pick file to save to",self.basedir,style=wx.FD_SAVE)
dlg.SetWildcard("STL files (;*.stl;)") dlg.SetWildcard("STL files (;*.stl;)")
if(dlg.ShowModal() == wx.ID_OK): if(dlg.ShowModal() == wx.ID_OK):
name=dlg.GetPath() name=dlg.GetPath()
facets=[] facets=[]
for i in self.models.values(): for i in self.models.values():
r=i.rot r=i.rot
o=i.offsets o=i.offsets
if r != 0: if r != 0:
i=i.rotate([0,0,-r]) i=i.rotate([0,0,-r])
if o != [0,0,0]: if o != [0,0,0]:
i=i.translate([o[0],-o[1],o[2]]) i=i.translate([o[0],-o[1],o[2]])
facets+=i.facets facets+=i.facets
stltool.emitstl(name,facets,"plater_export") stltool.emitstl(name,facets,"plater_export")
print "wrote ",name print "wrote ",name
def autoplate(self,event):
def right(self,event): print "Autoplating"
dlg=wx.FileDialog(self,"Open file to print",self.basedir,style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) separation = 2
dlg.SetWildcard("STL files (;*.stl;)") bedsize = [200,200,100]
if(dlg.ShowModal() == wx.ID_OK): cursor = [0,0,0]
name=dlg.GetPath() newrow = 0
if not(os.path.exists(name)): for i in self.models:
return x = abs(self.models[i].dims[0] - self.models[i].dims[1])
path = os.path.split(name)[0] y = abs(self.models[i].dims[2] - self.models[i].dims[3])
self.basedir=path centre = [x/2, y/2]
t=time.time() centreoffset = [self.models[i].dims[0] + centre[0], self.models[i].dims[2] + centre[1]]
#print name if (newrow == 0) or (newrow < y):
if name.lower().endswith(".stl"): newrow = y
newname=name #To the person who works out why the offsets are applied differently here:
c=1 # Good job, it confused the hell out of me.
while newname in self.models: self.models[i].offsets[0] = cursor[0] + centre[0] - centreoffset[0]
newname=name+"(%d)"%c self.models[i].offsets[1] = cursor[1] + centre[1] + centreoffset[1]
c+=1 cursor[0] += x+separation
self.models[newname]=stltool.stl(name) if cursor[0] >= bedsize[0]:
self.models[newname].offsets=[0,0,0] cursor[0] = 0
self.models[newname].rot=0 cursor[1] += newrow+separation
minx,miny,minz,maxx,maxy,maxz=(10000,10000,10000,0,0,0) newrow = 0
for i in self.models[newname].facets: self.models[i].offsets[0] = cursor[0] + centre[0] - centreoffset[0]
for j in i[1]: self.models[i].offsets[1] = cursor[1] + centre[1] + centreoffset[1]
if j[0]<minx: cursor[0] += x+separation
minx=j[0] if (cursor[1]+y) >= bedsize[1]:
if j[1]<miny: print "Bed full, sorry sir :("
miny=j[1] self.Refresh()
if j[2]<minz: return
minz=j[2] self.Refresh()
if j[0]>maxx:
maxx=j[0] def right(self,event):
if j[1]>maxy: dlg=wx.FileDialog(self,"Open file to print",self.basedir,style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
maxy=j[1] dlg.SetWildcard("STL files (;*.stl;)")
if j[2]>maxz: if(dlg.ShowModal() == wx.ID_OK):
maxz=j[2] name=dlg.GetPath()
self.models[newname].dims=[minx,maxx,miny,maxy,minz,maxz] if not(os.path.exists(name)):
#if minx<0: return
# self.models[newname].offsets[0]=-minx path = os.path.split(name)[0]
#if miny<0: self.basedir=path
# self.models[newname].offsets[1]=-miny t=time.time()
self.models[newname].bitmap=wx.EmptyBitmap(800,800,32) #print name
dc=wx.MemoryDC() if name.lower().endswith(".stl"):
dc.SelectObject(self.models[newname].bitmap) newname=name
dc.SetBackground(wx.Brush((0,0,0,0))) c=1
dc.SetBrush(wx.Brush((0,0,0,255))) while newname in self.models:
#dc.DrawRectangle(-1,-1,10000,10000) newname=name+"(%d)"%c
dc.SetBrush(wx.Brush(wx.Colour(128,255,128))) c+=1
dc.SetPen(wx.Pen(wx.Colour(128,128,128))) self.models[newname]=stltool.stl(name)
m=self.models[newname] self.models[newname].offsets=[0,0,0]
#m.offsets=[10,10,0] self.models[newname].rot=0
print m.offsets,m.dims minx,miny,minz,maxx,maxy,maxz=(10000,10000,10000,0,0,0)
scale=2 for i in self.models[newname].facets:
for i in m.facets:#random.sample(m.facets,min(100000,len(m.facets))): for j in i[1]:
dc.DrawPolygon([wx.Point(400+scale*p[0],(400+scale*p[1])) for p in i[1]]) if j[0]<minx:
#if(time.time()-t)>5: minx=j[0]
# break if j[1]<miny:
dc.SelectObject(wx.NullBitmap) miny=j[1]
m.bitmap.SetMask(wx.Mask(m.bitmap,wx.Colour(0,0,0,255))) if j[2]<minz:
minz=j[2]
#print time.time()-t if j[0]>maxx:
self.l.Append([stlwrap(self.models[newname],newname)]) maxx=j[0]
i=self.l.GetFirstSelected() if j[1]>maxy:
if i != -1: maxy=j[1]
self.l.Select(i,0) if j[2]>maxz:
maxz=j[2]
self.l.Select(self.l.GetItemCount()-1) self.models[newname].dims=[minx,maxx,miny,maxy,minz,maxz]
self.Refresh() #if minx<0:
#print time.time()-t # self.models[newname].offsets[0]=-minx
#if miny<0:
def move(self,event): # self.models[newname].offsets[1]=-miny
if event.ButtonUp(wx.MOUSE_BTN_LEFT): self.models[newname].bitmap=wx.EmptyBitmap(800,800,32)
if(self.initpos is not None): dc=wx.MemoryDC()
i=self.l.GetFirstSelected() dc.SelectObject(self.models[newname].bitmap)
if i != -1: dc.SetBackground(wx.Brush((0,0,0,0)))
p=event.GetPositionTuple() dc.SetBrush(wx.Brush((0,0,0,255)))
#print (p[0]-self.initpos[0]),(p[1]-self.initpos[1]) #dc.DrawRectangle(-1,-1,10000,10000)
t=time.time() dc.SetBrush(wx.Brush(wx.Colour(128,255,128)))
m=self.models[self.l.GetItemText(i)] dc.SetPen(wx.Pen(wx.Colour(128,128,128)))
m.offsets=[m.offsets[0]+0.5*(p[0]-self.initpos[0]),m.offsets[1]-0.5*(p[1]-self.initpos[1]),m.offsets[2]] m=self.models[newname]
#self.models[self.l.GetItemText(i)]=self.models[self.l.GetItemText(i)].translate([0.5*(p[0]-self.initpos[0]),0.5*(p[1]-self.initpos[1]),0]) #m.offsets=[10,10,0]
#print time.time()-t print m.offsets,m.dims
self.Refresh() scale=2
self.initpos=None for i in m.facets:#random.sample(m.facets,min(100000,len(m.facets))):
elif event.ButtonDown(wx.MOUSE_BTN_RIGHT): dc.DrawPolygon([wx.Point(400+scale*p[0],(400+scale*p[1])) for p in i[1]])
self.right(event) #if(time.time()-t)>5:
elif event.Dragging(): # break
if self.initpos is None: dc.SelectObject(wx.NullBitmap)
self.initpos=event.GetPositionTuple() m.bitmap.SetMask(wx.Mask(m.bitmap,wx.Colour(0,0,0,255)))
self.Refresh()
dc=wx.ClientDC(self) #print time.time()-t
p=event.GetPositionTuple() self.l.Append([stlwrap(self.models[newname],newname)])
dc.DrawLine(self.initpos[0],self.initpos[1],p[0],p[1]) i=self.l.GetFirstSelected()
#print math.sqrt((p[0]-self.initpos[0])**2+(p[1]-self.initpos[1])**2) if i != -1:
self.l.Select(i,0)
del dc
else: self.l.Select(self.l.GetItemCount()-1)
event.Skip() self.Refresh()
#print time.time()-t
def rotateafter(self): def move(self,event):
if(self.i!=self.previ): if event.ButtonUp(wx.MOUSE_BTN_LEFT):
i=self.l.GetFirstSelected() if(self.initpos is not None):
if i != -1: i=self.l.GetFirstSelected()
#o=self.models[self.l.GetItemText(i)].offsets if i != -1:
self.models[self.l.GetItemText(i)].rot+=5*(self.i-self.previ) p=event.GetPositionTuple()
#self.models[self.l.GetItemText(i)].offsets=o #print (p[0]-self.initpos[0]),(p[1]-self.initpos[1])
self.previ=self.i t=time.time()
self.Refresh() m=self.models[self.l.GetItemText(i)]
def cr(self): m.offsets=[m.offsets[0]+0.5*(p[0]-self.initpos[0]),m.offsets[1]-0.5*(p[1]-self.initpos[1]),m.offsets[2]]
time.sleep(0.01) #self.models[self.l.GetItemText(i)]=self.models[self.l.GetItemText(i)].translate([0.5*(p[0]-self.initpos[0]),0.5*(p[1]-self.initpos[1]),0])
wx.CallAfter(self.rotateafter) #print time.time()-t
self.triggered=0 self.Refresh()
self.initpos=None
def rot(self, event): elif event.ButtonDown(wx.MOUSE_BTN_RIGHT):
z=event.GetWheelRotation() self.right(event)
s=self.l.GetFirstSelected() elif event.Dragging():
if self.prevsel!=s: if self.initpos is None:
self.i=0 self.initpos=event.GetPositionTuple()
self.prevsel=s self.Refresh()
if z > 0: dc=wx.ClientDC(self)
self.i-=1 p=event.GetPositionTuple()
else: dc.DrawLine(self.initpos[0],self.initpos[1],p[0],p[1])
self.i+=1 #print math.sqrt((p[0]-self.initpos[0])**2+(p[1]-self.initpos[1])**2)
if not self.triggered:
self.triggered=1 del dc
threading.Thread(target=self.cr).start() else:
event.Skip()
def repaint(self,event):
dc=wx.PaintDC(self)
self.paint(dc=dc) def rotateafter(self):
if(self.i!=self.previ):
def paint(self,coord1="x",coord2="y",dc=None): i=self.l.GetFirstSelected()
coords={"x":0,"y":1,"z":2} if i != -1:
if dc is None: #o=self.models[self.l.GetItemText(i)].offsets
dc=wx.ClientDC(self) self.models[self.l.GetItemText(i)].rot+=5*(self.i-self.previ)
offset=[0,0] #self.models[self.l.GetItemText(i)].offsets=o
scale=2 self.previ=self.i
dc.SetPen(wx.Pen(wx.Colour(100,100,100))) self.Refresh()
for i in xrange(20): def cr(self):
dc.DrawLine(0,i*scale*10,400,i*scale*10) time.sleep(0.01)
dc.DrawLine(i*scale*10,0,i*scale*10,400) wx.CallAfter(self.rotateafter)
dc.SetPen(wx.Pen(wx.Colour(0,0,0))) self.triggered=0
for i in xrange(4):
dc.DrawLine(0,i*scale*50,400,i*scale*50) def rot(self, event):
dc.DrawLine(i*scale*50,0,i*scale*50,400) z=event.GetWheelRotation()
dc.SetBrush(wx.Brush(wx.Colour(128,255,128))) s=self.l.GetFirstSelected()
dc.SetPen(wx.Pen(wx.Colour(128,128,128))) if self.prevsel!=s:
t=time.time() self.i=0
dcs=wx.MemoryDC() self.prevsel=s
for m in self.models.values(): if z > 0:
b=m.bitmap self.i-=1
#print b else:
im=b.ConvertToImage() self.i+=1
#print im if not self.triggered:
imgc = wx.Point( im.GetWidth()/2,im.GetHeight()/2 ) self.triggered=1
#print math.radians(5*(self.i-self.previ)) threading.Thread(target=self.cr).start()
im= im.Rotate( math.radians(m.rot), imgc, 0)
bm=wx.BitmapFromImage(im) def repaint(self,event):
dcs.SelectObject(bm) dc=wx.PaintDC(self)
bsz=bm.GetSize() self.paint(dc=dc)
dc.Blit(scale*m.offsets[0]-bsz[0]/2,400-(scale*m.offsets[1]+bsz[1]/2),bsz[0],bsz[1],dcs,0,0,useMask=1)
#for i in m.facets:#random.sample(m.facets,min(100000,len(m.facets))): def paint(self,coord1="x",coord2="y",dc=None):
# dc.DrawPolygon([wx.Point(offset[0]+scale*m.offsets[0]+scale*p[0],400-(offset[1]+scale*m.offsets[1]+scale*p[1])) for p in i[1]]) coords={"x":0,"y":1,"z":2}
#if(time.time()-t)>5: if dc is None:
# break dc=wx.ClientDC(self)
del dc offset=[0,0]
#print time.time()-t scale=2
#s.export() dc.SetPen(wx.Pen(wx.Colour(100,100,100)))
for i in xrange(20):
dc.DrawLine(0,i*scale*10,400,i*scale*10)
dc.DrawLine(i*scale*10,0,i*scale*10,400)
dc.SetPen(wx.Pen(wx.Colour(0,0,0)))
for i in xrange(4):
dc.DrawLine(0,i*scale*50,400,i*scale*50)
dc.DrawLine(i*scale*50,0,i*scale*50,400)
dc.SetBrush(wx.Brush(wx.Colour(128,255,128)))
dc.SetPen(wx.Pen(wx.Colour(128,128,128)))
t=time.time()
dcs=wx.MemoryDC()
for m in self.models.values():
b=m.bitmap
#print b
im=b.ConvertToImage()
#print im
imgc = wx.Point( im.GetWidth()/2,im.GetHeight()/2 )
#print math.radians(5*(self.i-self.previ))
im= im.Rotate( math.radians(m.rot), imgc, 0)
bm=wx.BitmapFromImage(im)
dcs.SelectObject(bm)
bsz=bm.GetSize()
dc.Blit(scale*m.offsets[0]-bsz[0]/2,400-(scale*m.offsets[1]+bsz[1]/2),bsz[0],bsz[1],dcs,0,0,useMask=1)
#for i in m.facets:#random.sample(m.facets,min(100000,len(m.facets))):
# dc.DrawPolygon([wx.Point(offset[0]+scale*m.offsets[0]+scale*p[0],400-(offset[1]+scale*m.offsets[1]+scale*p[1])) for p in i[1]])
#if(time.time()-t)>5:
# break
del dc
#print time.time()-t
#s.export()
class stlwin(wx.Frame): class stlwin(wx.Frame):
def __init__(self,size=(400,530)): def __init__(self,size=(400,530)):
wx.Frame.__init__(self,None,title="Right-click to add a file",size=size) wx.Frame.__init__(self,None,title="Right-click to add a file",size=size)
self.SetIcon(wx.Icon("plater.ico",wx.BITMAP_TYPE_ICO)) self.SetIcon(wx.Icon("plater.ico",wx.BITMAP_TYPE_ICO))
self.SetClientSize(size) self.SetClientSize(size)
self.s=showstl(self,(400,530),(0,0)) self.s=showstl(self,(400,530),(0,0))
if __name__ == '__main__': if __name__ == '__main__':
app = wx.App(False) app = wx.App(False)
main = stlwin() main = stlwin()
main.Show() main.Show()
app.MainLoop() app.MainLoop()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment