chiark / gitweb /
Add convex hulls for all objects and do collision detection with that. Add initial...
authordaid <daid303@gmail.com>
Thu, 28 Nov 2013 13:38:44 +0000 (14:38 +0100)
committerdaid <daid303@gmail.com>
Thu, 28 Nov 2013 13:38:44 +0000 (14:38 +0100)
Cura/gui/sceneView.py
Cura/util/gcodeInterpreter.py
Cura/util/mesh.py
Cura/util/objectScene.py

index 3e1ce545404a37b62d4d234aa96ef63db4e31977..0afafc73ac89eb39a320a2d8fda2ee6a7c5832d4 100644 (file)
@@ -24,6 +24,7 @@ from Cura.util import sliceEngine
 from Cura.util import machineCom
 from Cura.util import removableStorage
 from Cura.util import gcodeInterpreter
+from Cura.util.printerConnection import printerConnectionManager
 from Cura.gui.util import previewTools
 from Cura.gui.util import opengl
 from Cura.gui.util import openglGui
@@ -56,6 +57,7 @@ class SceneView(openglGui.glGuiPanel):
                self._platformMesh = {}
                self._isSimpleMode = True
                self._usbPrintMonitor = printWindow.printProcessMonitor(lambda : self._queueRefresh())
+               self._printerConnectionManager = printerConnectionManager.PrinterConnectionManager()
 
                self._viewport = None
                self._modelMatrix = None
@@ -495,7 +497,7 @@ class SceneView(openglGui.glGuiPanel):
        def sceneUpdated(self):
                self._sceneUpdateTimer.Start(500, True)
                self._slicer.abortSlicer()
-               self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
+               self._scene.updateSizeOffsets()
                self.QueueRefresh()
 
        def _onRunSlicer(self, e):
@@ -616,10 +618,7 @@ class SceneView(openglGui.glGuiPanel):
                self._objColors[2] = profile.getPreferenceColour('model_colour3')
                self._objColors[3] = profile.getPreferenceColour('model_colour4')
                self._scene.setMachineSize(self._machineSize)
-               self._scene.setSizeOffsets(numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32))
                self._scene.setHeadSize(profile.getMachineSettingFloat('extruder_head_size_min_x'), profile.getMachineSettingFloat('extruder_head_size_max_x'), profile.getMachineSettingFloat('extruder_head_size_min_y'), profile.getMachineSettingFloat('extruder_head_size_max_y'), profile.getMachineSettingFloat('extruder_head_size_height'))
-               for n in xrange(1, 4):
-                       self._scene.setExtruderOffset(n, profile.getMachineSettingFloat('extruder_offset_x%d' % (n)), profile.getMachineSettingFloat('extruder_offset_y%d' % (n)))
 
                if self._selectedObj is not None:
                        scale = self._selectedObj.getScale()
@@ -832,12 +831,16 @@ class SceneView(openglGui.glGuiPanel):
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
 
        def OnPaint(self,e):
+               connectionEntry = self._printerConnectionManager.getAvailableConnection()
                if machineCom.machineIsConnected():
                        self.printButton._imageID = 6
                        self.printButton._tooltip = _("Print")
-               elif len(removableStorage.getPossibleSDcardDrives()) > 0:
+               elif len(removableStorage.getPossibleSDcardDrives()) > 0 and (connectionEntry is None or connectionEntry.priority < 0):
                        self.printButton._imageID = 2
                        self.printButton._tooltip = _("Toolpath to SD")
+               elif connectionEntry is not None:
+                       self.printButton._imageID = connectionEntry.icon
+                       self.printButton._tooltip = _("Print with %s") % (connectionEntry.name)
                else:
                        self.printButton._imageID = 3
                        self.printButton._tooltip = _("Save toolpath")
@@ -1151,19 +1154,31 @@ void main(void)
                                glPopMatrix()
                else:
                        #Draw the object box-shadow, so you can see where it will collide with other objects.
-                       if self._selectedObj is not None and len(self._scene.objects()) > 1:
-                               size = self._selectedObj.getSize()[0:2] / 2 + self._scene.getObjectExtend()
-                               glPushMatrix()
-                               glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
+                       if self._selectedObj is not None:
                                glEnable(GL_BLEND)
                                glEnable(GL_CULL_FACE)
