From: daid Date: Tue, 3 Dec 2013 10:33:00 +0000 (+0100) Subject: Allow for odd shaped platforms and generalize the UM2 clip code into no-go zones. X-Git-Tag: 14.01~42 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=16c67477c32e8c5cdff79d23347b0713e32ee1a3;p=cura.git Allow for odd shaped platforms and generalize the UM2 clip code into no-go zones. --- diff --git a/Cura/gui/sceneView.py b/Cura/gui/sceneView.py index e6e116a9..c7dbbb48 100644 --- a/Cura/gui/sceneView.py +++ b/Cura/gui/sceneView.py @@ -56,6 +56,7 @@ class SceneView(openglGui.glGuiPanel): self._animView = None self._animZoom = None self._platformMesh = {} + self._platformTexture = None self._isSimpleMode = True self._usbPrintMonitor = printWindow.printProcessMonitor(lambda : self._queueRefresh()) self._printerConnectionManager = printerConnectionManager.PrinterConnectionManager() @@ -631,8 +632,7 @@ class SceneView(openglGui.glGuiPanel): self._objColors[1] = profile.getPreferenceColour('model_colour2') self._objColors[2] = profile.getPreferenceColour('model_colour3') self._objColors[3] = profile.getPreferenceColour('model_colour4') - self._scene.setMachineSize(self._machineSize) - 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')) + self._scene.updateMachineDimensions() if self._selectedObj is not None: scale = self._selectedObj.getScale() @@ -1264,7 +1264,7 @@ void main(void) size = [profile.getMachineSettingFloat('machine_width'), profile.getMachineSettingFloat('machine_depth'), profile.getMachineSettingFloat('machine_height')] machine = profile.getMachineSetting('machine_type') - if profile.getMachineSetting('machine_type').startswith('ultimaker'): + if machine.startswith('ultimaker'): if machine not in self._platformMesh: meshes = meshLoader.loadMeshes(resources.getPathForMesh(machine + '_platform.stl')) if len(meshes) > 0: @@ -1330,62 +1330,79 @@ void main(void) glEnd() #Cornerpoints for big blue square - v0 = [ size[0] / 2, size[1] / 2, size[2]] - v1 = [ size[0] / 2,-size[1] / 2, size[2]] - v2 = [-size[0] / 2, size[1] / 2, size[2]] - v3 = [-size[0] / 2,-size[1] / 2, size[2]] - v4 = [ size[0] / 2, size[1] / 2, 0] - v5 = [ size[0] / 2,-size[1] / 2, 0] - v6 = [-size[0] / 2, size[1] / 2, 0] - v7 = [-size[0] / 2,-size[1] / 2, 0] - - vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7] - glEnableClientState(GL_VERTEX_ARRAY) - glVertexPointer(3, GL_FLOAT, 3*4, vList) + # v0 = [ size[0] / 2, size[1] / 2, size[2]] + # v1 = [ size[0] / 2,-size[1] / 2, size[2]] + # v2 = [-size[0] / 2, size[1] / 2, size[2]] + # v3 = [-size[0] / 2,-size[1] / 2, size[2]] + # v4 = [ size[0] / 2, size[1] / 2, 0] + # v5 = [ size[0] / 2,-size[1] / 2, 0] + # v6 = [-size[0] / 2, size[1] / 2, 0] + # v7 = [-size[0] / 2,-size[1] / 2, 0] + # + # vList = [v0,v1,v3,v2, v1,v0,v4,v5, v2,v3,v7,v6, v0,v2,v6,v4, v3,v1,v5,v7] + # 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) - glDrawArrays(GL_QUADS, 4, 8) + # glColor4ub(5, 171, 231, 64) + # glDrawArrays(GL_QUADS, 0, 4) + # glColor4ub(5, 171, 231, 96) + # glDrawArrays(GL_QUADS, 4, 8) + # glColor4ub(5, 171, 231, 128) + # glDrawArrays(GL_QUADS, 12, 8) + # glDisableClientState(GL_VERTEX_ARRAY) + + polys = profile.getMachineSizePolygons() + height = profile.getMachineSettingFloat('machine_height') + glBegin(GL_QUADS) + for n in xrange(0, len(polys[0])): + if n % 2 == 0: + glColor4ub(5, 171, 231, 96) + else: + glColor4ub(5, 171, 231, 64) + glVertex3f(polys[0][n][0], polys[0][n][1], height) + glVertex3f(polys[0][n][0], polys[0][n][1], 0) + glVertex3f(polys[0][n-1][0], polys[0][n-1][1], 0) + glVertex3f(polys[0][n-1][0], polys[0][n-1][1], height) + glEnd() glColor4ub(5, 171, 231, 128) - glDrawArrays(GL_QUADS, 12, 8) - glDisableClientState(GL_VERTEX_ARRAY) + glBegin(GL_TRIANGLE_FAN) + for p in polys[0][::-1]: + glVertex3f(p[0], p[1], height) + glEnd() #Draw checkerboard - sx = self._machineSize[0] - sy = self._machineSize[1] - for x in xrange(-int(sx/20)-1, int(sx / 20) + 1): - for y in xrange(-int(sx/20)-1, int(sy / 20) + 1): - x1 = x * 10 - x2 = x1 + 10 - y1 = y * 10 - y2 = y1 + 10 - x1 = max(min(x1, sx/2), -sx/2) - y1 = max(min(y1, sy/2), -sy/2) - x2 = max(min(x2, sx/2), -sx/2) - y2 = max(min(y2, sy/2), -sy/2) - #Black or "white" checker - if (x & 1) == (y & 1): - glColor4ub(5, 171, 231, 127) - else: - glColor4ub(5 * 8 / 10, 171 * 8 / 10, 231 * 8 / 10, 128) - glBegin(GL_QUADS) - glVertex3f(x1, y1, 0) - glVertex3f(x2, y1, 0) - glVertex3f(x2, y2, 0) - glVertex3f(x1, y2, 0) - glEnd() + if self._platformTexture is None: + self._platformTexture = opengl.loadGLTexture('checkerboard.png') + glBindTexture(GL_TEXTURE_2D, self._platformTexture) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) + glColor4f(1,1,1,0.5) + glBindTexture(GL_TEXTURE_2D, self._platformTexture) + glEnable(GL_TEXTURE_2D) + glBegin(GL_TRIANGLE_FAN) + for p in polys[0]: + glTexCoord2f(p[0]/20, p[1]/20) + glVertex3f(p[0], p[1], 0) + glEnd() + glDisable(GL_TEXTURE_2D) + glColor4ub(127, 127, 127, 200) + for poly in polys[1:]: + glBegin(GL_TRIANGLE_FAN) + for p in poly: + glTexCoord2f(p[0]/20, p[1]/20) + glVertex3f(p[0], p[1], 0) + glEnd() - if machine == 'ultimaker2': + if machine == 'ultimaker2x': glColor4ub(127, 127, 127, 200) #if UM2, draw bat-area zone for head. THe head can't stop there, because its bat-area. #UpperRight clipWidth = 25 clipHeight = 10 - posX = sx / 2 - clipWidth - posY = sy / 2 - clipHeight + posX = size[0] / 2 - clipWidth + posY = size[1] / 2 - clipHeight glBegin(GL_QUADS) glVertex3f(posX, posY, 0) glVertex3f(posX+clipWidth, posY, 0) @@ -1395,8 +1412,8 @@ void main(void) #UpperLeft clipWidth = 25 clipHeight = 10 - posX = -sx / 2 - posY = sy / 2 - clipHeight + posX = -size[0] / 2 + posY = size[1] / 2 - clipHeight glBegin(GL_QUADS) glVertex3f(posX, posY, 0) glVertex3f(posX+clipWidth, posY, 0) @@ -1406,8 +1423,8 @@ void main(void) #LowerRight clipWidth = 25 clipHeight = 10 - posX = sx / 2 - clipWidth - posY = -sy / 2 + posX = size[0] / 2 - clipWidth + posY = -size[1] / 2 glBegin(GL_QUADS) glVertex3f(posX, posY, 0) glVertex3f(posX+clipWidth, posY, 0) @@ -1417,8 +1434,8 @@ void main(void) #LowerLeft clipWidth = 25 clipHeight = 10 - posX = -sx / 2 - posY = -sy / 2 + posX = -size[0] / 2 + posY = -size[1] / 2 glBegin(GL_QUADS) glVertex3f(posX, posY, 0) glVertex3f(posX+clipWidth, posY, 0) diff --git a/Cura/util/objectScene.py b/Cura/util/objectScene.py index f50e5721..7510a93e 100644 --- a/Cura/util/objectScene.py +++ b/Cura/util/objectScene.py @@ -98,9 +98,11 @@ class Scene(object): self._gantryHeight = 60 self._oneAtATime = True - # Physical (square) machine size. - def setMachineSize(self, machineSize): - self._machineSize = machineSize + # update the physical machine dimensions + def updateMachineDimensions(self): + self._machineSize = numpy.array([profile.getMachineSettingFloat('machine_width'), profile.getMachineSettingFloat('machine_depth'), profile.getMachineSettingFloat('machine_height')]) + self._machinePolygons = profile.getMachineSizePolygons() + self.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')) # Size offsets are offsets caused by brim, skirt, etc. def updateSizeOffsets(self, force=False): @@ -140,8 +142,8 @@ class Scene(object): obj.applyMatrix(numpy.matrix(matrix, numpy.float64)) self._findFreePositionFor(obj) self._objectList.append(obj) - self.pushFree() self.updateSizeOffsets(True) + self.pushFree() def remove(self, obj): self._objectList.remove(obj) @@ -217,51 +219,22 @@ class Scene(object): return polygon.polygonCollision(a._boundaryHull + a.getPosition(), b._boundaryHull + b.getPosition()) def checkPlatform(self, obj): - p = obj.getPosition() - s = obj.getSize()[0:2] / 2 + self._sizeOffsets - offsetLeft = 0.0 - offsetRight = 0.0 - offsetBack = 0.0 - offsetFront = 0.0 - extruderCount = len(obj._meshList) - if profile.getProfileSetting('support_dual_extrusion') == 'Second extruder' and profile.getProfileSetting('support') != 'None': - extruderCount = max(extruderCount, 2) - for n in xrange(1, extruderCount): - if offsetLeft < self._extruderOffset[n][0]: - offsetLeft = self._extruderOffset[n][0] - if offsetRight > self._extruderOffset[n][0]: - offsetRight = self._extruderOffset[n][0] - if offsetFront < self._extruderOffset[n][1]: - offsetFront = self._extruderOffset[n][1] - if offsetBack > self._extruderOffset[n][1]: - offsetBack = self._extruderOffset[n][1] - boundLeft = -self._machineSize[0] / 2 + offsetLeft - boundRight = self._machineSize[0] / 2 + offsetRight - boundFront = -self._machineSize[1] / 2 + offsetFront - boundBack = self._machineSize[1] / 2 + offsetBack - if p[0] - s[0] < boundLeft: - return False - if p[0] + s[0] > boundRight: - return False - if p[1] - s[1] < boundFront: - return False - if p[1] + s[1] > boundBack: + area = obj._printAreaHull + obj.getPosition() + if not polygon.fullInside(area, self._machinePolygons[0]): return False - - #Do clip Check for UM2. - machine = profile.getMachineSetting('machine_type') - if machine == "ultimaker2": - #lowerRight clip check - if p[0] - s[0] < boundLeft + 25 and p[1] - s[1] < boundFront + 10: - return False - #UpperRight - if p[0] - s[0] < boundLeft + 25 and p[1] + s[1] > boundBack - 10: - return False - #LowerLeft - if p[0] + s[0] > boundRight - 25 and p[1] - s[1] < boundFront + 10: - return False - #UpperLeft - if p[0] + s[0] > boundRight - 25 and p[1] + s[1] > boundBack - 10: + # aMin = numpy.min(area, 0) + # aMax = numpy.max(area, 0) + # if aMin[0] < -self._machineSize[0] / 2: + # return False + # if aMax[0] > self._machineSize[0] / 2: + # return False + # if aMin[1] < -self._machineSize[1] / 2: + # return False + # if aMax[1] > self._machineSize[1] / 2: + # return False + #Check the "no go zones" + for poly in self._machinePolygons[1:]: + if polygon.polygonCollision(poly, area): return False return True diff --git a/Cura/util/polygon.py b/Cura/util/polygon.py index a6592fec..9b7a987b 100644 --- a/Cura/util/polygon.py +++ b/Cura/util/polygon.py @@ -120,6 +120,34 @@ def polygonCollisionPushVector(polyA, polyB): retSize = size return ret +#Check if polyA is fully inside of polyB. +def fullInside(polyA, polyB): + for n in xrange(0, len(polyA)): + p0 = polyA[n-1] + p1 = polyA[n] + normal = (p1 - p0)[::-1] + normal[1] = -normal[1] + normal /= numpy.linalg.norm(normal) + aMin, aMax = projectPoly(polyA, normal) + bMin, bMax = projectPoly(polyB, normal) + if aMax > bMax: + return False + if aMin < bMin: + return False + for n in xrange(0, len(polyB)): + p0 = polyB[n-1] + p1 = polyB[n] + normal = (p1 - p0)[::-1] + normal[1] = -normal[1] + normal /= numpy.linalg.norm(normal) + aMin, aMax = projectPoly(polyA, normal) + bMin, bMax = projectPoly(polyB, normal) + if aMax > bMax: + return False + if aMin < bMin: + return False + return True + def isLeft(a, b, c): return ((b[0] - a[0])*(c[1] - a[1]) - (b[1] - a[1])*(c[0] - a[0])) > 0 diff --git a/Cura/util/profile.py b/Cura/util/profile.py index 65128f0d..a2f0255a 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -4,6 +4,7 @@ __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AG import os, traceback, math, re, zlib, base64, time, sys, platform, glob, string, stat, types import cPickle as pickle +import numpy if sys.version_info[0] < 3: import ConfigParser else: @@ -870,6 +871,30 @@ def getMachineCenterCoords(): return [0, 0] return [getMachineSettingFloat('machine_width') / 2, getMachineSettingFloat('machine_depth') / 2] +#Returns a list of convex polygons, first polygon is the allowed area of the machine, +# the rest of the polygons are the dis-allowed areas of the machine. +def getMachineSizePolygons(): + size = numpy.array([getMachineSettingFloat('machine_width'), getMachineSettingFloat('machine_depth'), getMachineSettingFloat('machine_height')], numpy.float32) + ret = [] + ret.append(numpy.array([[-size[0]/2,-size[1]/2],[ size[0]/2,-size[1]/2],[ size[0]/2, size[1]/2], [-size[0]/2, size[1]/2]], numpy.float32)) + + # Circle platform for delta printers... + # circle = [] + # steps = 16 + # for n in xrange(0, steps): + # circle.append([math.cos(float(n)/steps*2*math.pi) * size[0]/2, math.sin(float(n)/steps*2*math.pi) * size[0]/2]) + # ret.append(numpy.array(circle, numpy.float32)) + + if getMachineSetting('machine_type') == 'ultimaker2': + #UM2 no-go zones + w = 25 + h = 10 + ret.append(numpy.array([[-size[0]/2,-size[1]/2],[-size[0]/2+w+2,-size[1]/2], [-size[0]/2+w,-size[1]/2+h], [-size[0]/2,-size[1]/2+h]], numpy.float32)) + ret.append(numpy.array([[ size[0]/2-w-2,-size[1]/2],[ size[0]/2,-size[1]/2], [ size[0]/2,-size[1]/2+h],[ size[0]/2-w,-size[1]/2+h]], numpy.float32)) + ret.append(numpy.array([[-size[0]/2+w+2, size[1]/2],[-size[0]/2, size[1]/2], [-size[0]/2, size[1]/2-h],[-size[0]/2+w, size[1]/2-h]], numpy.float32)) + ret.append(numpy.array([[ size[0]/2, size[1]/2],[ size[0]/2-w-2, size[1]/2], [ size[0]/2-w, size[1]/2-h],[ size[0]/2, size[1]/2-h]], numpy.float32)) + return ret + ######################################################### ## Alteration file functions #########################################################