chiark / gitweb /
Fix the number display on the scale tool, and make the scaling ticks depend on the...
[cura.git] / Cura / gui / util / previewTools.py
1 from __future__ import absolute_import
2
3 import math
4 import wx
5 import numpy
6
7 import OpenGL
8 OpenGL.ERROR_CHECKING = False
9 from OpenGL.GLU import *
10 from OpenGL.GL import *
11
12 from Cura.gui.util import opengl
13
14 class toolNone(object):
15         def __init__(self, parent):
16                 self.parent = parent
17
18         def OnMouseMove(self, p0, p1):
19                 pass
20
21         def OnDragStart(self, p0, p1):
22                 return False
23
24         def OnDrag(self, p0, p1):
25                 pass
26
27         def OnDragEnd(self):
28                 pass
29
30         def OnDraw(self):
31                 pass
32
33 class toolInfo(object):
34         def __init__(self, parent):
35                 self.parent = parent
36
37         def OnMouseMove(self, p0, p1):
38                 pass
39
40         def OnDragStart(self, p0, p1):
41                 return False
42
43         def OnDrag(self, p0, p1):
44                 pass
45
46         def OnDragEnd(self):
47                 pass
48
49         def OnDraw(self):
50                 glDisable(GL_LIGHTING)
51                 glDisable(GL_BLEND)
52                 glDisable(GL_DEPTH_TEST)
53                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
54                 glColor3ub(0,0,0)
55                 size = self.parent.getObjectSize()
56                 radius = self.parent.getObjectBoundaryCircle()
57                 glPushMatrix()
58                 glTranslate(0,0,size[2]/2 + 5)
59                 glRotate(-self.parent.yaw, 0,0,1)
60                 if self.parent.pitch < 80:
61                         glTranslate(0, radius + 5,0)
62                 elif self.parent.pitch < 100:
63                         glTranslate(0, (radius + 5) * (90 - self.parent.pitch) / 10,0)
64                 else:
65                         glTranslate(0,-(radius + 5),0)
66                 opengl.glDrawStringCenter("%dx%dx%d" % (size[0], size[1], size[2]))
67                 glPopMatrix()
68
69                 glColor(255,255,255)
70                 size = size / 2
71                 glLineWidth(1)
72                 glBegin(GL_LINES)
73                 glVertex3f(size[0], size[1], size[2])
74                 glVertex3f(size[0], size[1], size[2]/4*3)
75                 glVertex3f(size[0], size[1], size[2])
76                 glVertex3f(size[0], size[1]/4*3, size[2])
77                 glVertex3f(size[0], size[1], size[2])
78                 glVertex3f(size[0]/4*3, size[1], size[2])
79
80                 glVertex3f(-size[0], -size[1], size[2])
81                 glVertex3f(-size[0], -size[1], size[2]/4*3)
82                 glVertex3f(-size[0], -size[1], size[2])
83                 glVertex3f(-size[0], -size[1]/4*3, size[2])
84                 glVertex3f(-size[0], -size[1], size[2])
85                 glVertex3f(-size[0]/4*3, -size[1], size[2])
86
87                 glVertex3f(size[0], -size[1], -size[2])
88                 glVertex3f(size[0], -size[1], -size[2]/4*3)
89                 glVertex3f(size[0], -size[1], -size[2])
90                 glVertex3f(size[0], -size[1]/4*3, -size[2])
91                 glVertex3f(size[0], -size[1], -size[2])
92                 glVertex3f(size[0]/4*3, -size[1], -size[2])
93
94                 glVertex3f(-size[0], size[1], -size[2])
95                 glVertex3f(-size[0], size[1], -size[2]/4*3)
96                 glVertex3f(-size[0], size[1], -size[2])
97                 glVertex3f(-size[0], size[1]/4*3, -size[2])
98                 glVertex3f(-size[0], size[1], -size[2])
99                 glVertex3f(-size[0]/4*3, size[1], -size[2])
100                 glEnd()
101
102 class toolRotate(object):
103         def __init__(self, parent):
104                 self.parent = parent
105                 self.rotateRingDist = 1.5
106                 self.rotateRingDistMin = 1.3
107                 self.rotateRingDistMax = 1.7
108                 self.dragPlane = None
109                 self.dragStartAngle = None
110                 self.dragEndAngle = None
111
112         def _ProjectToPlanes(self, p0, p1):
113                 cursorX0 = p0 - (p1 - p0) * (p0[0] / (p1[0] - p0[0]))
114                 cursorY0 = p0 - (p1 - p0) * (p0[1] / (p1[1] - p0[1]))
115                 cursorZ0 = p0 - (p1 - p0) * (p0[2] / (p1[2] - p0[2]))
116                 cursorYZ = math.sqrt((cursorX0[1] * cursorX0[1]) + (cursorX0[2] * cursorX0[2]))
117                 cursorXZ = math.sqrt((cursorY0[0] * cursorY0[0]) + (cursorY0[2] * cursorY0[2]))
118                 cursorXY = math.sqrt((cursorZ0[0] * cursorZ0[0]) + (cursorZ0[1] * cursorZ0[1]))
119                 return cursorX0, cursorY0, cursorZ0, cursorYZ, cursorXZ, cursorXY
120
121         def OnMouseMove(self, p0, p1):
122                 radius = self.parent.getObjectBoundaryCircle()
123                 cursorX0, cursorY0, cursorZ0, cursorYZ, cursorXZ, cursorXY = self._ProjectToPlanes(p0, p1)
124                 oldDragPlane = self.dragPlane
125                 if radius * self.rotateRingDistMin <= cursorXY <= radius * self.rotateRingDistMax or radius * self.rotateRingDistMin <= cursorYZ <= radius * self.rotateRingDistMax or radius * self.rotateRingDistMin <= cursorXZ <= radius * self.rotateRingDistMax:
126                         self.parent.SetCursor(wx.StockCursor(wx.CURSOR_SIZING))
127                         if self.dragStartAngle is None:
128                                 if radius * self.rotateRingDistMin <= cursorXY <= radius * self.rotateRingDistMax:
129                                         self.dragPlane = 'XY'
130                                 elif radius * self.rotateRingDistMin <= cursorXZ <= radius * self.rotateRingDistMax:
131                                         self.dragPlane = 'XZ'
132                                 else:
133                                         self.dragPlane = 'YZ'
134                 else:
135                         if self.dragStartAngle is None:
136                                 self.dragPlane = ''
137                         self.parent.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
138
139         def OnDragStart(self, p0, p1):
140                 radius = self.parent.getObjectBoundaryCircle()
141                 cursorX0, cursorY0, cursorZ0, cursorYZ, cursorXZ, cursorXY = self._ProjectToPlanes(p0, p1)
142                 if radius * self.rotateRingDistMin <= cursorXY <= radius * self.rotateRingDistMax or radius * self.rotateRingDistMin <= cursorYZ <= radius * self.rotateRingDistMax or radius * self.rotateRingDistMin <= cursorXZ <= radius * self.rotateRingDistMax:
143                         if radius * self.rotateRingDistMin <= cursorXY <= radius * self.rotateRingDistMax:
144                                 self.dragPlane = 'XY'
145                                 self.dragStartAngle = math.atan2(cursorZ0[1], cursorZ0[0]) * 180 / math.pi
146                         elif radius * self.rotateRingDistMin <= cursorXZ <= radius * self.rotateRingDistMax:
147                                 self.dragPlane = 'XZ'
148                                 self.dragStartAngle = math.atan2(cursorY0[2], cursorY0[0]) * 180 / math.pi
149                         else:
150                                 self.dragPlane = 'YZ'
151                                 self.dragStartAngle = math.atan2(cursorX0[2], cursorX0[1]) * 180 / math.pi
152                         return True
153                 return False
154
155         def OnDrag(self, p0, p1):
156                 cursorX0, cursorY0, cursorZ0, cursorYZ, cursorXZ, cursorXY = self._ProjectToPlanes(p0, p1)
157                 if self.dragPlane == 'XY':
158                         angle = math.atan2(cursorZ0[1], cursorZ0[0]) * 180 / math.pi
159                 elif self.dragPlane == 'XZ':
160                         angle = math.atan2(cursorY0[2], cursorY0[0]) * 180 / math.pi
161                 else:
162                         angle = math.atan2(cursorX0[2], cursorX0[1]) * 180 / math.pi
163                 diff = angle - self.dragStartAngle
164                 if wx.GetKeyState(wx.WXK_SHIFT):
165                         diff = round(diff / 1) * 1
166                 else:
167                         diff = round(diff / 15) * 15
168                 if diff > 180:
169                         diff -= 360
170                 if diff < -180:
171                         diff += 360
172                 rad = diff / 180.0 * math.pi
173                 self.dragEndAngle = self.dragStartAngle + diff
174                 if self.dragPlane == 'XY':
175                         self.parent.tempMatrix = numpy.matrix([[math.cos(rad), math.sin(rad), 0], [-math.sin(rad), math.cos(rad), 0], [0,0,1]], numpy.float64)
176                 elif self.dragPlane == 'XZ':
177                         self.parent.tempMatrix = numpy.matrix([[math.cos(rad), 0, math.sin(rad)], [0,1,0], [-math.sin(rad), 0, math.cos(rad)]], numpy.float64)
178                 else:
179                         self.parent.tempMatrix = numpy.matrix([[1,0,0], [0, math.cos(rad), math.sin(rad)], [0, -math.sin(rad), math.cos(rad)]], numpy.float64)
180
181         def OnDragEnd(self):
182                 self.dragStartAngle = None
183
184         def OnDraw(self):
185                 glDisable(GL_LIGHTING)
186                 glDisable(GL_BLEND)
187                 glDisable(GL_DEPTH_TEST)
188                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
189                 radius = self.parent.getObjectBoundaryCircle()
190                 glScalef(self.rotateRingDist * radius, self.rotateRingDist * radius, self.rotateRingDist * radius)
191                 if self.dragPlane == 'XY':
192                         glLineWidth(3)
193                         glColor4ub(255,64,64,255)
194                         if self.dragStartAngle is not None:
195                                 glPushMatrix()
196                                 glRotate(self.dragStartAngle, 0,0,1)
197                                 glBegin(GL_LINES)
198                                 glVertex3f(0,0,0)
199                                 glVertex3f(1,0,0)
200                                 glEnd()
201                                 glPopMatrix()
202                                 glPushMatrix()
203                                 glRotate(self.dragEndAngle, 0,0,1)
204                                 glBegin(GL_LINES)
205                                 glVertex3f(0,0,0)
206                                 glVertex3f(1,0,0)
207                                 glEnd()
208                                 glTranslatef(1.1,0,0)
209                                 glColor4ub(0,0,0,255)
210                                 opengl.glDrawStringCenter("%d" % (abs(self.dragEndAngle - self.dragStartAngle)))
211                                 glColor4ub(255,64,64,255)
212                                 glPopMatrix()
213                 else:
214                         glLineWidth(1)
215                         glColor4ub(128,0,0,255)
216                 glBegin(GL_LINE_LOOP)
217                 for i in xrange(0, 64):
218                         glVertex3f(math.cos(i/32.0*math.pi), math.sin(i/32.0*math.pi),0)
219                 glEnd()
220                 if self.dragPlane == 'YZ':
221                         glColor4ub(64,255,64,255)
222                         glLineWidth(3)
223                         if self.dragStartAngle is not None:
224                                 glPushMatrix()
225                                 glRotate(self.dragStartAngle, 1,0,0)
226                                 glBegin(GL_LINES)
227                                 glVertex3f(0,0,0)
228                                 glVertex3f(0,1,0)
229                                 glEnd()
230                                 glPopMatrix()
231                                 glPushMatrix()
232                                 glRotate(self.dragEndAngle, 1,0,0)
233                                 glBegin(GL_LINES)
234                                 glVertex3f(0,0,0)
235                                 glVertex3f(0,1,0)
236                                 glEnd()
237                                 glTranslatef(0,1.1,0)
238                                 glColor4ub(0,0,0,255)
239                                 opengl.glDrawStringCenter("%d" % (abs(self.dragEndAngle - self.dragStartAngle)))
240                                 glColor4ub(64,255,64,255)
241                                 glPopMatrix()
242                 else:
243                         glColor4ub(0,128,0,255)
244                         glLineWidth(1)
245                 glBegin(GL_LINE_LOOP)
246                 for i in xrange(0, 64):
247                         glVertex3f(0, math.cos(i/32.0*math.pi), math.sin(i/32.0*math.pi))
248                 glEnd()
249                 if self.dragPlane == 'XZ':
250                         glLineWidth(3)
251                         glColor4ub(255,255,0,255)
252                         if self.dragStartAngle is not None:
253                                 glPushMatrix()
254                                 glRotate(self.dragStartAngle, 0,-1,0)
255                                 glBegin(GL_LINES)
256                                 glVertex3f(0,0,0)
257                                 glVertex3f(1,0,0)
258                                 glEnd()
259                                 glPopMatrix()
260                                 glPushMatrix()
261                                 glRotate(self.dragEndAngle, 0,-1,0)
262                                 glBegin(GL_LINES)
263                                 glVertex3f(0,0,0)
264                                 glVertex3f(1,0,0)
265                                 glEnd()
266                                 glTranslatef(1.1,0,0)
267                                 glColor4ub(0,0,0,255)
268                                 opengl.glDrawStringCenter("%d" % (abs(self.dragEndAngle - self.dragStartAngle)))
269                                 glColor4ub(255,255,0,255)
270                                 glPopMatrix()
271                 else:
272                         glColor4ub(128,128,0,255)
273                         glLineWidth(1)
274                 glBegin(GL_LINE_LOOP)
275                 for i in xrange(0, 64):
276                         glVertex3f(math.cos(i/32.0*math.pi), 0, math.sin(i/32.0*math.pi))
277                 glEnd()
278                 glEnable(GL_DEPTH_TEST)
279
280 class toolScale(object):
281         def __init__(self, parent):
282                 self.parent = parent
283                 self.node = None
284                 self.scale = None
285
286         def _pointDist(self, p0, p1, p2):
287                 return numpy.linalg.norm(numpy.cross((p0 - p1), (p0 - p2))) / numpy.linalg.norm(p2 - p1)
288
289         def _traceNodes(self, p0, p1):
290                 s = self._nodeSize()
291                 if self._pointDist(numpy.array([0,0,0],numpy.float32), p0, p1) < s * 2:
292                         return 1
293                 if self._pointDist(numpy.array([s*15,0,0],numpy.float32), p0, p1) < s * 2:
294                         return 2
295                 if self._pointDist(numpy.array([0,s*15,0],numpy.float32), p0, p1) < s * 2:
296                         return 3
297                 if self._pointDist(numpy.array([0,0,s*15],numpy.float32), p0, p1) < s * 2:
298                         return 4
299                 return None
300
301         def _lineLineCrossingDistOnLine(self, s0, e0, s1, e1):
302                 d0 = e0 - s0
303                 d1 = e1 - s1
304                 a = numpy.dot(d0, d0)
305                 b = numpy.dot(d0, d1)
306                 e = numpy.dot(d1, d1)
307                 d = a*e - b*b
308
309                 r = s0 - s1
310                 c = numpy.dot(d0, r)
311                 f = numpy.dot(d1, r)
312
313                 s = (b*f - c*e) / d
314                 t = (a*f - b*c) / d
315                 return t
316
317         def _nodeSize(self):
318                 return float(self.parent.zoom) / float(self.parent.GetSize().GetWidth()) * 6.0
319
320         def OnMouseMove(self, p0, p1):
321                 self.node = self._traceNodes(p0, p1)
322
323         def OnDragStart(self, p0, p1):
324                 if self.node is None:
325                         return False
326                 return True
327
328         def OnDrag(self, p0, p1):
329                 s = self._nodeSize()
330                 endPoint = [1,1,1]
331                 if self.node == 2:
332                         endPoint = [1,0,0]
333                 elif self.node == 3:
334                         endPoint = [0,1,0]
335                 elif self.node == 4:
336                         endPoint = [0,0,1]
337                 scale = self._lineLineCrossingDistOnLine(p0, p1, numpy.array([0,0,0], numpy.float32), numpy.array(endPoint, numpy.float32)) / 15.0 / s
338                 if not wx.GetKeyState(wx.WXK_SHIFT):
339                         objMatrix = self.parent.getObjectMatrix()
340                         scaleX = numpy.linalg.norm(objMatrix[0].getA().flatten())
341                         scaleY = numpy.linalg.norm(objMatrix[1].getA().flatten())
342                         scaleZ = numpy.linalg.norm(objMatrix[2].getA().flatten())
343                         if self.node == 1 or not wx.GetKeyState(wx.WXK_CONTROL):
344                                 matrixScale = (scaleX + scaleY + scaleZ) / 3
345                         elif self.node == 2:
346                                 matrixScale = scaleX
347                         elif self.node == 3:
348                                 matrixScale = scaleY
349                         elif self.node == 4:
350                                 matrixScale = scaleZ
351                         scale = (round((matrixScale * scale) * 10) / 10) / matrixScale
352                 if scale < 0:
353                         scale = -scale
354                 if scale < 0.1:
355                         scale = 0.1
356                 self.scale = scale
357                 if self.node == 1 or not wx.GetKeyState(wx.WXK_CONTROL):
358                         self.parent.tempMatrix = numpy.matrix([[scale,0,0], [0, scale, 0], [0, 0, scale]], numpy.float64)
359                 elif self.node == 2:
360                         self.parent.tempMatrix = numpy.matrix([[scale,0,0], [0, 1, 0], [0, 0, 1]], numpy.float64)
361                 elif self.node == 3:
362                         self.parent.tempMatrix = numpy.matrix([[1,0,0], [0, scale, 0], [0, 0, 1]], numpy.float64)
363                 elif self.node == 4:
364                         self.parent.tempMatrix = numpy.matrix([[1,0,0], [0, 1, 0], [0, 0, scale]], numpy.float64)
365
366         def OnDragEnd(self):
367                 self.scale = None
368
369         def OnDraw(self):
370                 s = self._nodeSize()
371                 sx = s*15
372                 sy = s*15
373                 sz = s*15
374                 if self.node == 2 and self.scale is not None:
375                         sx *= self.scale
376                 if self.node == 3 and self.scale is not None:
377                         sy *= self.scale
378                 if self.node == 4 and self.scale is not None:
379                         sz *= self.scale
380                 objMatrix = self.parent.getObjectMatrix()
381                 scaleX = numpy.linalg.norm(objMatrix[0].getA().flatten())
382                 scaleY = numpy.linalg.norm(objMatrix[1].getA().flatten())
383                 scaleZ = numpy.linalg.norm(objMatrix[2].getA().flatten())
384                 if self.scale is not None:
385                         scaleX *= self.scale
386                         scaleY *= self.scale
387                         scaleZ *= self.scale
388
389                 glDisable(GL_LIGHTING)
390                 glDisable(GL_DEPTH_TEST)
391                 glEnable(GL_BLEND)
392                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
393
394                 glColor3ub(0,0,0)
395                 size = self.parent.getObjectSize()
396                 radius = self.parent.getObjectBoundaryCircle() * max(scaleX, scaleY, scaleZ)
397                 glPushMatrix()
398                 glTranslate(0,0,size[2]/2 + 5)
399                 glRotate(-self.parent.yaw, 0,0,1)
400                 if self.parent.pitch < 80:
401                         glTranslate(0, radius + 5,0)
402                 elif self.parent.pitch < 100:
403                         glTranslate(0, (radius + 5) * (90 - self.parent.pitch) / 10,0)
404                 else:
405                         glTranslate(0,-(radius + 5),0)
406                 if self.parent.tempMatrix is not None:
407                         size = (numpy.matrix([size]) * self.parent.tempMatrix).getA().flatten()
408                 opengl.glDrawStringCenter("%dx%dx%dmm" % (size[0], size[1], size[2]))
409                 glPopMatrix()
410
411                 glLineWidth(1)
412                 glBegin(GL_LINES)
413                 glColor3ub(128,0,0)
414                 glVertex3f(0, 0, 0)
415                 glVertex3f(sx, 0, 0)
416                 glColor3ub(128,128,0)
417                 glVertex3f(0, 0, 0)
418                 glVertex3f(0, sy, 0)
419                 glColor3ub(0,128,0)
420                 glVertex3f(0, 0, 0)
421                 glVertex3f(0, 0, sz)
422                 glEnd()
423
424                 glLineWidth(2)
425                 if self.node == 1:
426                         glColor3ub(255,255,255)
427                 else:
428                         glColor3ub(192,192,192)
429                 opengl.DrawBox([-s,-s,-s], [s,s,s])
430                 if self.node == 1:
431                         glColor3ub(0,0,0)
432                         opengl.glDrawStringCenter("%0.2f" % ((scaleX + scaleY + scaleZ) / 3.0))
433
434                 if self.node == 2:
435                         glColor3ub(255,64,64)
436                 else:
437                         glColor3ub(128,0,0)
438                 glPushMatrix()
439                 glTranslatef(sx,0,0)
440                 opengl.DrawBox([-s,-s,-s], [s,s,s])
441                 if self.node == 2:
442                         glColor3ub(0,0,0)
443                         opengl.glDrawStringCenter("%0.2f" % (scaleX))
444                 glPopMatrix()
445                 if self.node == 3:
446                         glColor3ub(255,255,0)
447                 else:
448                         glColor3ub(128,128,0)
449                 glPushMatrix()
450                 glTranslatef(0,sy,0)
451                 opengl.DrawBox([-s,-s,-s], [s,s,s])
452                 if self.node == 3:
453                         glColor3ub(0,0,0)
454                         opengl.glDrawStringCenter("%0.2f" % (scaleY))
455                 glPopMatrix()
456                 if self.node == 4:
457                         glColor3ub(64,255,64)
458                 else:
459                         glColor3ub(0,128,0)
460                 glPushMatrix()
461                 glTranslatef(0,0,sz)
462                 opengl.DrawBox([-s,-s,-s], [s,s,s])
463                 if self.node == 4:
464                         glColor3ub(0,0,0)
465                         opengl.glDrawStringCenter("%0.2f" % (scaleZ))
466                 glPopMatrix()
467
468                 glEnable(GL_DEPTH_TEST)