-                               glColor4f(0,0,0,0.12)
-                               glBegin(GL_QUADS)
-                               glVertex3f(-size[0],  size[1], 0.1)
-                               glVertex3f(-size[0], -size[1], 0.1)
-                               glVertex3f( size[0], -size[1], 0.1)
-                               glVertex3f( size[0],  size[1], 0.1)
+                               glColor4f(0,0,0,0.16)
+                               glDepthMask(False)
+                               for obj in self._scene.objects():
+                                       glPushMatrix()
+                                       glTranslatef(obj.getPosition()[0], obj.getPosition()[1], 0)
+                                       glBegin(GL_TRIANGLE_FAN)
+                                       for p in obj._boundaryHull[::-1]:
+                                               glVertex3f(p[0], p[1], 0)
+                                       glEnd()
+                                       glPopMatrix()
+                               glPushMatrix()
+                               glColor4f(0,0,0,0.06)
+                               glTranslatef(self._selectedObj.getPosition()[0], self._selectedObj.getPosition()[1], 0)
+                               glBegin(GL_TRIANGLE_FAN)
+                               for p in self._selectedObj._printAreaHull[::-1]:
+                                       glVertex3f(p[0], p[1], 0)
+                               glEnd()
+                               glBegin(GL_TRIANGLE_FAN)
+                               for p in self._selectedObj._headAreaHull[::-1]:
+                                       glVertex3f(p[0], p[1], 0)
                                glEnd()
+                               glDepthMask(True)
                                glDisable(GL_CULL_FACE)
                                glPopMatrix()
 
@@ -1314,6 +1329,7 @@ void main(void)
                glEnableClientState(GL_VERTEX_ARRAY)
                glVertexPointer(3, GL_FLOAT, 3*4, vList)
 
+               glDepthMask(False)
                glColor4ub(5, 171, 231, 64)
                glDrawArrays(GL_QUADS, 0, 4)
                glColor4ub(5, 171, 231, 96)
@@ -1341,10 +1357,10 @@ void main(void)
                                else:
                                        glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128)
                                glBegin(GL_QUADS)
-                               glVertex3f(x1, y1, -0.02) #Draw bit below z0 to prevent zfighting.
-                               glVertex3f(x2, y1, -0.02)
-                               glVertex3f(x2, y2, -0.02)
-                               glVertex3f(x1, y2, -0.02)
+                               glVertex3f(x1, y1, 0)
+                               glVertex3f(x2, y1, 0)
+                               glVertex3f(x2, y2, 0)
+                               glVertex3f(x1, y2, 0)
                                glEnd()
 
                if machine == 'ultimaker2':
@@ -1357,10 +1373,10 @@ void main(void)
                        posX = sx / 2 - clipWidth
                        posY = sy / 2 - clipHeight
                        glBegin(GL_QUADS)
-                       glVertex3f(posX, posY, 0.1)
-                       glVertex3f(posX+clipWidth, posY, 0.1)
-                       glVertex3f(posX+clipWidth, posY+clipHeight, 0.1)
-                       glVertex3f(posX, posY+clipHeight, 0.1)
+                       glVertex3f(posX, posY, 0)
+                       glVertex3f(posX+clipWidth, posY, 0)
+                       glVertex3f(posX+clipWidth, posY+clipHeight, 0)
+                       glVertex3f(posX, posY+clipHeight, 0)
                        glEnd()
                        #UpperLeft
                        clipWidth = 25
@@ -1368,10 +1384,10 @@ void main(void)
                        posX = -sx / 2
                        posY = sy / 2 - clipHeight
                        glBegin(GL_QUADS)
-                       glVertex3f(posX, posY, 0.1)
-                       glVertex3f(posX+clipWidth, posY, 0.1)
-                       glVertex3f(posX+clipWidth, posY+clipHeight, 0.1)
-                       glVertex3f(posX, posY+clipHeight, 0.1)
+                       glVertex3f(posX, posY, 0)
+                       glVertex3f(posX+clipWidth, posY, 0)
+                       glVertex3f(posX+clipWidth, posY+clipHeight, 0)
+                       glVertex3f(posX, posY+clipHeight, 0)
                        glEnd()
                        #LowerRight
                        clipWidth = 25
@@ -1379,10 +1395,10 @@ void main(void)
                        posX = sx / 2 - clipWidth
                        posY = -sy / 2
                        glBegin(GL_QUADS)
