mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-25 15:44:04 -06:00
Merge branch '15.06' of https://github.com/Ultimaker/Cura into 15.06
Someone else pushed changes before I did
This commit is contained in:
commit
1acd3ee2a5
16 changed files with 190 additions and 51 deletions
26
CHANGES
26
CHANGES
|
@ -7,6 +7,22 @@ Cura 15.06 is a new release built from the ground up on a completely new
|
||||||
framework called Uranium. This framework has been designed to make it easier to
|
framework called Uranium. This framework has been designed to make it easier to
|
||||||
extend Cura with additional functionality as well as provide a cleaner UI.
|
extend Cura with additional functionality as well as provide a cleaner UI.
|
||||||
|
|
||||||
|
Changes since 15.05.95
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
* Fixed: Selection ghost remains visible after deleting an object
|
||||||
|
* Fixed: Window does not show up immediately after starting application on OSX
|
||||||
|
* Fixed: Added display of rotation angle during rotation
|
||||||
|
* Fixed: Object changes position while rotating/scaling
|
||||||
|
* Fixed: Loading improvements in the layer view
|
||||||
|
* Fixed: Added application icons
|
||||||
|
* Fixed: Improved feedback when loading models
|
||||||
|
* Fixed: Eject device on MacOSX now provides proper feedback
|
||||||
|
* Fixed: Make it possible to show retraction settings for UM2
|
||||||
|
* Fixed: Opening the machine preferences page will switch to the first available machine
|
||||||
|
* Fixed: Improved tool handle hit area size
|
||||||
|
* Fixed: Render lines with a thickness based on screen DPI
|
||||||
|
|
||||||
Changes since 15.05.94
|
Changes since 15.05.94
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
@ -150,18 +166,8 @@ For an up to date list of all known issues, please see
|
||||||
https://github.com/Ultimaker/Cura/issues and
|
https://github.com/Ultimaker/Cura/issues and
|
||||||
https://github.com/Ultimaker/Uranium/issues .
|
https://github.com/Ultimaker/Uranium/issues .
|
||||||
|
|
||||||
* The application has no application icon yet.
|
|
||||||
* The Windows version starts a console before starting the
|
|
||||||
application. This is intentional for the beta and it will be
|
|
||||||
removed for the final version.
|
|
||||||
* Opening the machine preferences page will switch to the first
|
|
||||||
available machine instead of keeping the current machine
|
|
||||||
selected.
|
|
||||||
* Some OBJ files are rendered as black objects due to missing
|
* Some OBJ files are rendered as black objects due to missing
|
||||||
normals.
|
normals.
|
||||||
* The developer documentation for Uranium (available at
|
|
||||||
http://software.ultimaker.com/uranium/index.html) is not yet
|
|
||||||
complete.
|
|
||||||
* Disabling plugins does not work correctly yet.
|
* Disabling plugins does not work correctly yet.
|
||||||
* Unicorn occasionally still requires feeding. Do not feed it
|
* Unicorn occasionally still requires feeding. Do not feed it
|
||||||
after midnight.
|
after midnight.
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty
|
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty, QUrl
|
||||||
|
from PyQt5.QtGui import QDesktopServices
|
||||||
|
|
||||||
|
from UM.Event import CallFunctionEvent
|
||||||
|
from UM.Application import Application
|
||||||
|
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
|
@ -8,8 +12,16 @@ class CuraActions(QObject):
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def openDocumentation(self):
|
def openDocumentation(self):
|
||||||
webbrowser.open("http://ultimaker.com/en/support/software")
|
# Starting a web browser from a signal handler connected to a menu will crash on windows.
|
||||||
|
# So instead, defer the call to the next run of the event loop, since that does work.
|
||||||
|
# Note that weirdly enough, only signal handlers that open a web browser fail like that.
|
||||||
|
event = CallFunctionEvent(self._openUrl, [QUrl("http://ultimaker.com/en/support/software")], {})
|
||||||
|
Application.getInstance().functionEvent(event)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def openBugReportPage(self):
|
def openBugReportPage(self):
|
||||||
webbrowser.open("http://github.com/Ultimaker/Cura/issues")
|
event = CallFunctionEvent(self._openUrl, [QUrl("http://github.com/Ultimaker/Cura/issues")], {})
|
||||||
|
Application.getInstance().functionEvent(event)
|
||||||
|
|
||||||
|
def _openUrl(self, url):
|
||||||
|
QDesktopServices.openUrl(url)
|
|
@ -85,7 +85,7 @@ class CuraApplication(QtApplication):
|
||||||
if not os.path.isfile(f):
|
if not os.path.isfile(f):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self._recent_files.append(f)
|
self._recent_files.append(QUrl.fromLocalFile(f))
|
||||||
|
|
||||||
## Handle loading of all plugin types (and the backend explicitly)
|
## Handle loading of all plugin types (and the backend explicitly)
|
||||||
# \sa PluginRegistery
|
# \sa PluginRegistery
|
||||||
|
@ -215,6 +215,9 @@ class CuraApplication(QtApplication):
|
||||||
def deleteObject(self, object_id):
|
def deleteObject(self, object_id):
|
||||||
object = self.getController().getScene().findObject(object_id)
|
object = self.getController().getScene().findObject(object_id)
|
||||||
|
|
||||||
|
if not object and object_id != 0: #Workaround for tool handles overlapping the selected object
|
||||||
|
object = Selection.getSelectedObject(0)
|
||||||
|
|
||||||
if object:
|
if object:
|
||||||
op = RemoveSceneNodeOperation(object)
|
op = RemoveSceneNodeOperation(object)
|
||||||
op.push()
|
op.push()
|
||||||
|
@ -224,6 +227,9 @@ class CuraApplication(QtApplication):
|
||||||
def multiplyObject(self, object_id, count):
|
def multiplyObject(self, object_id, count):
|
||||||
node = self.getController().getScene().findObject(object_id)
|
node = self.getController().getScene().findObject(object_id)
|
||||||
|
|
||||||
|
if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
|
||||||
|
node = Selection.getSelectedObject(0)
|
||||||
|
|
||||||
if node:
|
if node:
|
||||||
op = GroupedOperation()
|
op = GroupedOperation()
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
|
@ -240,6 +246,9 @@ class CuraApplication(QtApplication):
|
||||||
def centerObject(self, object_id):
|
def centerObject(self, object_id):
|
||||||
node = self.getController().getScene().findObject(object_id)
|
node = self.getController().getScene().findObject(object_id)
|
||||||
|
|
||||||
|
if not node and object_id != 0: #Workaround for tool handles overlapping the selected object
|
||||||
|
node = Selection.getSelectedObject(0)
|
||||||
|
|
||||||
if node:
|
if node:
|
||||||
op = SetTransformOperation(node, Vector())
|
op = SetTransformOperation(node, Vector())
|
||||||
op.push()
|
op.push()
|
||||||
|
@ -330,7 +339,7 @@ class CuraApplication(QtApplication):
|
||||||
return log
|
return log
|
||||||
|
|
||||||
recentFilesChanged = pyqtSignal()
|
recentFilesChanged = pyqtSignal()
|
||||||
@pyqtProperty("QStringList", notify = recentFilesChanged)
|
@pyqtProperty("QVariantList", notify = recentFilesChanged)
|
||||||
def recentFiles(self):
|
def recentFiles(self):
|
||||||
return self._recent_files
|
return self._recent_files
|
||||||
|
|
||||||
|
@ -468,7 +477,9 @@ class CuraApplication(QtApplication):
|
||||||
self._volume.rebuild()
|
self._volume.rebuild()
|
||||||
|
|
||||||
if self.getController().getTool("ScaleTool"):
|
if self.getController().getTool("ScaleTool"):
|
||||||
self.getController().getTool("ScaleTool").setMaximumBounds(self._volume.getBoundingBox())
|
bbox = self._volume.getBoundingBox()
|
||||||
|
bbox.setBottom(0.0)
|
||||||
|
self.getController().getTool("ScaleTool").setMaximumBounds(bbox)
|
||||||
|
|
||||||
offset = machine.getSettingValueByKey("machine_platform_offset")
|
offset = machine.getSettingValueByKey("machine_platform_offset")
|
||||||
if offset:
|
if offset:
|
||||||
|
@ -508,7 +519,7 @@ class CuraApplication(QtApplication):
|
||||||
if type(job) is not ReadMeshJob:
|
if type(job) is not ReadMeshJob:
|
||||||
return
|
return
|
||||||
|
|
||||||
f = job.getFileName()
|
f = QUrl.fromLocalFile(job.getFileName())
|
||||||
if f in self._recent_files:
|
if f in self._recent_files:
|
||||||
self._recent_files.remove(f)
|
self._recent_files.remove(f)
|
||||||
|
|
||||||
|
@ -516,5 +527,9 @@ class CuraApplication(QtApplication):
|
||||||
if len(self._recent_files) > 10:
|
if len(self._recent_files) > 10:
|
||||||
del self._recent_files[10]
|
del self._recent_files[10]
|
||||||
|
|
||||||
Preferences.getInstance().setValue("cura/recent_files", ";".join(self._recent_files))
|
pref = ""
|
||||||
|
for path in self._recent_files:
|
||||||
|
pref += path.toLocalFile() + ";"
|
||||||
|
|
||||||
|
Preferences.getInstance().setValue("cura/recent_files", pref)
|
||||||
self.recentFilesChanged.emit()
|
self.recentFilesChanged.emit()
|
||||||
|
|
|
@ -24,8 +24,12 @@ class PlatformPhysics:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._controller = controller
|
self._controller = controller
|
||||||
self._controller.getScene().sceneChanged.connect(self._onSceneChanged)
|
self._controller.getScene().sceneChanged.connect(self._onSceneChanged)
|
||||||
|
self._controller.toolOperationStarted.connect(self._onToolOperationStarted)
|
||||||
|
self._controller.toolOperationStopped.connect(self._onToolOperationStopped)
|
||||||
self._build_volume = volume
|
self._build_volume = volume
|
||||||
|
|
||||||
|
self._enabled = True
|
||||||
|
|
||||||
self._change_timer = QTimer()
|
self._change_timer = QTimer()
|
||||||
self._change_timer.setInterval(100)
|
self._change_timer.setInterval(100)
|
||||||
self._change_timer.setSingleShot(True)
|
self._change_timer.setSingleShot(True)
|
||||||
|
@ -35,6 +39,9 @@ class PlatformPhysics:
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
|
|
||||||
def _onChangeTimerFinished(self):
|
def _onChangeTimerFinished(self):
|
||||||
|
if not self._enabled:
|
||||||
|
return
|
||||||
|
|
||||||
root = self._controller.getScene().getRoot()
|
root = self._controller.getScene().getRoot()
|
||||||
for node in BreadthFirstIterator(root):
|
for node in BreadthFirstIterator(root):
|
||||||
if node is root or type(node) is not SceneNode:
|
if node is root or type(node) is not SceneNode:
|
||||||
|
@ -93,3 +100,10 @@ class PlatformPhysics:
|
||||||
if node.getBoundingBox().intersectsBox(self._build_volume.getBoundingBox()) == AxisAlignedBox.IntersectionResult.FullIntersection:
|
if node.getBoundingBox().intersectsBox(self._build_volume.getBoundingBox()) == AxisAlignedBox.IntersectionResult.FullIntersection:
|
||||||
op = ScaleToBoundsOperation(node, self._build_volume.getBoundingBox())
|
op = ScaleToBoundsOperation(node, self._build_volume.getBoundingBox())
|
||||||
op.push()
|
op.push()
|
||||||
|
|
||||||
|
def _onToolOperationStarted(self, tool):
|
||||||
|
self._enabled = False
|
||||||
|
|
||||||
|
def _onToolOperationStopped(self, tool):
|
||||||
|
self._enabled = True
|
||||||
|
self._onChangeTimerFinished()
|
||||||
|
|
BIN
icons/cura-128.png
Normal file
BIN
icons/cura-128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
icons/cura-32.png
Normal file
BIN
icons/cura-32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 625 B |
BIN
icons/cura-48.png
Normal file
BIN
icons/cura-48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1 KiB |
BIN
icons/cura-64.png
Normal file
BIN
icons/cura-64.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
icons/cura.icns
Normal file
BIN
icons/cura.icns
Normal file
Binary file not shown.
BIN
icons/cura.ico
Normal file
BIN
icons/cura.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
|
@ -59,6 +59,8 @@ class CuraEngineBackend(Backend):
|
||||||
self._save_polygons = True
|
self._save_polygons = True
|
||||||
self._report_progress = True
|
self._report_progress = True
|
||||||
|
|
||||||
|
self._enabled = True
|
||||||
|
|
||||||
self.backendConnected.connect(self._onBackendConnected)
|
self.backendConnected.connect(self._onBackendConnected)
|
||||||
|
|
||||||
def getEngineCommand(self):
|
def getEngineCommand(self):
|
||||||
|
@ -86,6 +88,9 @@ class CuraEngineBackend(Backend):
|
||||||
# If False, this method will do nothing when already slicing. True by default.
|
# If False, this method will do nothing when already slicing. True by default.
|
||||||
# - report_progress: True if the slicing progress should be reported, False if not. Default is True.
|
# - report_progress: True if the slicing progress should be reported, False if not. Default is True.
|
||||||
def slice(self, **kwargs):
|
def slice(self, **kwargs):
|
||||||
|
if not self._enabled:
|
||||||
|
return
|
||||||
|
|
||||||
if self._slicing:
|
if self._slicing:
|
||||||
if not kwargs.get("force_restart", True):
|
if not kwargs.get("force_restart", True):
|
||||||
return
|
return
|
||||||
|
@ -235,3 +240,10 @@ class CuraEngineBackend(Backend):
|
||||||
if self._restart:
|
if self._restart:
|
||||||
self._onChanged()
|
self._onChanged()
|
||||||
self._restart = False
|
self._restart = False
|
||||||
|
|
||||||
|
def _onToolOperationStarted(self, tool):
|
||||||
|
self._enabled = False
|
||||||
|
|
||||||
|
def _onToolOperationStopped(self, tool):
|
||||||
|
self._enabled = True
|
||||||
|
self._onChanged()
|
||||||
|
|
|
@ -8,6 +8,7 @@ from UM.Math.Vector import Vector
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
import math
|
import math
|
||||||
|
import copy
|
||||||
|
|
||||||
class LayerData(MeshData):
|
class LayerData(MeshData):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -48,11 +49,23 @@ class LayerData(MeshData):
|
||||||
self._layers[layer].setThickness(thickness)
|
self._layers[layer].setThickness(thickness)
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
|
vertex_count = 0
|
||||||
for layer, data in self._layers.items():
|
for layer, data in self._layers.items():
|
||||||
data.build()
|
vertex_count += data.vertexCount()
|
||||||
|
|
||||||
|
vertices = numpy.empty((vertex_count, 3), numpy.float32)
|
||||||
|
colors = numpy.empty((vertex_count, 4), numpy.float32)
|
||||||
|
indices = numpy.empty((vertex_count, 2), numpy.int32)
|
||||||
|
|
||||||
|
offset = 0
|
||||||
|
for layer, data in self._layers.items():
|
||||||
|
offset = data.build(offset, vertices, colors, indices)
|
||||||
self._element_counts[layer] = data.elementCount
|
self._element_counts[layer] = data.elementCount
|
||||||
|
|
||||||
|
self.addVertices(vertices)
|
||||||
|
self.addColors(colors)
|
||||||
|
self.addIndices(indices.flatten())
|
||||||
|
|
||||||
class Layer():
|
class Layer():
|
||||||
def __init__(self, id):
|
def __init__(self, id):
|
||||||
self._id = id
|
self._id = id
|
||||||
|
@ -83,20 +96,30 @@ class Layer():
|
||||||
def setThickness(self, thickness):
|
def setThickness(self, thickness):
|
||||||
self._thickness = thickness
|
self._thickness = thickness
|
||||||
|
|
||||||
def build(self):
|
def vertexCount(self):
|
||||||
|
result = 0
|
||||||
|
for polygon in self._polygons:
|
||||||
|
result += polygon.vertexCount()
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def build(self, offset, vertices, colors, indices):
|
||||||
|
result = offset
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
if polygon._type == Polygon.InfillType or polygon._type == Polygon.SupportInfillType:
|
if polygon._type == Polygon.InfillType or polygon._type == Polygon.SupportInfillType:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
polygon.build()
|
polygon.build(result, vertices, colors, indices)
|
||||||
|
result += polygon.vertexCount()
|
||||||
self._element_count += polygon.elementCount
|
self._element_count += polygon.elementCount
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def createMesh(self):
|
def createMesh(self):
|
||||||
builder = MeshBuilder()
|
builder = MeshBuilder()
|
||||||
|
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
poly_color = polygon.getColor()
|
poly_color = polygon.getColor()
|
||||||
poly_color = Color(poly_color[0], poly_color[1], poly_color[2], poly_color[3])
|
|
||||||
|
|
||||||
points = numpy.copy(polygon.data)
|
points = numpy.copy(polygon.data)
|
||||||
if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType:
|
if polygon.type == Polygon.InfillType or polygon.type == Polygon.SkinType or polygon.type == Polygon.SupportInfillType:
|
||||||
|
@ -159,43 +182,48 @@ class Polygon():
|
||||||
self._data = data
|
self._data = data
|
||||||
self._line_width = line_width / 1000
|
self._line_width = line_width / 1000
|
||||||
|
|
||||||
def build(self):
|
def build(self, offset, vertices, colors, indices):
|
||||||
self._begin = self._mesh._vertex_count
|
self._begin = offset
|
||||||
self._mesh.addVertices(self._data)
|
|
||||||
self._end = self._begin + len(self._data) - 1
|
|
||||||
|
|
||||||
color = self.getColor()
|
color = self.getColor()
|
||||||
color[3] = 2.0
|
color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
|
||||||
|
|
||||||
colors = [color for i in range(len(self._data))]
|
for i in range(len(self._data)):
|
||||||
self._mesh.addColors(numpy.array(colors, dtype=numpy.float32) * 0.5)
|
vertices[offset + i, :] = self._data[i, :]
|
||||||
|
colors[offset + i, 0] = color.r
|
||||||
|
colors[offset + i, 1] = color.g
|
||||||
|
colors[offset + i, 2] = color.b
|
||||||
|
colors[offset + i, 3] = color.a
|
||||||
|
|
||||||
|
self._end = self._begin + len(self._data) - 1
|
||||||
|
|
||||||
indices = []
|
|
||||||
for i in range(self._begin, self._end):
|
for i in range(self._begin, self._end):
|
||||||
indices.append(i)
|
indices[i, 0] = i
|
||||||
indices.append(i + 1)
|
indices[i, 1] = i + 1
|
||||||
|
|
||||||
indices.append(self._end)
|
indices[self._end, 0] = self._end
|
||||||
indices.append(self._begin)
|
indices[self._end, 1] = self._begin
|
||||||
self._mesh.addIndices(numpy.array(indices, dtype=numpy.int32))
|
|
||||||
|
|
||||||
def getColor(self):
|
def getColor(self):
|
||||||
if self._type == self.Inset0Type:
|
if self._type == self.Inset0Type:
|
||||||
return [1.0, 0.0, 0.0, 1.0]
|
return Color(1.0, 0.0, 0.0, 1.0)
|
||||||
elif self._type == self.InsetXType:
|
elif self._type == self.InsetXType:
|
||||||
return [0.0, 1.0, 0.0, 1.0]
|
return Color(0.0, 1.0, 0.0, 1.0)
|
||||||
elif self._type == self.SkinType:
|
elif self._type == self.SkinType:
|
||||||
return [1.0, 1.0, 0.0, 1.0]
|
return Color(1.0, 1.0, 0.0, 1.0)
|
||||||
elif self._type == self.SupportType:
|
elif self._type == self.SupportType:
|
||||||
return [0.0, 1.0, 1.0, 1.0]
|
return Color(0.0, 1.0, 1.0, 1.0)
|
||||||
elif self._type == self.SkirtType:
|
elif self._type == self.SkirtType:
|
||||||
return [0.0, 1.0, 1.0, 1.0]
|
return Color(0.0, 1.0, 1.0, 1.0)
|
||||||
elif self._type == self.InfillType:
|
elif self._type == self.InfillType:
|
||||||
return [1.0, 1.0, 0.0, 1.0]
|
return Color(1.0, 1.0, 0.0, 1.0)
|
||||||
elif self._type == self.SupportInfillType:
|
elif self._type == self.SupportInfillType:
|
||||||
return [0.0, 1.0, 1.0, 1.0]
|
return Color(0.0, 1.0, 1.0, 1.0)
|
||||||
else:
|
else:
|
||||||
return [1.0, 1.0, 1.0, 1.0]
|
return Color(1.0, 1.0, 1.0, 1.0)
|
||||||
|
|
||||||
|
def vertexCount(self):
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
|
|
|
@ -7,18 +7,30 @@ from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Mesh.MeshData import MeshData
|
from UM.Mesh.MeshData import MeshData
|
||||||
|
|
||||||
|
from UM.Message import Message
|
||||||
|
from UM.i18n import i18nCatalog
|
||||||
|
|
||||||
from . import LayerData
|
from . import LayerData
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
class ProcessSlicedObjectListJob(Job):
|
class ProcessSlicedObjectListJob(Job):
|
||||||
def __init__(self, message):
|
def __init__(self, message):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._message = message
|
self._message = message
|
||||||
self._scene = Application.getInstance().getController().getScene()
|
self._scene = Application.getInstance().getController().getScene()
|
||||||
|
|
||||||
|
self._progress = None
|
||||||
|
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
|
||||||
|
self._progress = Message(catalog.i18nc("Layers View mode", "Layers"), 0, False, 0)
|
||||||
|
self._progress.show()
|
||||||
|
|
||||||
objectIdMap = {}
|
objectIdMap = {}
|
||||||
new_node = SceneNode()
|
new_node = SceneNode()
|
||||||
## Put all nodes in a dict identified by ID
|
## Put all nodes in a dict identified by ID
|
||||||
|
@ -32,6 +44,15 @@ class ProcessSlicedObjectListJob(Job):
|
||||||
settings = Application.getInstance().getActiveMachine()
|
settings = Application.getInstance().getActiveMachine()
|
||||||
layerHeight = settings.getSettingValueByKey("layer_height")
|
layerHeight = settings.getSettingValueByKey("layer_height")
|
||||||
|
|
||||||
|
center = None
|
||||||
|
if not settings.getSettingValueByKey("machine_center_is_zero"):
|
||||||
|
center = numpy.array([settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2])
|
||||||
|
else:
|
||||||
|
center = numpy.array([0.0, 0.0, 0.0])
|
||||||
|
|
||||||
|
if self._progress:
|
||||||
|
self._progress.setProgress(2)
|
||||||
|
|
||||||
mesh = MeshData()
|
mesh = MeshData()
|
||||||
for object in self._message.objects:
|
for object in self._message.objects:
|
||||||
try:
|
try:
|
||||||
|
@ -53,15 +74,37 @@ class ProcessSlicedObjectListJob(Job):
|
||||||
|
|
||||||
points[:,2] *= -1
|
points[:,2] *= -1
|
||||||
|
|
||||||
if not settings.getSettingValueByKey("machine_center_is_zero"):
|
points -= numpy.array(center)
|
||||||
center = [settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2]
|
|
||||||
points -= numpy.array(center)
|
|
||||||
|
|
||||||
layerData.addPolygon(layer.id, polygon.type, points, polygon.line_width)
|
layerData.addPolygon(layer.id, polygon.type, points, polygon.line_width)
|
||||||
|
|
||||||
|
if self._progress:
|
||||||
|
self._progress.setProgress(50)
|
||||||
|
|
||||||
# We are done processing all the layers we got from the engine, now create a mesh out of the data
|
# We are done processing all the layers we got from the engine, now create a mesh out of the data
|
||||||
layerData.build()
|
layerData.build()
|
||||||
mesh.layerData = layerData
|
mesh.layerData = layerData
|
||||||
|
|
||||||
|
if self._progress:
|
||||||
|
self._progress.setProgress(100)
|
||||||
|
|
||||||
new_node.setMeshData(mesh)
|
new_node.setMeshData(mesh)
|
||||||
new_node.setParent(self._scene.getRoot())
|
new_node.setParent(self._scene.getRoot())
|
||||||
|
|
||||||
|
view = Application.getInstance().getController().getActiveView()
|
||||||
|
if view.getPluginId() == "LayerView":
|
||||||
|
view.resetLayerData()
|
||||||
|
|
||||||
|
if self._progress:
|
||||||
|
self._progress.hide()
|
||||||
|
|
||||||
|
def _onActiveViewChanged(self):
|
||||||
|
if self.isRunning():
|
||||||
|
if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView":
|
||||||
|
if not self._progress:
|
||||||
|
self._progress = Message(catalog.i18nc("Layers View mode", "Layers"), 0, False, 0)
|
||||||
|
self._progress.show()
|
||||||
|
else:
|
||||||
|
if self._progress:
|
||||||
|
self._progress.hide()
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,9 @@ class LayerView(View):
|
||||||
def getMaxLayers(self):
|
def getMaxLayers(self):
|
||||||
return self._max_layers
|
return self._max_layers
|
||||||
|
|
||||||
|
def resetLayerData(self):
|
||||||
|
self._current_layer_mesh = None
|
||||||
|
|
||||||
def beginRendering(self):
|
def beginRendering(self):
|
||||||
scene = self.getController().getScene()
|
scene = self.getController().getScene()
|
||||||
renderer = self.getRenderer()
|
renderer = self.getRenderer()
|
||||||
|
|
|
@ -173,6 +173,10 @@ class PrinterConnection(SignalEmitter):
|
||||||
Logger.log("i", "Could not establish connection on %s: %s. Device is not arduino based." %(self._serial_port,str(e)))
|
Logger.log("i", "Could not establish connection on %s: %s. Device is not arduino based." %(self._serial_port,str(e)))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
Logger.log("i", "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port)
|
Logger.log("i", "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port)
|
||||||
|
|
||||||
|
if not self._serial or not programmer.serial:
|
||||||
|
self._is_connecting = False
|
||||||
|
return
|
||||||
|
|
||||||
# If the programmer connected, we know its an atmega based version. Not all that usefull, but it does give some debugging information.
|
# If the programmer connected, we know its an atmega based version. Not all that usefull, but it does give some debugging information.
|
||||||
for baud_rate in self._getBaudrateList(): # Cycle all baud rates (auto detect)
|
for baud_rate in self._getBaudrateList(): # Cycle all baud rates (auto detect)
|
||||||
|
|
|
@ -37,9 +37,11 @@ UM.MainWindow {
|
||||||
Instantiator {
|
Instantiator {
|
||||||
model: Printer.recentFiles
|
model: Printer.recentFiles
|
||||||
MenuItem {
|
MenuItem {
|
||||||
property url filePath: modelData;
|
text: {
|
||||||
text: (index + 1) + ". " + modelData.slice(modelData.lastIndexOf("/") + 1);
|
var path = modelData.toString()
|
||||||
onTriggered: UM.MeshFileHandler.readLocalFile(filePath);
|
return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1);
|
||||||
|
}
|
||||||
|
onTriggered: UM.MeshFileHandler.readLocalFile(modelData);
|
||||||
}
|
}
|
||||||
onObjectAdded: fileMenu.insertItem(index, object)
|
onObjectAdded: fileMenu.insertItem(index, object)
|
||||||
onObjectRemoved: fileMenu.removeItem(object)
|
onObjectRemoved: fileMenu.removeItem(object)
|
||||||
|
@ -281,8 +283,8 @@ UM.MainWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
x: base.mouseX;
|
x: base.mouseX + UM.Theme.sizes.default_margin.width;
|
||||||
y: base.mouseY;
|
y: base.mouseY + UM.Theme.sizes.default_margin.height;
|
||||||
|
|
||||||
width: childrenRect.width;
|
width: childrenRect.width;
|
||||||
height: childrenRect.height;
|
height: childrenRect.height;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue