chiark / gitweb /
Add proper copyright statements.
[cura.git] / Cura / gui / tools / superformula.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2 from __future__ import absolute_import
3
4 import wx
5 import math
6 import time
7 import random
8 import numpy
9
10 from wx import glcanvas
11 import OpenGL
12 OpenGL.ERROR_CHECKING = False
13 from OpenGL.GL import *
14 from OpenGL.GLU import *
15
16 from Cura.gui.util import opengl
17 from Cura.util import mesh
18
19 class superShape(object):
20         def __init__(self, a1, b1, m1, n11, n21, n31, a2, b2, m2, n12, n22, n32):
21                 self._a1 = a1
22                 self._b1 = b1
23                 self._m1 = math.floor(m1)
24                 self._n11 = n11
25                 self._n21 = n21
26                 self._n31 = n31
27                 self._a2 = a2
28                 self._b2 = b2
29                 self._m2 = m2
30                 self._n12 = n12
31                 self._n22 = n22
32                 self._n32 = n32
33
34                 points = []
35                 cnt = 64
36                 for n in xrange(-cnt, cnt):
37                         row = []
38                         points.append(row)
39                         f1 = n * math.pi / cnt
40                         try:
41                                 r1 = math.pow((math.pow(abs(math.cos(m1*f1/4)/a1),n21) + math.pow(abs(math.sin(m1*f1/4)/b1), n31)), -(1/n11))
42                         except:
43                                 r1 = 1.0
44                         for m in xrange(0, cnt):
45                                 f2 = m * math.pi / ((cnt*2) - 2)
46                                 try:
47                                         r2 = math.pow((math.pow(abs(math.cos(m2*f2/4)/a2),n22) + math.pow(abs(math.sin(m2*f2/4)/b2), n32)), -(1/n12))
48                                 except:
49                                         r2 = 1.0
50
51                                 x = r1 * math.cos(f1) * r2 * math.cos(f2)
52                                 y = r1 * math.sin(f1) * r2 * math.cos(f2)
53                                 z = r2 * math.sin(f2)
54
55                                 row.append([x,y,z])
56
57                 self._obj = mesh.printableObject()
58                 objMesh = self._obj._addMesh()
59                 objMesh._prepareFaceCount(len(points) * (len(points[0]) - 1) * 2)
60
61                 for n in xrange(-1, len(points) - 1):
62                         row1 = points[n]
63                         row2 = points[n+1]
64                         for m in xrange(0, len(row1) - 1):
65                                 p0 = row1[m]
66                                 p1 = row1[m+1]
67                                 p2 = row2[m]
68                                 p3 = row2[m+1]
69
70                                 objMesh._addFace(p0[0], p0[1], p0[2], p2[0], p2[1], p2[2], p1[0], p1[1], p1[2])
71                                 objMesh._addFace(p1[0], p1[1], p1[2], p2[0], p2[1], p2[2], p3[0], p3[1], p3[2])
72
73                 self._obj._postProcessAfterLoad()
74
75         def isValid(self):
76                 size = self._obj.getSize()
77                 if size[0] / size[2] > 10:
78                         return False
79                 return True
80
81         def draw(self):
82                 for m in self._obj._meshList:
83                         if m.vbo is None:
84                                 m.vbo = opengl.GLVBO(m.vertexes, m.normal)
85                         m.vbo.render()
86
87 class superformulaEvolver(wx.Frame):
88         def __init__(self, parent):
89                 super(superformulaEvolver, self).__init__(parent, title='Cura - Superformula')
90                 self._rotate = 0.0
91                 self._t0 = time.time()
92
93                 sizer = wx.BoxSizer()
94                 self.SetSizer(sizer)
95
96                 attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 32, glcanvas.WX_GL_STENCIL_SIZE, 8)
97                 self._glCanvas = glcanvas.GLCanvas(self, style=wx.WANTS_CHARS, attribList = attribList)
98                 self._glCanvas.SetMinSize((800,600))
99                 sizer.Add(self._glCanvas, 1, flag=wx.EXPAND)
100                 self._context = glcanvas.GLContext(self._glCanvas)
101
102                 wx.EVT_PAINT(self._glCanvas, self._OnPaint)
103                 wx.EVT_SIZE(self._glCanvas, self._OnSize)
104                 wx.EVT_ERASE_BACKGROUND(self._glCanvas, self._OnEraseBackground)
105                 wx.EVT_IDLE(self, self._OnIdle)
106
107                 wx.EVT_LEFT_DOWN(self._glCanvas, self._OnMouseDown)
108
109                 self._shapes = [None] * 12
110                 self._releaseList = []
111
112                 self._randomize()
113
114                 self.Maximize()
115
116         def _OnMouseDown(self, e):
117                 size = self._glCanvas.GetSize()
118                 sel = e.GetX() / (size.GetWidth() / 4) + (size.GetHeight() - e.GetY()) / (size.GetHeight() / 3) * 4
119                 shape = self._shapes[sel]
120                 for n in xrange(0, len(self._shapes)):
121                         if n == sel:
122                                 continue
123                         for m in self._shapes[n]._obj._meshList:
124                                 if m.vbo is not None:
125                                         self._releaseList.append(m.vbo)
126                         f = 0.5 + n * 0.1
127                         update = True
128                         while update:
129                                 self._shapes[n] = superShape(
130                                         shape._a1 + random.uniform(-f, f) / 2.0,
131                                         shape._b1 + random.uniform(-f, f) / 2.0,
132                                         shape._m1 + random.uniform(-f, f) * 2.0,
133                                         shape._n11 + random.uniform(-f, f),
134                                         shape._n21 + random.uniform(-f, f),
135                                         shape._n31 + random.uniform(-f, f),
136                                         shape._a2 + random.uniform(-f, f) / 2.0,
137                                         shape._b2 + random.uniform(-f, f) / 2.0,
138                                         shape._m2 + random.uniform(-f, f),
139                                         shape._n12 + random.uniform(-f, f),
140                                         shape._n22 + random.uniform(-f, f),
141                                         shape._n32 + random.uniform(-f, f))
142                                 update = not self._shapes[n].isValid()
143
144         def _randomize(self):
145                 for shape in self._shapes:
146                         if shape is not None:
147                                 for m in shape._obj._meshList:
148                                         if m.vbo is not None:
149                                                 self._releaseList.append(m.vbo)
150                 for n in xrange(0, len(self._shapes)):
151                         update = True
152                         while update:
153                                 self._shapes[n] = superShape(
154                                         random.uniform(0.5, 5.0),
155                                         random.uniform(0.5, 5.0),
156                                         random.uniform(0.5, 20.0),
157                                         random.uniform(0.5, 10.0),
158                                         random.uniform(0.5, 10.0),
159                                         random.uniform(0.5, 10.0),
160                                         random.uniform(0.5, 5.0),
161                                         random.uniform(0.5, 5.0),
162                                         random.uniform(0.5, 10.0),
163                                         random.uniform(0.5, 10.0),
164                                         random.uniform(0.5, 10.0),
165                                         random.uniform(0.5, 10.0))
166                                 update = not self._shapes[n].isValid()
167
168         def _OnEraseBackground(self,event):
169                 #Workaround for windows background redraw flicker.
170                 pass
171
172         def _OnSize(self, e):
173                 self.Refresh()
174
175         def _OnIdle(self, e):
176                 self._glCanvas.Refresh()
177
178         def _OnPaint(self, e):
179                 dc = wx.PaintDC(self._glCanvas)
180
181                 self._glCanvas.SetCurrent(self._context)
182                 for obj in self._releaseList:
183                         obj.release()
184                 self._releaseList = []
185
186                 size = self._glCanvas.GetSize()
187                 glViewport(0, 0, size.GetWidth(), size.GetHeight())
188                 glLoadIdentity()
189
190                 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
191
192                 glDisable(GL_RESCALE_NORMAL)
193                 glDisable(GL_LIGHTING)
194                 glDisable(GL_LIGHT0)
195                 glEnable(GL_DEPTH_TEST)
196                 glDisable(GL_CULL_FACE)
197                 glDisable(GL_BLEND)
198                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
199
200                 glClearColor(0.0, 0.0, 0.0, 1.0)
201                 glClearStencil(0)
202                 glClearDepth(1.0)
203
204                 glMatrixMode(GL_PROJECTION)
205                 glLoadIdentity()
206                 aspect = float(size.GetWidth()) / float(size.GetHeight())
207                 gluPerspective(30.0, aspect, 1.0, 1000.0)
208
209                 glMatrixMode(GL_MODELVIEW)
210                 glLoadIdentity()
211                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
212
213                 glTranslate(0,0,-2.0)
214                 glRotate(-45 - math.sin(self._rotate/50.0) * 30, 1, 0, 0)
215                 glRotate(self._rotate, 0, 0, 1)
216                 self._rotate += (self._t0 - time.time()) * 20
217                 self._t0 = time.time()
218
219                 glEnable(GL_LIGHTING)
220                 glEnable(GL_LIGHT0)
221                 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
222                 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8,1.0,0.8,0])
223                 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.3,0.3,0.3,0])
224                 glEnable(GL_LIGHT1)
225                 glLightfv(GL_LIGHT1, GL_POSITION, [1.2, 0.2, 0.2, 0.0])
226                 glLightfv(GL_LIGHT1, GL_DIFFUSE, [0.5,0.3,0.2,0])
227                 glLightfv(GL_LIGHT1, GL_AMBIENT, [0.0,0.0,0.0,0])
228
229                 for n in xrange(0, len(self._shapes)):
230                         shape = self._shapes[n]
231                         scale = 1.0/numpy.max(shape._obj.getSize())
232                         glPushMatrix()
233                         glScalef(scale, scale, scale)
234                         glEnable(GL_NORMALIZE)
235                         glViewport(size.GetWidth() / 4 * (n % 4), size.GetHeight() / 3 * (n / 4), size.GetWidth() / 4, size.GetHeight() / 3)
236                         shape.draw()
237                         glPopMatrix()
238
239                 glFlush()
240                 self._glCanvas.SwapBuffers()
241
242 class superformulaWindow(wx.Frame):
243         def __init__(self, parent):
244                 super(superformulaWindow, self).__init__(parent, title='Cura - Superformula')
245                 self._rotate = 0.0
246                 self._t0 = time.time()
247
248                 self.panel = wx.Panel(self, -1)
249                 self.SetSizer(wx.BoxSizer())
250                 self.GetSizer().Add(self.panel, 1, wx.EXPAND)
251
252                 sizer = wx.GridBagSizer(2, 2)
253
254                 sizer.Add(wx.StaticText(self.panel, -1, 'A1'), pos=(0,0))
255                 self.sliderA1 = wx.Slider(self.panel, -1, 10, 5, 50, size=(150, -1))
256                 sizer.Add(self.sliderA1, pos=(0,1))
257                 sizer.Add(wx.StaticText(self.panel, -1, 'B1'), pos=(1,0))
258                 self.sliderB1 = wx.Slider(self.panel, -1, 10, 5, 50, size=(150, -1))
259                 sizer.Add(self.sliderB1, pos=(1,1))
260                 sizer.Add(wx.StaticText(self.panel, -1, 'M1'), pos=(2,0))
261                 self.sliderM1 = wx.Slider(self.panel, -1, 50, 5, 200, size=(150, -1))
262                 sizer.Add(self.sliderM1, pos=(2,1))
263                 sizer.Add(wx.StaticText(self.panel, -1, 'N11'), pos=(3,0))
264                 self.sliderN11 = wx.Slider(self.panel, -1, 20, 5, 100, size=(150, -1))
265                 sizer.Add(self.sliderN11, pos=(3,1))
266                 sizer.Add(wx.StaticText(self.panel, -1, 'N21'), pos=(4,0))
267                 self.sliderN21 = wx.Slider(self.panel, -1, 20, 5, 100, size=(150, -1))
268                 sizer.Add(self.sliderN21, pos=(4,1))
269                 sizer.Add(wx.StaticText(self.panel, -1, 'N31'), pos=(5,0))
270                 self.sliderN31 = wx.Slider(self.panel, -1, 20, 5, 100, size=(150, -1))
271                 sizer.Add(self.sliderN31, pos=(5,1))
272
273                 sizer.Add(wx.StaticText(self.panel, -1, 'A2'), pos=(6,0))
274                 self.sliderA2 = wx.Slider(self.panel, -1, 10, 5, 50, size=(150, -1))
275                 sizer.Add(self.sliderA2, pos=(6,1))
276                 sizer.Add(wx.StaticText(self.panel, -1, 'B2'), pos=(7,0))
277                 self.sliderB2 = wx.Slider(self.panel, -1, 10, 5, 50, size=(150, -1))
278                 sizer.Add(self.sliderB2, pos=(7,1))
279                 sizer.Add(wx.StaticText(self.panel, -1, 'M2'), pos=(8,0))
280                 self.sliderM2 = wx.Slider(self.panel, -1, 20, 5, 100, size=(150, -1))
281                 sizer.Add(self.sliderM2, pos=(8,1))
282                 sizer.Add(wx.StaticText(self.panel, -1, 'N12'), pos=(9,0))
283                 self.sliderN12 = wx.Slider(self.panel, -1, 20, 5, 100, size=(150, -1))
284                 sizer.Add(self.sliderN12, pos=(9,1))
285                 sizer.Add(wx.StaticText(self.panel, -1, 'N22'), pos=(10,0))
286                 self.sliderN22 = wx.Slider(self.panel, -1, 20, 5, 100, size=(150, -1))
287                 sizer.Add(self.sliderN22, pos=(10,1))
288                 sizer.Add(wx.StaticText(self.panel, -1, 'N32'), pos=(11,0))
289                 self.sliderN32 = wx.Slider(self.panel, -1, 20, 5, 100, size=(150, -1))
290                 sizer.Add(self.sliderN32, pos=(11,1))
291
292                 self.randomButton = wx.Button(self.panel, -1, 'Randomize')
293                 sizer.Add(self.randomButton, pos=(12,1))
294                 self.addButton = wx.Button(self.panel, -1, 'Add to print')
295                 sizer.Add(self.addButton, pos=(13,1))
296
297                 attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 32, glcanvas.WX_GL_STENCIL_SIZE, 8)
298                 self._glCanvas = glcanvas.GLCanvas(self.panel, style=wx.WANTS_CHARS, attribList = attribList)
299                 self._glCanvas.SetMinSize((800,600))
300                 sizer.Add(self._glCanvas, pos=(0,2), span=(14,1), flag=wx.EXPAND)
301                 self._context = glcanvas.GLContext(self._glCanvas)
302
303                 sizer.AddGrowableRow(13)
304                 sizer.AddGrowableCol(2)
305                 self.panel.SetSizer(sizer)
306                 self.Layout()
307                 self.Fit()
308
309                 wx.EVT_PAINT(self._glCanvas, self._OnPaint)
310                 wx.EVT_SIZE(self._glCanvas, self._OnSize)
311                 wx.EVT_ERASE_BACKGROUND(self._glCanvas, self._OnEraseBackground)
312                 wx.EVT_IDLE(self, self._OnIdle)
313
314                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderA1)
315                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderB1)
316                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderM1)
317                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderN11)
318                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderN21)
319                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderN31)
320
321                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderA2)
322                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderB2)
323                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderM2)
324                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderN12)
325                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderN22)
326                 self.Bind(wx.EVT_SLIDER, lambda e: self._updateShape(), self.sliderN32)
327
328                 self.Bind(wx.EVT_BUTTON, lambda e: self.onRandom(), self.randomButton)
329                 self.Bind(wx.EVT_BUTTON, lambda e: self.onAdd(), self.addButton)
330
331                 self._shape = None
332                 self._releaseList = []
333                 self._updateShape()
334
335         def onRandom(self):
336                 update = True
337                 while update:
338                         update = False
339                         self.sliderA1.SetValue(random.randint(self.sliderA1.GetMin(), self.sliderA1.GetMax()))
340                         self.sliderB1.SetValue(random.randint(self.sliderB1.GetMin(), self.sliderB1.GetMax()))
341                         self.sliderM1.SetValue(random.randint(self.sliderM1.GetMin(), self.sliderM1.GetMax()))
342                         self.sliderN11.SetValue(random.randint(self.sliderN11.GetMin(), self.sliderN11.GetMax()))
343                         self.sliderN21.SetValue(random.randint(self.sliderN21.GetMin(), self.sliderN21.GetMax()))
344                         self.sliderN31.SetValue(random.randint(self.sliderN31.GetMin(), self.sliderN31.GetMax()))
345                         self.sliderA2.SetValue(random.randint(self.sliderA2.GetMin(), self.sliderA2.GetMax()))
346                         self.sliderB2.SetValue(random.randint(self.sliderB2.GetMin(), self.sliderB2.GetMax()))
347                         self.sliderM2.SetValue(random.randint(self.sliderM2.GetMin(), self.sliderM2.GetMax()))
348                         self.sliderN12.SetValue(random.randint(self.sliderN12.GetMin(), self.sliderN12.GetMax()))
349                         self.sliderN22.SetValue(random.randint(self.sliderN22.GetMin(), self.sliderN22.GetMax()))
350                         self.sliderN32.SetValue(random.randint(self.sliderN32.GetMin(), self.sliderN32.GetMax()))
351                         self._updateShape()
352                         if not self._shape.isValid():
353                                 update = True
354
355         def onAdd(self):
356                 scale = 1.0/numpy.max(self._shape._obj.getSize()) * 50
357
358                 obj = mesh.printableObject()
359                 m = obj._addMesh()
360                 m._prepareFaceCount(self._shape._obj._meshList[0].vertexCount / 3)
361                 m.vertexes = self._shape._obj._meshList[0].vertexes * scale
362                 m.vertexCount = self._shape._obj._meshList[0].vertexCount
363                 obj._postProcessAfterLoad()
364                 self.GetParent().scene._scene.add(obj)
365                 self.GetParent().scene.sceneUpdated()
366
367         def _updateShape(self):
368                 if self._shape is not None:
369                         for m in self._shape._obj._meshList:
370                                 if m.vbo is not None:
371                                         self._releaseList.append(m.vbo)
372                 self._shape = superShape(
373                         float(self.sliderA1.GetValue()) / 10.0,
374                         float(self.sliderB1.GetValue()) / 10.0,
375                         float(self.sliderM1.GetValue()) / 10.0,
376
377                         float(self.sliderN11.GetValue()) / 10.0,
378                         float(self.sliderN21.GetValue()) / 10.0,
379                         float(self.sliderN31.GetValue()) / 10.0,
380
381                         float(self.sliderA2.GetValue()) / 10.0,
382                         float(self.sliderB2.GetValue()) / 10.0,
383                         float(self.sliderM2.GetValue()) / 10.0,
384
385                         float(self.sliderN12.GetValue()) / 10.0,
386                         float(self.sliderN22.GetValue()) / 10.0,
387                         float(self.sliderN32.GetValue()) / 10.0,
388                 )
389
390         def _OnEraseBackground(self,event):
391                 #Workaround for windows background redraw flicker.
392                 pass
393
394         def _OnSize(self, e):
395                 self.Refresh()
396
397         def _OnIdle(self, e):
398                 self._glCanvas.Refresh()
399
400         def _OnPaint(self, e):
401                 dc = wx.PaintDC(self._glCanvas)
402
403                 self._glCanvas.SetCurrent(self._context)
404                 for obj in self._releaseList:
405                         obj.release()
406                 self._releaseList = []
407
408                 size = self._glCanvas.GetSize()
409                 glViewport(0, 0, size.GetWidth(), size.GetHeight())
410                 glLoadIdentity()
411
412                 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
413
414                 glDisable(GL_RESCALE_NORMAL)
415                 glDisable(GL_LIGHTING)
416                 glDisable(GL_LIGHT0)
417                 glEnable(GL_DEPTH_TEST)
418                 glDisable(GL_CULL_FACE)
419                 glDisable(GL_BLEND)
420                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
421
422                 glClearColor(0.0, 0.0, 0.0, 1.0)
423                 glClearStencil(0)
424                 glClearDepth(1.0)
425
426                 glMatrixMode(GL_PROJECTION)
427                 glLoadIdentity()
428                 aspect = float(size.GetWidth()) / float(size.GetHeight())
429                 gluPerspective(45.0, aspect, 1.0, 1000.0)
430
431                 glMatrixMode(GL_MODELVIEW)
432                 glLoadIdentity()
433                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
434
435                 glTranslate(0,0,-2)
436                 glRotate(-45 - math.sin(self._rotate/50.0) * 30, 1, 0, 0)
437                 glRotate(self._rotate, 0, 0, 1)
438                 self._rotate += (self._t0 - time.time()) * 20
439                 self._t0 = time.time()
440
441                 glEnable(GL_LIGHTING)
442                 glEnable(GL_LIGHT0)
443                 glLightfv(GL_LIGHT0, GL_POSITION, [0.2, 0.2, 1.0, 0.0])
444                 glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.8,1.0,0.8,0])
445                 glLightfv(GL_LIGHT0, GL_AMBIENT, [0.3,0.3,0.3,0])
446                 glEnable(GL_LIGHT1)
447                 glLightfv(GL_LIGHT1, GL_POSITION, [1.2, 0.2, 0.2, 0.0])
448                 glLightfv(GL_LIGHT1, GL_DIFFUSE, [0.5,0.3,0.2,0])
449                 glLightfv(GL_LIGHT1, GL_AMBIENT, [0.0,0.0,0.0,0])
450
451                 scale = 1.0/numpy.max(self._shape._obj.getSize())
452                 glScalef(scale, scale, scale)
453                 glEnable(GL_NORMALIZE)
454
455                 self._shape.draw()
456
457                 glFlush()
458                 self._glCanvas.SwapBuffers()