-                       glVertex3f(posX, posY, 0.1)
-                       glVertex3f(posX+clipWidth, posY, 0.1)
-                       glVertex3f(posX+clipWidth, posY+clipHeight, 0.1)
-                       glVertex3f(posX, posY+clipHeight, 0.1)
+                       glVertex3f(posX, posY, 0)
+                       glVertex3f(posX+clipWidth, posY, 0)
+                       glVertex3f(posX+clipWidth, posY+clipHeight, 0)
+                       glVertex3f(posX, posY+clipHeight, 0)
                        glEnd()
                        #LowerLeft
                        clipWidth = 25
@@ -1390,12 +1406,13 @@ void main(void)
                        posX = -sx / 2
                        posY = -sy / 2
                        glBegin(GL_QUADS)
-                       glVertex3f(posX, posY, 0.1)
-                       glVertex3f(posX+clipWidth, posY, 0.1)
-                       glVertex3f(posX+clipWidth, posY+clipHeight, 0.1)
-                       glVertex3f(posX, posY+clipHeight, 0.1)
+                       glVertex3f(posX, posY, 0)
+                       glVertex3f(posX+clipWidth, posY, 0)
+                       glVertex3f(posX+clipWidth, posY+clipHeight, 0)
+                       glVertex3f(posX, posY+clipHeight, 0)
                        glEnd()
 
+               glDepthMask(True)
                glDisable(GL_BLEND)
                glDisable(GL_CULL_FACE)
 
index 00f98e36961de75bda5e7efe16347148236c3870..2d67464153f7a856e00ea65357888bf1a797d0fe 100644 (file)
@@ -238,6 +238,8 @@ class gcode(object):
                                                pass
                                        elif M == 1:    #Message with possible wait (ignored)
                                                pass
+                                       elif M == 25:   #Stop SD printing
+                                               pass
                                        elif M == 80:   #Enable power supply
                                                pass
                                        elif M == 81:   #Suicide/disable power supply
index 9d641426087264b42d6d70b3a46796ef92f89da9..cf196d4a8eba80750a841814e40bccf37c0106da 100644 (file)
@@ -8,43 +8,7 @@ import os
 import numpy
 numpy.seterr(all='ignore')
 
-def convexHull(pointList):
-       def _isRightTurn((p, q, r)):
-               sum1 = q[0]*r[1] + p[0]*q[1] + r[0]*p[1]
-               sum2 = q[0]*p[1] + r[0]*q[1] + p[0]*r[1]
-
-               if sum1 - sum2 < 0:
-                       return 1
-               else:
-                       return 0
-
-       unique = {}
-       for p in pointList:
-               unique[(int(p[0]),int(p[1]))] = 1
-
-       points = unique.keys()
-       points.sort()
-
-       # Build upper half of the hull.
-       upper = [points[0], points[1]]
-       for p in points[2:]:
-               upper.append(p)
-               while len(upper) > 2 and not _isRightTurn(upper[-3:]):
-                       del upper[-2]
-
-       # Build lower half of the hull.
-       points = points[::-1]
-       lower = [points[0], points[1]]
-       for p in points[2:]:
-               lower.append(p)
-               while len(lower) > 2 and not _isRightTurn(lower[-3:]):
-                       del lower[-2]
-
-       # Remove duplicates.
-       del lower[0]
-       del lower[-1]
-
-       return numpy.array(upper + lower, numpy.float32) - numpy.array([0.0,0.0], numpy.float32)
+from Cura.util import polygon
 
 class printableObject(object):
        def __init__(self, originFilename):
@@ -63,6 +27,12 @@ class printableObject(object):
                self._transformedSize = None
                self._boundaryCircleSize = None
                self._drawOffset = None
+               self._boundaryHull = None
+               self._printAreaExtend = numpy.array([[-1,-1],[ 1,-1],[ 1, 1],[-1, 1]], numpy.float32)
+               self._headAreaExtend = numpy.array([[-1,-1],[ 1,-1],[ 1, 1],[-1, 1]], numpy.float32)
+               self._printAreaHull = None
+               self._headAreaHull = None
+
                self._loadAnim = None
 
        def copy(self):
@@ -73,6 +43,8 @@ class printableObject(object):
                ret._transformedSize = self._transformedSize.copy()
                ret._boundaryCircleSize = self._boundaryCircleSize
                ret._boundaryHull = self._boundaryHull.copy()
