From 8069d0633fde1b5c458568f654eacbc32510a27c Mon Sep 17 00:00:00 2001 From: daid Date: Thu, 26 Jul 2012 16:30:43 +0200 Subject: [PATCH] Increase performance and decrease memory usage by using numpy library for 3D models. Saves more then 50% memory, and is about 30% faster when loading models. I think more performance can be gained with this library. --- Cura/gui/opengl.py | 56 +++++++------- Cura/gui/preview3d.py | 30 ++++---- Cura/gui/projectPlanner.py | 148 ++++++++++++++++++------------------- Cura/util/mesh.py | 71 +++++++++--------- Cura/util/stl.py | 36 ++++----- Cura/util/util3d.py | 2 +- 6 files changed, 164 insertions(+), 179 deletions(-) diff --git a/Cura/gui/opengl.py b/Cura/gui/opengl.py index ab685d59..1c385e59 100644 --- a/Cura/gui/opengl.py +++ b/Cura/gui/opengl.py @@ -180,44 +180,44 @@ def ResetMatrixRotationAndScale(): def DrawBox(vMin, vMax): glBegin(GL_LINE_LOOP) - glVertex3f(vMin.x, vMin.y, vMin.z) - glVertex3f(vMax.x, vMin.y, vMin.z) - glVertex3f(vMax.x, vMax.y, vMin.z) - glVertex3f(vMin.x, vMax.y, vMin.z) + glVertex3f(vMin[0], vMin[1], vMin[2]) + glVertex3f(vMax[0], vMin[1], vMin[2]) + glVertex3f(vMax[0], vMax[1], vMin[2]) + glVertex3f(vMin[0], vMax[1], vMin[2]) glEnd() glBegin(GL_LINE_LOOP) - glVertex3f(vMin.x, vMin.y, vMax.z) - glVertex3f(vMax.x, vMin.y, vMax.z) - glVertex3f(vMax.x, vMax.y, vMax.z) - glVertex3f(vMin.x, vMax.y, vMax.z) + glVertex3f(vMin[0], vMin[1], vMax[2]) + glVertex3f(vMax[0], vMin[1], vMax[2]) + glVertex3f(vMax[0], vMax[1], vMax[2]) + glVertex3f(vMin[0], vMax[1], vMax[2]) glEnd() glBegin(GL_LINES) - glVertex3f(vMin.x, vMin.y, vMin.z) - glVertex3f(vMin.x, vMin.y, vMax.z) - glVertex3f(vMax.x, vMin.y, vMin.z) - glVertex3f(vMax.x, vMin.y, vMax.z) - glVertex3f(vMax.x, vMax.y, vMin.z) - glVertex3f(vMax.x, vMax.y, vMax.z) - glVertex3f(vMin.x, vMax.y, vMin.z) - glVertex3f(vMin.x, vMax.y, vMax.z) + glVertex3f(vMin[0], vMin[1], vMin[2]) + glVertex3f(vMin[0], vMin[1], vMax[2]) + glVertex3f(vMax[0], vMin[1], vMin[2]) + glVertex3f(vMax[0], vMin[1], vMax[2]) + glVertex3f(vMax[0], vMax[1], vMin[2]) + glVertex3f(vMax[0], vMax[1], vMax[2]) + glVertex3f(vMin[0], vMax[1], vMin[2]) + glVertex3f(vMin[0], vMax[1], vMax[2]) glEnd() def DrawSTL(mesh): glEnable(GL_CULL_FACE) - for face in mesh.faces: + for i in xrange(0, mesh.vertexCount, 3): glBegin(GL_TRIANGLES) - v1 = face.v[0] - v2 = face.v[1] - v3 = face.v[2] - glNormal3f(face.normal.x, face.normal.y, face.normal.z) - glVertex3f(v1.x, v1.y, v1.z) - glVertex3f(v2.x, v2.y, v2.z) - glVertex3f(v3.x, v3.y, v3.z) - glNormal3f(-face.normal.x, -face.normal.y, -face.normal.z) - glVertex3f(v1.x, v1.y, v1.z) - glVertex3f(v3.x, v3.y, v3.z) - glVertex3f(v2.x, v2.y, v2.z) + v1 = mesh.vertexes[i] + v2 = mesh.vertexes[i+1] + v3 = mesh.vertexes[i+2] + glNormal3f(mesh.normal[i/3][0], mesh.normal[i/3][1], mesh.normal[i/3][2]) + glVertex3f(v1[0], v1[1], v1[2]) + glVertex3f(v2[0], v2[1], v2[2]) + glVertex3f(v3[0], v3[1], v3[2]) + glNormal3f(-mesh.normal[i/3][0], -mesh.normal[i/3][1], -mesh.normal[i/3][2]) + glVertex3f(v1[0], v1[1], v1[2]) + glVertex3f(v2[0], v2[1], v2[2]) + glVertex3f(v3[0], v3[1], v3[2]) glEnd() def DrawGCodeLayer(layer): diff --git a/Cura/gui/preview3d.py b/Cura/gui/preview3d.py index 9adf0073..ef27dc04 100644 --- a/Cura/gui/preview3d.py +++ b/Cura/gui/preview3d.py @@ -1,6 +1,7 @@ from __future__ import division import sys, math, threading, re, time, os +import numpy from wx import glcanvas import wx @@ -170,11 +171,11 @@ class previewPanel(wx.Panel): return vMin = self.objectsMinV vMax = self.objectsMaxV - scaleX1 = (self.machineSize.x - self.machineCenter.x) / ((vMax.x - vMin.x) / 2) - scaleY1 = (self.machineSize.y - self.machineCenter.y) / ((vMax.y - vMin.y) / 2) - scaleX2 = (self.machineCenter.x) / ((vMax.x - vMin.x) / 2) - scaleY2 = (self.machineCenter.y) / ((vMax.y - vMin.y) / 2) - scaleZ = self.machineSize.z / (vMax.z - vMin.z) + scaleX1 = (self.machineSize.x - self.machineCenter.x) / ((vMax[0] - vMin[0]) / 2) + scaleY1 = (self.machineSize.y - self.machineCenter.y) / ((vMax[1] - vMin[1]) / 2) + scaleX2 = (self.machineCenter.x) / ((vMax[0] - vMin[1]) / 2) + scaleY2 = (self.machineCenter.y) / ((vMax[1] - vMin[1]) / 2) + scaleZ = self.machineSize.z / (vMax[2] - vMin[2]) scale = min(scaleX1, scaleY1, scaleX2, scaleY2, scaleZ) self.scale.SetValue(str(scale)) profile.putProfileSetting('model_scale', self.scale.GetValue()) @@ -356,8 +357,8 @@ class previewPanel(wx.Panel): continue obj.mesh.getMinimumZ() - minV = minV.min(obj.mesh.getMinimum()) - maxV = maxV.max(obj.mesh.getMaximum()) + minV = numpy.minimum(minV, obj.mesh.getMinimum()) + maxV = numpy.maximum(maxV, obj.mesh.getMaximum()) self.objectsMaxV = maxV self.objectsMinV = minV @@ -365,10 +366,11 @@ class previewPanel(wx.Panel): if obj.mesh == None: continue - for v in obj.mesh.vertexes: - v.z -= minV.z - v.x -= minV.x + (maxV.x - minV.x) / 2 - v.y -= minV.y + (maxV.y - minV.y) / 2 + obj.mesh.vertexes -= numpy.array([minV[0] + (maxV[0] - minV[0]) / 2, minV[1] + (maxV[1] - minV[1]) / 2, minV[2]]) + #for v in obj.mesh.vertexes: + # v[2] -= minV[2] + # v[0] -= minV[0] + (maxV[0] - minV[0]) / 2 + # v[1] -= minV[1] + (maxV[1] - minV[1]) / 2 obj.mesh.getMinimumZ() obj.dirty = True self.glCanvas.Refresh() @@ -461,7 +463,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas): glTranslate(0,0,-self.parent.gcode.layerList[self.parent.layerSpin.GetValue()][0].list[-1].z) else: if self.parent.objectsMaxV != None: - glTranslate(0,0,-self.parent.objectsMaxV.z * profile.getProfileSettingFloat('model_scale') / 2) + glTranslate(0,0,-self.parent.objectsMaxV[2] * profile.getProfileSettingFloat('model_scale') / 2) else: glScale(1.0/self.zoom, 1.0/self.zoom, 1.0) glTranslate(self.offsetX, self.offsetY, 0.0) @@ -610,11 +612,11 @@ class PreviewGLCanvas(glcanvas.GLCanvas): modelScale = profile.getProfileSettingFloat('model_scale') modelSize = (obj.mesh.getMaximum() - obj.mesh.getMinimum()) * modelScale glPushMatrix() - glTranslate(-(modelSize.x+10)*(multiX-1)/2,-(modelSize.y+10)*(multiY-1)/2, 0) + glTranslate(-(modelSize[0]+10)*(multiX-1)/2,-(modelSize[1]+10)*(multiY-1)/2, 0) for mx in xrange(0, multiX): for my in xrange(0, multiY): glPushMatrix() - glTranslate((modelSize.x+10)*mx,(modelSize.y+10)*my, 0) + glTranslate((modelSize[0]+10)*mx,(modelSize[1]+10)*my, 0) glScalef(modelScale, modelScale, modelScale) glCallList(obj.displayList) glPopMatrix() diff --git a/Cura/gui/projectPlanner.py b/Cura/gui/projectPlanner.py index 951037bd..f09d999a 100644 --- a/Cura/gui/projectPlanner.py +++ b/Cura/gui/projectPlanner.py @@ -3,9 +3,9 @@ import __init__ import wx, os, platform, types, webbrowser, math, subprocess, threading, time, re import ConfigParser +import numpy from wx import glcanvas -import wx try: import OpenGL OpenGL.ERROR_CHECKING = False @@ -55,18 +55,15 @@ class ProjectObject(stl.stlModel): self.modelDisplayList = None self.modelDirty = False - self.origonalVertexes = list(self.vertexes) - for i in xrange(0, len(self.origonalVertexes)): - self.origonalVertexes[i] = self.origonalVertexes[i].copy() self.getMinimumZ() - self.centerX = -self.getMinimum().x + 5 - self.centerY = -self.getMinimum().y + 5 + self.centerX = -self.getMinimum()[0] + 5 + self.centerY = -self.getMinimum()[1] + 5 self.updateModelTransform() - self.centerX = -self.getMinimum().x + 5 - self.centerY = -self.getMinimum().y + 5 + self.centerX = -self.getMinimum()[0] + 5 + self.centerY = -self.getMinimum()[1] + 5 def isSameExceptForPosition(self, other): if self.filename != other.filename: @@ -96,10 +93,7 @@ class ProjectObject(stl.stlModel): minZ = self.getMinimumZ() minV = self.getMinimum() maxV = self.getMaximum() - for v in self.vertexes: - v.z -= minZ - v.x -= minV.x + (maxV.x - minV.x) / 2 - v.y -= minV.y + (maxV.y - minV.y) / 2 + self.vertexes -= numpy.array([minV[0] + (maxV[0] - minV[0]) / 2, minV[1] + (maxV[1] - minV[1]) / 2, minZ]) minZ = self.getMinimumZ() self.modelDirty = True @@ -125,14 +119,14 @@ class ProjectObject(stl.stlModel): return p def clampXY(self): - if self.centerX < -self.getMinimum().x * self.scale + self.parent.extruderOffset[self.extruder].x: - self.centerX = -self.getMinimum().x * self.scale + self.parent.extruderOffset[self.extruder].x - if self.centerY < -self.getMinimum().y * self.scale + self.parent.extruderOffset[self.extruder].y: - self.centerY = -self.getMinimum().y * self.scale + self.parent.extruderOffset[self.extruder].y - if self.centerX > self.parent.machineSize.x + self.parent.extruderOffset[self.extruder].x - self.getMaximum().x * self.scale: - self.centerX = self.parent.machineSize.x + self.parent.extruderOffset[self.extruder].x - self.getMaximum().x * self.scale - if self.centerY > self.parent.machineSize.y + self.parent.extruderOffset[self.extruder].y - self.getMaximum().y * self.scale: - self.centerY = self.parent.machineSize.y + self.parent.extruderOffset[self.extruder].y - self.getMaximum().y * self.scale + if self.centerX < -self.getMinimum()[0] * self.scale + self.parent.extruderOffset[self.extruder][0]: + self.centerX = -self.getMinimum()[0] * self.scale + self.parent.extruderOffset[self.extruder][0] + if self.centerY < -self.getMinimum()[1] * self.scale + self.parent.extruderOffset[self.extruder][1]: + self.centerY = -self.getMinimum()[1] * self.scale + self.parent.extruderOffset[self.extruder][1] + if self.centerX > self.parent.machineSize[0] + self.parent.extruderOffset[self.extruder][0] - self.getMaximum()[0] * self.scale: + self.centerX = self.parent.machineSize[0] + self.parent.extruderOffset[self.extruder][0] - self.getMaximum()[0] * self.scale + if self.centerY > self.parent.machineSize[1] + self.parent.extruderOffset[self.extruder][1] - self.getMaximum()[1] * self.scale: + self.centerY = self.parent.machineSize[1] + self.parent.extruderOffset[self.extruder][1] - self.getMaximum()[1] * self.scale class projectPlanner(wx.Frame): "Main user interface window" @@ -151,15 +145,15 @@ class projectPlanner(wx.Frame): self.selection = None self.printMode = 0 - self.machineSize = util3d.Vector3(profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')) - self.headSizeMin = util3d.Vector3(profile.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_min_y'),0) - self.headSizeMax = util3d.Vector3(profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_max_y'),0) + self.machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]) + self.headSizeMin = numpy.array([profile.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_min_y'),0]) + self.headSizeMax = numpy.array([profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_max_y'),0]) self.extruderOffset = [ - util3d.Vector3(0,0,0), - util3d.Vector3(profile.getPreferenceFloat('extruder_offset_x1'), profile.getPreferenceFloat('extruder_offset_y1'), 0), - util3d.Vector3(profile.getPreferenceFloat('extruder_offset_x2'), profile.getPreferenceFloat('extruder_offset_y2'), 0), - util3d.Vector3(profile.getPreferenceFloat('extruder_offset_x3'), profile.getPreferenceFloat('extruder_offset_y3'), 0)] + numpy.array([0,0,0]), + numpy.array([profile.getPreferenceFloat('extruder_offset_x1'), profile.getPreferenceFloat('extruder_offset_y1'), 0]), + numpy.array([profile.getPreferenceFloat('extruder_offset_x2'), profile.getPreferenceFloat('extruder_offset_y2'), 0]), + numpy.array([profile.getPreferenceFloat('extruder_offset_x3'), profile.getPreferenceFloat('extruder_offset_y3'), 0])] self.toolbar = toolbarUtil.Toolbar(self.panel) @@ -392,7 +386,7 @@ class projectPlanner(wx.Frame): def OnTopClick(self): self.preview.view3D = False - self.preview.zoom = self.machineSize.x / 2 + 10 + self.preview.zoom = self.machineSize[0] / 2 + 10 self.preview.offsetX = 0 self.preview.offsetY = 0 self.preview.Refresh() @@ -499,9 +493,9 @@ class projectPlanner(wx.Frame): self.listbox.SetSelection(-1) def OnAutoPlace(self, e): - bestAllowedSize = int(self.machineSize.y) + bestAllowedSize = int(self.machineSize[1]) bestArea = self._doAutoPlace(bestAllowedSize) - for i in xrange(10, int(self.machineSize.y), 10): + for i in xrange(10, int(self.machineSize[1]), 10): area = self._doAutoPlace(i) if area < bestArea: bestAllowedSize = i @@ -516,18 +510,18 @@ class projectPlanner(wx.Frame): extraSizeMax = self.headSizeMax if profile.getProfileSettingFloat('skirt_line_count') > 0: skirtSize = profile.getProfileSettingFloat('skirt_line_count') * profile.calculateEdgeWidth() + profile.getProfileSettingFloat('skirt_gap') - extraSizeMin = extraSizeMin + util3d.Vector3(skirtSize, skirtSize, 0) - extraSizeMax = extraSizeMax + util3d.Vector3(skirtSize, skirtSize, 0) + extraSizeMin = extraSizeMin + numpy.array([skirtSize, skirtSize, 0]) + extraSizeMax = extraSizeMax + numpy.array([skirtSize, skirtSize, 0]) if profile.getProfileSetting('support') != 'None': - extraSizeMin = extraSizeMin + util3d.Vector3(3.0, 0, 0) - extraSizeMax = extraSizeMax + util3d.Vector3(3.0, 0, 0) + extraSizeMin = extraSizeMin + numpy.array([3.0, 0, 0]) + extraSizeMax = extraSizeMax + numpy.array([3.0, 0, 0]) if self.printMode == 1: - extraSizeMin = util3d.Vector3(6.0, 6.0, 0) - extraSizeMax = util3d.Vector3(6.0, 6.0, 0) + extraSizeMin = numpy.array([6.0, 6.0, 0]) + extraSizeMax = numpy.array([6.0, 6.0, 0]) - if extraSizeMin.x > extraSizeMax.x: - posX = self.machineSize.x + if extraSizeMin[0] > extraSizeMax[0]: + posX = self.machineSize[0] dirX = -1 else: posX = 0 @@ -535,35 +529,35 @@ class projectPlanner(wx.Frame): posY = 0 dirY = 1 - minX = self.machineSize.x - minY = self.machineSize.y + minX = self.machineSize[0] + minY = self.machineSize[1] maxX = 0 maxY = 0 for item in self.list: - item.centerX = posX + item.getMaximum().x * item.scale * dirX - item.centerY = posY + item.getMaximum().y * item.scale * dirY - if item.centerY + item.getSize().y >= allowedSizeY: + item.centerX = posX + item.getMaximum()[0] * item.scale * dirX + item.centerY = posY + item.getMaximum()[1] * item.scale * dirY + if item.centerY + item.getSize()[1] >= allowedSizeY: if dirX < 0: - posX = minX - extraSizeMax.x - 1 + posX = minX - extraSizeMax[0] - 1 else: - posX = maxX + extraSizeMin.x + 1 + posX = maxX + extraSizeMin[0] + 1 posY = 0 - item.centerX = posX + item.getMaximum().x * item.scale * dirX - item.centerY = posY + item.getMaximum().y * item.scale * dirY - posY += item.getSize().y * item.scale * dirY + extraSizeMin.y + 1 - minX = min(minX, item.centerX - item.getSize().x * item.scale / 2) - minY = min(minY, item.centerY - item.getSize().y * item.scale / 2) - maxX = max(maxX, item.centerX + item.getSize().x * item.scale / 2) - maxY = max(maxY, item.centerY + item.getSize().y * item.scale / 2) + item.centerX = posX + item.getMaximum()[0] * item.scale * dirX + item.centerY = posY + item.getMaximum()[1] * item.scale * dirY + posY += item.getSize()[1] * item.scale * dirY + extraSizeMin[1] + 1 + minX = min(minX, item.centerX - item.getSize()[0] * item.scale / 2) + minY = min(minY, item.centerY - item.getSize()[1] * item.scale / 2) + maxX = max(maxX, item.centerX + item.getSize()[0] * item.scale / 2) + maxY = max(maxY, item.centerY + item.getSize()[1] * item.scale / 2) for item in self.list: if dirX < 0: item.centerX -= minX / 2 else: - item.centerX += (self.machineSize.x - maxX) / 2 - item.centerY += (self.machineSize.y - maxY) / 2 + item.centerX += (self.machineSize[0] - maxX) / 2 + item.centerY += (self.machineSize[1] - maxY) / 2 - if minX < 0 or maxX > self.machineSize.x: + if minX < 0 or maxX > self.machineSize[0]: return ((maxX - minX) + (maxY - minY)) * 100 return (maxX - minX) + (maxY - minY) @@ -590,8 +584,8 @@ class projectPlanner(wx.Frame): for item in self.list: if item.profile != None and os.path.isfile(item.profile): profile.loadGlobalProfile(item.profile) - put('machine_center_x', item.centerX - self.extruderOffset[item.extruder].x) - put('machine_center_y', item.centerY - self.extruderOffset[item.extruder].y) + put('machine_center_x', item.centerX - self.extruderOffset[item.extruder][0]) + put('machine_center_y', item.centerY - self.extruderOffset[item.extruder][1]) put('model_scale', item.scale) put('flip_x', item.flipX) put('flip_y', item.flipY) @@ -607,7 +601,7 @@ class projectPlanner(wx.Frame): action.temperature = profile.getProfileSettingFloat('print_temperature') action.extruder = item.extruder action.filename = item.filename - clearZ = max(clearZ, item.getMaximum().z * item.scale + 5.0) + clearZ = max(clearZ, item.getMaximum()[2] * item.scale + 5.0) action.clearZ = clearZ action.leaveResultForNextSlice = False action.usePreviousSlice = False @@ -698,7 +692,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas): wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel) self.yaw = 30 self.pitch = 60 - self.zoom = self.parent.machineSize.x / 2 + 10 + self.zoom = self.parent.machineSize[0] / 2 + 10 self.offsetX = 0 self.offsetY = 0 self.view3D = False @@ -760,32 +754,30 @@ class PreviewGLCanvas(glcanvas.GLCanvas): glTranslate(0,0,-self.zoom) glRotate(-self.pitch, 1,0,0) glRotate(self.yaw, 0,0,1) - if False: #self.parent.triangleMesh != None: - glTranslate(0,0,-self.parent.triangleMesh.getMaximum().z / 2) else: glScale(1.0/self.zoom, 1.0/self.zoom, 1.0) glTranslate(self.offsetX, self.offsetY, 0.0) - glTranslate(-self.parent.machineSize.x/2, -self.parent.machineSize.y/2, 0) + glTranslate(-self.parent.machineSize[0]/2, -self.parent.machineSize[1]/2, 0) self.OnDraw() self.SwapBuffers() def OnDraw(self): machineSize = self.parent.machineSize - opengl.DrawMachine(machineSize) + opengl.DrawMachine(util3d.Vector3(machineSize[0], machineSize[1], machineSize[2])) extraSizeMin = self.parent.headSizeMin extraSizeMax = self.parent.headSizeMax if profile.getProfileSettingFloat('skirt_line_count') > 0: skirtSize = profile.getProfileSettingFloat('skirt_line_count') * profile.calculateEdgeWidth() + profile.getProfileSettingFloat('skirt_gap') - extraSizeMin = extraSizeMin + util3d.Vector3(skirtSize, skirtSize, 0) - extraSizeMax = extraSizeMax + util3d.Vector3(skirtSize, skirtSize, 0) + extraSizeMin = extraSizeMin + numpy.array([skirtSize, skirtSize, 0]) + extraSizeMax = extraSizeMax + numpy.array([skirtSize, skirtSize, 0]) if profile.getProfileSetting('support') != 'None': - extraSizeMin = extraSizeMin + util3d.Vector3(3.0, 0, 0) - extraSizeMax = extraSizeMax + util3d.Vector3(3.0, 0, 0) + extraSizeMin = extraSizeMin + numpy.array([3.0, 0, 0]) + extraSizeMax = extraSizeMax + numpy.array([3.0, 0, 0]) if self.parent.printMode == 1: - extraSizeMin = util3d.Vector3(6.0, 6.0, 0) - extraSizeMax = util3d.Vector3(6.0, 6.0, 0) + extraSizeMin = numpy.array([6.0, 6.0, 0]) + extraSizeMax = numpy.array([6.0, 6.0, 0]) for item in self.parent.list: item.validPlacement = True @@ -793,13 +785,13 @@ class PreviewGLCanvas(glcanvas.GLCanvas): for idx1 in xrange(0, len(self.parent.list)): item = self.parent.list[idx1] - iMin1 = item.getMinimum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) - extraSizeMin - self.parent.extruderOffset[item.extruder] - iMax1 = item.getMaximum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) + extraSizeMax - self.parent.extruderOffset[item.extruder] + iMin1 = (item.getMinimum() * item.scale) + numpy.array([item.centerX, item.centerY, 0]) - extraSizeMin - self.parent.extruderOffset[item.extruder] + iMax1 = (item.getMaximum() * item.scale) + numpy.array([item.centerX, item.centerY, 0]) + extraSizeMax - self.parent.extruderOffset[item.extruder] for idx2 in xrange(0, idx1): item2 = self.parent.list[idx2] - iMin2 = item2.getMinimum() * item2.scale + util3d.Vector3(item2.centerX, item2.centerY, 0) - iMax2 = item2.getMaximum() * item2.scale + util3d.Vector3(item2.centerX, item2.centerY, 0) - if item != item2 and iMax1.x >= iMin2.x and iMin1.x <= iMax2.x and iMax1.y >= iMin2.y and iMin1.y <= iMax2.y: + iMin2 = (item2.getMinimum() * item2.scale) + numpy.array([item2.centerX, item2.centerY, 0]) + iMax2 = (item2.getMaximum() * item2.scale) + numpy.array([item2.centerX, item2.centerY, 0]) + if item != item2 and iMax1[0] >= iMin2[0] and iMin1[0] <= iMax2[0] and iMax1[1] >= iMin2[1] and iMin1[1] <= iMax2[1]: item.validPlacement = False item2.gotHit = True @@ -959,8 +951,8 @@ class ProjectSliceProgressWindow(wx.Frame): line = p.stdout.readline() self.returnCode = p.wait() - put('machine_center_x', action.centerX - self.extruderOffset[action.extruder].x) - put('machine_center_y', action.centerY - self.extruderOffset[action.extruder].y) + put('machine_center_x', action.centerX - self.extruderOffset[action.extruder][0]) + put('machine_center_y', action.centerY - self.extruderOffset[action.extruder][1]) put('clear_z', action.clearZ) put('extruder', action.extruder) put('print_temperature', action.temperature) @@ -1089,8 +1081,8 @@ class preferencesDialog(configBase.configWindowBase): self.Fit() def OnClose(self, e): - self.parent.headSizeMin = util3d.Vector3(profile.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_min_y'),0) - self.parent.headSizeMax = util3d.Vector3(profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_max_y'),0) + self.parent.headSizeMin = numpy.array([profile.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_min_y'),0]) + self.parent.headSizeMax = numpy.array([profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_max_y'),0]) self.parent.Refresh() self.MakeModal(False) diff --git a/Cura/util/mesh.py b/Cura/util/mesh.py index 30e29521..0a943b1e 100644 --- a/Cura/util/mesh.py +++ b/Cura/util/mesh.py @@ -2,41 +2,36 @@ import sys, math, re, os, struct, time import util3d -class meshFace(object): - def __init__(self, v0, v1, v2): - self.v = [v0, v1, v2] +import numpy class mesh(object): def __init__(self): - self.faces = [] - self.vertexes = [] + self.vertexes = None + self.origonalVertexes = None + self.vertexCount = 0 - def addFace(self, v0, v1, v2): - self.vertexes.append(v0) - self.vertexes.append(v1) - self.vertexes.append(v2) - self.faces.append(meshFace(v0, v1, v2)) + def addVertex(self, x, y, z): + n = self.vertexCount + self.origonalVertexes[n][0] = x + self.origonalVertexes[n][1] = y + self.origonalVertexes[n][2] = z + self.vertexCount += 1 + + def _prepareVertexCount(self, vertexNumber): + #Set the amount of faces before loading data in them. This way we can create the numpy arrays before we fill them. + self.origonalVertexes = numpy.zeros((vertexNumber, 3), float) + self.normal = numpy.zeros((vertexNumber / 3, 3)) + self.vertexCount = 0 def _postProcessAfterLoad(self): - self.origonalVertexes = list(self.vertexes) - for i in xrange(0, len(self.origonalVertexes)): - self.origonalVertexes[i] = self.origonalVertexes[i].copy() + self.vertexes = self.origonalVertexes.copy() self.getMinimumZ() def getMinimumZ(self): - minv = self.vertexes[0].copy() - maxv = self.vertexes[0].copy() - for v in self.vertexes: - minv.x = min(minv.x, v.x) - minv.y = min(minv.y, v.y) - minv.z = min(minv.z, v.z) - maxv.x = max(maxv.x, v.x) - maxv.y = max(maxv.y, v.y) - maxv.z = max(maxv.z, v.z) - self.min = minv - self.max = maxv - self.size = maxv - minv - return self.min.z + self.min = self.vertexes.min(0) + self.max = self.vertexes.max(0) + self.size = self.max - self.min + return self.min[2] def getMaximum(self): return self.max @@ -62,23 +57,23 @@ class mesh(object): mat11 = math.cos(rotate) * scaleY for i in xrange(0, len(self.origonalVertexes)): - x = self.origonalVertexes[i].x - y = self.origonalVertexes[i].y - z = self.origonalVertexes[i].z + x = self.origonalVertexes[i][0] + y = self.origonalVertexes[i][1] + z = self.origonalVertexes[i][2] if swapXZ: x, z = z, x if swapYZ: y, z = z, y - self.vertexes[i].x = x * mat00 + y * mat01 - self.vertexes[i].y = x * mat10 + y * mat11 - self.vertexes[i].z = z * scaleZ + self.vertexes[i][0] = x * mat00 + y * mat01 + self.vertexes[i][1] = x * mat10 + y * mat11 + self.vertexes[i][2] = z * scaleZ - for face in self.faces: - v1 = face.v[0] - v2 = face.v[1] - v3 = face.v[2] - face.normal = (v2 - v1).cross(v3 - v1) - face.normal.normalize() + for i in xrange(0, len(self.origonalVertexes), 3): + v1 = self.vertexes[i] + v2 = self.vertexes[i+1] + v3 = self.vertexes[i+2] + self.normal[i/3] = numpy.cross((v2 - v1), (v3 - v1)) + self.normal[i/3] /= (self.normal[i/3] * self.normal[i/3]).sum() self.getMinimumZ() diff --git a/Cura/util/stl.py b/Cura/util/stl.py index 72b34254..7e422679 100644 --- a/Cura/util/stl.py +++ b/Cura/util/stl.py @@ -1,6 +1,5 @@ import sys, math, re, os, struct, time -import util3d import mesh class stlModel(mesh.mesh): @@ -11,7 +10,7 @@ class stlModel(mesh.mesh): f = open(filename, "rb") if f.read(5).lower() == "solid": self._loadAscii(f) - if not self.faces: + if self.vertexCount < 3: f.seek(5, os.SEEK_SET) self._loadBinary(f) else: @@ -22,31 +21,28 @@ class stlModel(mesh.mesh): return self def _loadAscii(self, f): + cnt = 0 + for line in f: + if 'vertex' in line: + cnt += 1 + self._prepareVertexCount(int(cnt)) + f.seek(5, os.SEEK_SET) cnt = 0 for line in f: if 'vertex' in line: data = line.split() - if cnt == 0: - v0 = util3d.Vector3(float(data[1]), float(data[2]), float(data[3])) - cnt = 1 - elif cnt == 1: - v1 = util3d.Vector3(float(data[1]), float(data[2]), float(data[3])) - cnt = 2 - elif cnt == 2: - v2 = util3d.Vector3(float(data[1]), float(data[2]), float(data[3])) - self.addFace(v0, v1, v2) - cnt = 0 + self.addVertex(float(data[1]), float(data[2]), float(data[3])) def _loadBinary(self, f): #Skip the header f.read(80-5) faceCount = struct.unpack('