mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 23:17:32 -06:00
Merge branch '15.06'
* 15.06: Update changelog Correct the bottom offset we add when setting the volume for scale to max Display progress information during processing of layer data If findObject returns none but object_id != 0 use the selected object Offset the displayed rotation angle so it does not overlap the mouse cursor Abort attempts to connect if an error is thrown when connecting to the serial port Fix recent files on Windows Defer opening the webbrowser until the next run of the event loop Disable slicing and platform physics when an operation is being performed Rework LayerData mesh generation for improved performance Performance: Only calculate the platform center once, not for every poly Add application icons for all three platforms
This commit is contained in:
commit
a429e362ad
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"):
|
|
||||||
center = [settings.getSettingValueByKey("machine_width") / 2, 0.0, -settings.getSettingValueByKey("machine_depth") / 2]
|
|
||||||
points -= numpy.array(center)
|
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()
|
||||||
|
|
|
@ -174,6 +174,10 @@ class PrinterConnection(SignalEmitter):
|
||||||
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