+               ret._printAreaExtend = self._printAreaExtend.copy()
+               ret._printAreaHull = self._printAreaHull.copy()
                ret._drawOffset = self._drawOffset.copy()
                for m in self._meshList[:]:
                        m2 = ret._addMesh()
@@ -109,10 +81,10 @@ class printableObject(object):
                self._transformedMax = numpy.array([-999999999999,-999999999999,-999999999999], numpy.float64)
                self._boundaryCircleSize = 0
 
-               hull = numpy.zeros((0, 2), numpy.float32)
+               hull = numpy.zeros((0, 2), numpy.int)
                for m in self._meshList:
                        transformedVertexes = m.getTransformedVertexes()
-                       hull = convexHull(numpy.concatenate((transformedVertexes[:,0:2], hull), 0))
+                       hull = polygon.convexHull(numpy.concatenate((numpy.rint(transformedVertexes[:,0:2]).astype(int), hull), 0))
                        transformedMin = transformedVertexes.min(0)
                        transformedMax = transformedVertexes.max(0)
                        for n in xrange(0, 3):
@@ -127,10 +99,13 @@ class printableObject(object):
                self._transformedSize = self._transformedMax - self._transformedMin
                self._drawOffset = (self._transformedMax + self._transformedMin) / 2
                self._drawOffset[2] = self._transformedMin[2]
-               self._boundaryHull = hull - self._drawOffset[0:2]
                self._transformedMax -= self._drawOffset
                self._transformedMin -= self._drawOffset
 
+               self._boundaryHull = polygon.minkowskiHull((hull.astype(numpy.float32) - self._drawOffset[0:2]), numpy.array([[-1,-1],[-1,1],[1,1],[1,-1]],numpy.float32))
+               self._printAreaHull = polygon.minkowskiHull(self._boundaryHull, self._printAreaExtend)
+               self._headAreaHull = polygon.minkowskiHull(self._printAreaHull, self._headAreaExtend)
+
        def getName(self):
                return self._name
        def getOriginFilename(self):
@@ -153,6 +128,15 @@ class printableObject(object):
        def getBoundaryCircle(self):
                return self._boundaryCircleSize
 
+       def setPrintAreaExtends(self, poly):
+               self._printAreaExtend = poly
+               self._printAreaHull = polygon.minkowskiHull(self._boundaryHull, self._printAreaExtend)
+               self._headAreaHull = polygon.minkowskiHull(self._printAreaHull, self._headAreaExtend)
+
+       def setHeadArea(self, poly):
+               self._headAreaExtend = poly
+               self._headAreaHull = polygon.minkowskiHull(self._printAreaHull, self._headAreaExtend)
+
        def mirror(self, axis):
                matrix = [[1,0,0], [0, 1, 0], [0, 0, 1]]
                matrix[axis][axis] = -1
index 16744add5957bd3283887344813688782dde6c7c..947bc95b474220e1c3211964b8373e5a15756308 100644 (file)
@@ -1,7 +1,9 @@
 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
 import random
 import numpy
+
 from Cura.util import profile
+from Cura.util import polygon
 
 class _objectOrder(object):
        def __init__(self, order, todo):
@@ -73,26 +75,9 @@ class _objectOrderFinder(object):
 
        #Check if printing one object will cause printhead colission with other object.
        def _checkHit(self, addIdx, idx):
-               addPos = self._scene._objectList[addIdx].getPosition()
-               addSize = self._scene._objectList[addIdx].getSize()
-               pos = self._scene._objectList[idx].getPosition()
-               size = self._scene._objectList[idx].getSize()
-
-               if self._leftToRight:
-                       if addPos[0] - addSize[0] / 2 - self._offset[0] >= pos[0] + size[0] / 2:
-                               return False
-               else:
-                       if addPos[0] + addSize[0] / 2 + self._offset[0] <= pos[0] - size[0] / 2:
-                               return False
-
-               if self._frontToBack:
-                       if addPos[1] - addSize[1] / 2 - self._offset[1] >= pos[1] + size[1] / 2:
-                               return False
-               else:
-                       if addPos[1] + addSize[1] / 2 + self._offset[1] <= pos[1] - size[1] / 2:
-                               return False
-
-               return True
+               obj = self._scene._objectList[idx]
+               addObj = self._scene._objectList[addIdx]
+               return polygon.polygonCollision(obj._headAreaHull + obj.getPosition(), addObj._boundaryHull + addObj.getPosition())
 
 class Scene(object):
        def __init__(self):
@@ -106,13 +91,22 @@ class Scene(object):
                self._leftToRight = False
                self._frontToBack = True
                self._gantryHeight = 60
+               self._oneAtATime = True
+
        # Physical (square) machine size.
        def setMachineSize(self, machineSize):
                self._machineSize = machineSize
 
        # Size offsets are offsets caused by brim, skirt, etc.
-       def setSizeOffsets(self, sizeOffsets):
-               self._sizeOffsets = sizeOffsets
+       def updateSizeOffsets(self, force=False):
+               newOffsets = numpy.array(profile.calculateObjectSizeOffsets(), numpy.float32)
+               if not force and numpy.array_equal(self._sizeOffsets, newOffsets):
+                       return
+               self._sizeOffsets = newOffsets
+
+               extends = numpy.array([[-newOffsets[0],-newOffsets[1]],[ newOffsets[0],-newOffsets[1]],[ newOffsets[0], newOffsets[1]],[-newOffsets[0], newOffsets[1]]], numpy.float32)
+               for obj in self._objectList:
+                       obj.setPrintAreaExtends(extends)
 
        #size of the printing head.
        def setHeadSize(self, xMin, xMax, yMin, yMax, gantryHeight):
@@ -121,6 +115,11 @@ class Scene(object):
                self._headSizeOffsets[0] = min(xMin, xMax)
                self._headSizeOffsets[1] = min(yMin, yMax)
                self._gantryHeight = gantryHeight
+               self._oneAtATime = self._gantryHeight > 0
+
+               headArea = numpy.array([[-xMin,-yMin],[ xMax,-yMin],[ xMax, yMax],[-xMin, yMax]], numpy.float32)
+               for obj in self._objectList:
+                       obj.setHeadArea(headArea)
 
        def setExtruderOffset(self, extruderNr, offsetX, offsetY):
                self._extruderOffset[extruderNr] = numpy.array([offsetX, offsetY], numpy.float32)
@@ -140,6 +139,7 @@ class Scene(object):
                        scale = numpy.max(self._machineSize[0:2]) * 2.5 / numpy.max(obj.getSize()[0:2])
                        matrix = [[scale,0,0], [0, scale, 0], [0, 0, scale]]
                        obj.applyMatrix(numpy.matrix(matrix, numpy.float64))
+               self.updateSizeOffsets(True)
 
        def remove(self, obj):
                self._objectList.remove(obj)
@@ -155,6 +155,7 @@ class Scene(object):
                self.pushFree()
 
        def pushFree(self):
+               return
                n = 1000
                while self._pushFree():
                        n -= 1
@@ -183,7 +184,10 @@ class Scene(object):
                        obj.setPosition(obj.getPosition() + offset)
 
        def printOrder(self):
-               order = _objectOrderFinder(self, self._headSizeOffsets + self._sizeOffsets, self._leftToRight, self._frontToBack, self._gantryHeight).order
+               if self._oneAtATime:
+                       order = _objectOrderFinder(self, self._headSizeOffsets + self._sizeOffsets, self._leftToRight, self._frontToBack, self._gantryHeight).order
+               else:
+                       order = None
                return order
 
        def _pushFree(self):
@@ -215,11 +219,10 @@ class Scene(object):
        def _checkHit(self, a, b):
                if a == b:
                        return False
-               posDiff = a.getPosition() - b.getPosition()
-               if abs(posDiff[0]) < (a.getSize()[0] + b.getSize()[0]) / 2 + self._sizeOffsets[0] + self._headSizeOffsets[0]:
-                       if abs(posDiff[1]) < (a.getSize()[1] + b.getSize()[1]) / 2 + self._sizeOffsets[1] + self._headSizeOffsets[1]:
-                               return True
-               return False
+               if self._oneAtATime:
+                       return polygon.polygonCollision(a._headAreaHull + a.getPosition(), b._boundaryHull + b.getPosition())
+               else:
+                       return polygon.polygonCollision(a._boundaryHull + a.getPosition(), b._boundaryHull + b.getPosition())
 
        def checkPlatform(self, obj):
                p = obj.getPosition()