Merge remote-tracking branch 'upstream/master' into mb-infill-line-angles

This commit is contained in:
Mark Burton 2017-01-12 08:59:34 +00:00
commit 35f35b082d
26 changed files with 11937 additions and 61 deletions

View File

@ -0,0 +1,9 @@
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
class BlockSlicingDecorator(SceneNodeDecorator):
def __init__(self):
super().__init__()
def isBlockSlicing(self):
return True

View File

@ -19,6 +19,8 @@ from UM.SaveFile import SaveFile
from UM.Scene.Selection import Selection
from UM.Scene.GroupDecorator import GroupDecorator
from UM.Settings.Validator import Validator
from UM.Message import Message
from UM.i18n import i18nCatalog
from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
@ -26,13 +28,13 @@ from UM.Operations.GroupedOperation import GroupedOperation
from UM.Operations.SetTransformOperation import SetTransformOperation
from UM.Operations.TranslateOperation import TranslateOperation
from cura.SetParentOperation import SetParentOperation
from cura.SliceableObjectDecorator import SliceableObjectDecorator
from cura.BlockSlicingDecorator import BlockSlicingDecorator
from UM.Settings.SettingDefinition import SettingDefinition, DefinitionPropertyType
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.SettingFunction import SettingFunction
from UM.i18n import i18nCatalog
from . import PlatformPhysics
from . import BuildVolume
from . import CameraAnimation
@ -135,6 +137,9 @@ class CuraApplication(QtApplication):
}
)
self._currently_loading_files = []
self._non_sliceable_extensions = []
self._machine_action_manager = MachineActionManager.MachineActionManager()
self._machine_manager = None # This is initialized on demand.
self._setting_inheritance_manager = None
@ -580,9 +585,12 @@ class CuraApplication(QtApplication):
def updatePlatformActivity(self, node = None):
count = 0
scene_bounding_box = None
is_block_slicing_node = False
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData():
if type(node) is not SceneNode or (not node.getMeshData() and not node.callDecoration("getLayerData")):
continue
if node.callDecoration("isBlockSlicing"):
is_block_slicing_node = True
count += 1
if not scene_bounding_box:
@ -592,6 +600,10 @@ class CuraApplication(QtApplication):
if other_bb is not None:
scene_bounding_box = scene_bounding_box + node.getBoundingBox()
print_information = self.getPrintInformation()
if print_information:
print_information.setPreSliced(is_block_slicing_node)
if not scene_bounding_box:
scene_bounding_box = AxisAlignedBox.Null
@ -712,7 +724,7 @@ class CuraApplication(QtApplication):
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
if type(node) is not SceneNode:
continue
if not node.getMeshData() and not node.callDecoration("isGroup"):
if (not node.getMeshData() and not node.callDecoration("getLayerData")) and not node.callDecoration("isGroup"):
continue # Node that doesnt have a mesh and is not a group.
if node.getParent() and node.getParent().callDecoration("isGroup"):
continue # Grouped nodes don't need resetting as their parent (the group) is resetted)
@ -1007,3 +1019,78 @@ class CuraApplication(QtApplication):
@pyqtSlot(str)
def log(self, msg):
Logger.log("d", msg)
@pyqtSlot(QUrl)
def readLocalFile(self, file):
if not file.isValid():
return
scene = self.getController().getScene()
for node in DepthFirstIterator(scene.getRoot()):
if node.callDecoration("isBlockSlicing"):
self.deleteAll()
break
f = file.toLocalFile()
extension = os.path.splitext(f)[1]
filename = os.path.basename(f)
if len(self._currently_loading_files) > 0:
# If a non-slicable file is already being loaded, we prevent loading of any further non-slicable files
if extension.lower() in self._non_sliceable_extensions:
message = Message(
self._i18n_catalog.i18nc("@info:status",
"Only one G-code file can be loaded at a time. Skipped importing {0}",
filename))
message.show()
return
# If file being loaded is non-slicable file, then prevent loading of any other files
extension = os.path.splitext(self._currently_loading_files[0])[1]
if extension.lower() in self._non_sliceable_extensions:
message = Message(
self._i18n_catalog.i18nc("@info:status",
"Can't open any other file if G-code is loading. Skipped importing {0}",
filename))
message.show()
return
self._currently_loading_files.append(f)
if extension in self._non_sliceable_extensions:
self.deleteAll()
job = ReadMeshJob(f)
job.finished.connect(self._readMeshFinished)
job.start()
def _readMeshFinished(self, job):
nodes = job.getResult()
filename = job.getFileName()
self._currently_loading_files.remove(filename)
for node in nodes:
node.setSelectable(True)
node.setName(os.path.basename(filename))
extension = os.path.splitext(filename)[1]
if extension.lower() in self._non_sliceable_extensions:
self.getController().setActiveView("LayerView")
view = self.getController().getActiveView()
view.resetLayerData()
view.setLayer(9999999)
view.calculateMaxLayers()
block_slicing_decorator = BlockSlicingDecorator()
node.addDecorator(block_slicing_decorator)
else:
sliceable_decorator = SliceableObjectDecorator()
node.addDecorator(sliceable_decorator)
scene = self.getController().getScene()
op = AddSceneNodeOperation(node, scene.getRoot())
op.push()
scene.sceneChanged.emit(node)
def addNonSliceableExtension(self, extension):
self._non_sliceable_extensions.append(extension)

View File

@ -0,0 +1,13 @@
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
class GCodeListDecorator(SceneNodeDecorator):
def __init__(self):
super().__init__()
self._gcode_list = []
def getGCodeList(self):
return self._gcode_list
def setGCodeList(self, list):
self._gcode_list = list

View File

@ -13,6 +13,9 @@ import math
import os.path
import unicodedata
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
## A class for processing and calculating minimum, current and maximum print time as well as managing the job name
#
# This class contains all the logic relating to calculation and slicing for the
@ -49,6 +52,8 @@ class PrintInformation(QObject):
self._material_lengths = []
self._material_weights = []
self._pre_sliced = False
self._backend = Application.getInstance().getBackend()
if self._backend:
self._backend.printDurationMessage.connect(self._onPrintDurationMessage)
@ -61,6 +66,16 @@ class PrintInformation(QObject):
currentPrintTimeChanged = pyqtSignal()
preSlicedChanged = pyqtSignal()
@pyqtProperty(bool, notify=preSlicedChanged)
def preSliced(self):
return self._pre_sliced
def setPreSliced(self, pre_sliced):
self._pre_sliced = pre_sliced
self.preSlicedChanged.emit()
@pyqtProperty(Duration, notify = currentPrintTimeChanged)
def currentPrintTime(self):
return self._current_print_time
@ -122,7 +137,9 @@ class PrintInformation(QObject):
def createJobName(self, base_name):
base_name = self._stripAccents(base_name)
self._setAbbreviatedMachineName()
if Preferences.getInstance().getValue("cura/jobname_prefix"):
if self._pre_sliced:
return catalog.i18nc("@label", "Pre-sliced file {0}", base_name)
elif Preferences.getInstance().getValue("cura/jobname_prefix"):
return self._abbr_machine + "_" + base_name
else:
return base_name
@ -150,4 +167,4 @@ class PrintInformation(QObject):
## Utility method that strips accents from characters (eg: â -> a)
def _stripAccents(self, str):
return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')
return ''.join(char for char in unicodedata.normalize('NFD', str) if unicodedata.category(char) != 'Mn')

View File

@ -0,0 +1,12 @@
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
class SliceableObjectDecorator(SceneNodeDecorator):
def __init__(self):
super().__init__()
def isSliceable(self):
return True
def __deepcopy__(self, memo):
return type(self)()

View File

@ -1,22 +1,22 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Mesh.MeshReader import MeshReader
from UM.Mesh.MeshBuilder import MeshBuilder
import os.path
import zipfile
from UM.Job import Job
from UM.Logger import Logger
from UM.Math.Matrix import Matrix
from UM.Math.Vector import Vector
from UM.Scene.SceneNode import SceneNode
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Mesh.MeshReader import MeshReader
from UM.Scene.GroupDecorator import GroupDecorator
import UM.Application
from UM.Job import Job
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
from UM.Application import Application
from cura.Settings.ExtruderManager import ExtruderManager
from cura.QualityManager import QualityManager
import os.path
import zipfile
from UM.Scene.SceneNode import SceneNode
try:
import xml.etree.cElementTree as ET
@ -263,4 +263,4 @@ class ThreeMFReader(MeshReader):
Logger.log("w", "Unrecognised unit %s used. Assuming mm instead", unit)
scale = 1
return Vector(scale, scale, scale)
return Vector(scale, scale, scale)

View File

@ -12,6 +12,8 @@ from UM.PluginRegistry import PluginRegistry
from UM.Resources import Resources
from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then.
from UM.Platform import Platform
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
import cura.Settings
@ -69,6 +71,8 @@ class CuraEngineBackend(Backend):
self._scene = Application.getInstance().getController().getScene()
self._scene.sceneChanged.connect(self._onSceneChanged)
self._pause_slicing = False
# Workaround to disable layer view processing if layer view is not active.
self._layer_view_active = False
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
@ -150,6 +154,8 @@ class CuraEngineBackend(Backend):
## Perform a slice of the scene.
def slice(self):
Logger.log("d", "Starting slice job...")
if self._pause_slicing:
return
self._slice_start_time = time()
if not self._enabled or not self._global_container_stack: # We shouldn't be slicing.
# try again in a short time
@ -183,6 +189,17 @@ class CuraEngineBackend(Backend):
self._start_slice_job.start()
self._start_slice_job.finished.connect(self._onStartSliceCompleted)
def pauseSlicing(self):
self.close()
self._pause_slicing = True
self.backendStateChange.emit(BackendState.Disabled)
def continueSlicing(self):
if self._pause_slicing:
self._pause_slicing = False
self.backendStateChange.emit(BackendState.NotStarted)
## Terminate the engine process.
def _terminate(self):
self._slicing = False
@ -298,6 +315,19 @@ class CuraEngineBackend(Backend):
if source is self._scene.getRoot():
return
should_pause = False
for node in DepthFirstIterator(self._scene.getRoot()):
if node.callDecoration("isBlockSlicing"):
should_pause = True
gcode_list = node.callDecoration("getGCodeList")
if gcode_list is not None:
self._scene.gcode_list = gcode_list
if should_pause:
self.pauseSlicing()
else:
self.continueSlicing()
if source.getMeshData() is None:
return

View File

@ -0,0 +1,303 @@
# Copyright (c) 2016 Aleph Objects, Inc.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Application import Application
from UM.Logger import Logger
from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Math.Vector import Vector
from UM.Mesh.MeshReader import MeshReader
from UM.Message import Message
from UM.Scene.SceneNode import SceneNode
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
from cura import LayerDataBuilder
from cura import LayerDataDecorator
from cura.LayerPolygon import LayerPolygon
from cura.GCodeListDecorator import GCodeListDecorator
import numpy
import math
import re
from collections import namedtuple
# Class for loading and parsing G-code files
class GCodeReader(MeshReader):
def __init__(self):
super(GCodeReader, self).__init__()
self._supported_extensions = [".gcode", ".g"]
Application.getInstance().hideMessageSignal.connect(self._onHideMessage)
self._cancelled = False
self._message = None
self._clearValues()
self._scene_node = None
self._position = namedtuple('Position', ['x', 'y', 'z', 'e'])
def _clearValues(self):
self._extruder = 0
self._layer_type = LayerPolygon.Inset0Type
self._layer = 0
self._previous_z = 0
self._layer_data_builder = LayerDataBuilder.LayerDataBuilder()
self._center_is_zero = False
@staticmethod
def _getValue(line, code):
n = line.find(code)
if n < 0:
return None
n += len(code)
pattern = re.compile("[;\s]")
match = pattern.search(line, n)
m = match.start() if match is not None else -1
try:
if m < 0:
return line[n:]
return line[n:m]
except:
return None
def _getInt(self, line, code):
value = self._getValue(line, code)
try:
return int(value)
except:
return None
def _getFloat(self, line, code):
value = self._getValue(line, code)
try:
return float(value)
except:
return None
def _onHideMessage(self, message):
if message == self._message:
self._cancelled = True
@staticmethod
def _getNullBoundingBox():
return AxisAlignedBox(minimum=Vector(0, 0, 0), maximum=Vector(10, 10, 10))
def _createPolygon(self, current_z, path):
countvalid = 0
for point in path:
if point[3] > 0:
countvalid += 1
if countvalid < 2:
return False
try:
self._layer_data_builder.addLayer(self._layer)
self._layer_data_builder.setLayerHeight(self._layer, path[0][2])
self._layer_data_builder.setLayerThickness(self._layer, math.fabs(current_z - self._previous_z))
this_layer = self._layer_data_builder.getLayer(self._layer)
except ValueError:
return False
count = len(path)
line_types = numpy.empty((count - 1, 1), numpy.int32)
line_widths = numpy.empty((count - 1, 1), numpy.float32)
# TODO: need to calculate actual line width based on E values
line_widths[:, 0] = 0.4
points = numpy.empty((count, 3), numpy.float32)
i = 0
for point in path:
points[i, 0] = point[0]
points[i, 1] = point[2]
points[i, 2] = -point[1]
if i > 0:
line_types[i - 1] = point[3]
if point[3] in [LayerPolygon.MoveCombingType, LayerPolygon.MoveRetractionType]:
line_widths[i - 1] = 0.2
i += 1
this_poly = LayerPolygon(self._layer_data_builder, self._extruder, line_types, points, line_widths)
this_poly.buildCache()
this_layer.polygons.append(this_poly)
return True
def _gCode0(self, position, params, path):
x, y, z, e = position
x = params.x if params.x is not None else x
y = params.y if params.y is not None else y
z_changed = False
if params.z is not None:
if z != params.z:
z_changed = True
self._previous_z = z
z = params.z
if params.e is not None:
if params.e > e[self._extruder]:
path.append([x, y, z, self._layer_type]) # extrusion
else:
path.append([x, y, z, LayerPolygon.MoveRetractionType]) # retraction
e[self._extruder] = params.e
else:
path.append([x, y, z, LayerPolygon.MoveCombingType])
if z_changed:
if not self._is_layers_in_file:
if len(path) > 1 and z > 0:
if self._createPolygon(z, path):
self._layer += 1
path.clear()
else:
path.clear()
return self._position(x, y, z, e)
def _gCode28(self, position, params, path):
return self._position(
params.x if params.x is not None else position.x,
params.y if params.y is not None else position.y,
0,
position.e)
def _gCode92(self, position, params, path):
if params.e is not None:
position.e[self._extruder] = params.e
return self._position(
params.x if params.x is not None else position.x,
params.y if params.y is not None else position.y,
params.z if params.z is not None else position.z,
position.e)
_gCode1 = _gCode0
def _processGCode(self, G, line, position, path):
func = getattr(self, "_gCode%s" % G, None)
x = self._getFloat(line, "X")
y = self._getFloat(line, "Y")
z = self._getFloat(line, "Z")
e = self._getFloat(line, "E")
if func is not None:
if (x is not None and x < 0) or (y is not None and y < 0):
self._center_is_zero = True
params = self._position(x, y, z, e)
return func(position, params, path)
return position
def _processTCode(self, T, line, position, path):
self._extruder = T
if self._extruder + 1 > len(position.e):
position.e.extend([0] * (self._extruder - len(position.e) + 1))
if not self._is_layers_in_file:
if len(path) > 1 and position[2] > 0:
if self._createPolygon(position[2], path):
self._layer += 1
path.clear()
else:
path.clear()
return position
_type_keyword = ";TYPE:"
_layer_keyword = ";LAYER:"
def read(self, file_name):
Logger.log("d", "Preparing to load %s" % file_name)
self._cancelled = False
scene_node = SceneNode()
scene_node.getBoundingBox = self._getNullBoundingBox # Manually set bounding box, because mesh doesn't have mesh data
glist = []
self._is_layers_in_file = False
Logger.log("d", "Opening file %s" % file_name)
with open(file_name, "r") as file:
file_lines = 0
current_line = 0
for line in file:
file_lines += 1
glist.append(line)
if not self._is_layers_in_file and line[:len(self._layer_keyword)] == self._layer_keyword:
self._is_layers_in_file = True
file.seek(0)
file_step = max(math.floor(file_lines / 100), 1)
self._clearValues()
self._message = Message(catalog.i18nc("@info:status", "Parsing G-code"), lifetime=0)
self._message.setProgress(0)
self._message.show()
Logger.log("d", "Parsing %s" % file_name)
current_position = self._position(0, 0, 0, [0])
current_path = []
for line in file:
if self._cancelled:
Logger.log("d", "Parsing %s cancelled" % file_name)
return None
current_line += 1
if current_line % file_step == 0:
self._message.setProgress(math.floor(current_line / file_lines * 100))
if len(line) == 0:
continue
if line.find(self._type_keyword) == 0:
type = line[len(self._type_keyword):].strip()
if type == "WALL-INNER":
self._layer_type = LayerPolygon.InsetXType
elif type == "WALL-OUTER":
self._layer_type = LayerPolygon.Inset0Type
elif type == "SKIN":
self._layer_type = LayerPolygon.SkinType
elif type == "SKIRT":
self._layer_type = LayerPolygon.SkirtType
elif type == "SUPPORT":
self._layer_type = LayerPolygon.SupportType
elif type == "FILL":
self._layer_type = LayerPolygon.InfillType
if self._is_layers_in_file and line[:len(self._layer_keyword)] == self._layer_keyword:
try:
layer_number = int(line[len(self._layer_keyword):])
self._createPolygon(current_position[2], current_path)
current_path.clear()
self._layer = layer_number
except:
pass
if line[0] == ";":
continue
G = self._getInt(line, "G")
if G is not None:
current_position = self._processGCode(G, line, current_position, current_path)
T = self._getInt(line, "T")
if T is not None:
current_position = self._processTCode(T, line, current_position, current_path)
if not self._is_layers_in_file and len(current_path) > 1 and current_position[2] > 0:
if self._createPolygon(current_position[2], current_path):
self._layer += 1
current_path.clear()
layer_mesh = self._layer_data_builder.build()
decorator = LayerDataDecorator.LayerDataDecorator()
decorator.setLayerData(layer_mesh)
scene_node.addDecorator(decorator)
gcode_list_decorator = GCodeListDecorator()
gcode_list_decorator.setGCodeList(glist)
scene_node.addDecorator(gcode_list_decorator)
Logger.log("d", "Finished parsing %s" % file_name)
self._message.hide()
if self._layer == 0:
Logger.log("w", "File %s doesn't contain any valid layers" % file_name)
settings = Application.getInstance().getGlobalContainerStack()
machine_width = settings.getProperty("machine_width", "value")
machine_depth = settings.getProperty("machine_depth", "value")
if not self._center_is_zero:
scene_node.setPosition(Vector(-machine_width / 2, 0, machine_depth / 2))
Logger.log("d", "Loaded %s" % file_name)
return scene_node

View File

@ -0,0 +1,33 @@
# Copyright (c) 2016 Aleph Objects, Inc.
# Cura is released under the terms of the AGPLv3 or higher.
from . import GCodeReader
from UM.i18n import i18nCatalog
i18n_catalog = i18nCatalog("cura")
def getMetaData():
return {
"plugin": {
"name": i18n_catalog.i18nc("@label", "G-code Reader"),
"author": "Victor Larchenko",
"version": "1.0",
"description": i18n_catalog.i18nc("@info:whatsthis", "Allows loading and displaying G-code files."),
"api": 3
},
"mesh_reader": [
{
"extension": "gcode",
"description": i18n_catalog.i18nc("@item:inlistbox", "G-code File")
},
{
"extension": "g",
"description": i18n_catalog.i18nc("@item:inlistbox", "G File")
}
]
}
def register(app):
app.addNonSliceableExtension(".gcode")
app.addNonSliceableExtension(".g")
return { "mesh_reader": GCodeReader.GCodeReader() }

View File

@ -45,10 +45,11 @@ class LayerPass(RenderPass):
tool_handle_batch = RenderBatch(self._tool_handle_shader, type = RenderBatch.RenderType.Overlay)
for node in DepthFirstIterator(self._scene.getRoot()):
if isinstance(node, ToolHandle):
tool_handle_batch.addItem(node.getWorldTransformation(), mesh = node.getSolidMesh())
elif isinstance(node, SceneNode) and node.getMeshData() and node.isVisible():
elif isinstance(node, SceneNode) and (node.getMeshData() or node.callDecoration("isBlockSlicing")) and node.isVisible():
layer_data = node.callDecoration("getLayerData")
if not layer_data:
continue

View File

@ -119,7 +119,7 @@ class LayerView(View):
continue
if not node.render(renderer):
if node.getMeshData() and node.isVisible():
if (node.getMeshData()) and node.isVisible():
renderer.queueNode(node, transparent = True, shader = self._ghost_shader)
def setLayer(self, value):

View File

@ -1,7 +1,7 @@
# Copyright (c) 2015 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.
# Cura is released under the terms of the AGPLv3 or higher.
import platform
from UM.Platform import Platform
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@ -18,15 +18,15 @@ def getMetaData():
}
def register(app):
if platform.system() == "Windows":
if Platform.isWindows():
from . import WindowsRemovableDrivePlugin
return { "output_device": WindowsRemovableDrivePlugin.WindowsRemovableDrivePlugin() }
elif platform.system() == "Darwin":
elif Platform.isOSX():
from . import OSXRemovableDrivePlugin
return { "output_device": OSXRemovableDrivePlugin.OSXRemovableDrivePlugin() }
elif platform.system() == "Linux":
elif Platform.isLinux():
from . import LinuxRemovableDrivePlugin
return { "output_device": LinuxRemovableDrivePlugin.LinuxRemovableDrivePlugin() }
else:
Logger.log("e", "Unsupported system %s, no removable device hotplugging support available.", platform.system())
Logger.log("e", "Unsupported system, thus no removable device hotplugging support available.")
return { }

View File

@ -43,17 +43,20 @@ class Stk500v2(ispBase.IspBase):
self.serial.flushInput()
self.serial.flushOutput()
if self.sendMessage([0x10, 0xc8, 0x64, 0x19, 0x20, 0x00, 0x53, 0x03, 0xac, 0x53, 0x00, 0x00]) != [0x10, 0x00]:
try:
if self.sendMessage([0x10, 0xc8, 0x64, 0x19, 0x20, 0x00, 0x53, 0x03, 0xac, 0x53, 0x00, 0x00]) != [0x10, 0x00]:
raise ispBase.IspError("Failed to enter programming mode")
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
if self.sendMessage([0xEE])[1] == 0x00:
self._has_checksum = True
else:
self._has_checksum = False
except ispBase.IspError:
self.close()
raise ispBase.IspError("Failed to enter programming mode")
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
if self.sendMessage([0xEE])[1] == 0x00:
self._has_checksum = True
else:
self._has_checksum = False
raise
self.serial.timeout = 5
def close(self):
if self.serial is not None:
self.serial.close()

View File

@ -1,15 +1,17 @@
# Contributed by Seva Alekseyev <sevaa@nih.gov> with National Institutes of Health, 2016
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Mesh.MeshReader import MeshReader
from UM.Mesh.MeshBuilder import MeshBuilder
from math import pi, sin, cos, sqrt
import numpy
from UM.Job import Job
from UM.Logger import Logger
from UM.Math.Matrix import Matrix
from UM.Math.Vector import Vector
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Mesh.MeshReader import MeshReader
from UM.Scene.SceneNode import SceneNode
from UM.Job import Job
from math import pi, sin, cos, sqrt
import numpy
try:
import xml.etree.cElementTree as ET

View File

@ -2831,7 +2831,7 @@
"support_z_distance":
{
"label": "Support Z Distance",
"description": "Distance from the top/bottom of the support structure to the print. This gap provides clearance to remove the supports after the model is printed. This value is rounded down to a multiple of the layer height.",
"description": "Distance from the top/bottom of the support structure to the print. This gap provides clearance to remove the supports after the model is printed. This value is rounded up to a multiple of the layer height.",
"unit": "mm",
"type": "float",
"minimum_value": "0",

View File

@ -26,10 +26,10 @@
"machine_nozzle_cool_down_speed": { "default_value": 2 },
"machine_head_with_fans_polygon": {
"default_value": [
[ 55, -20 ],
[ 55, 99999 ],
[ -49, 99999 ],
[ -49, -20 ]
[-49, 20],
[-49, -99999],
[55, 20],
[55, -99999]
]
},
"gantry_height": { "default_value": 99999 },

3546
resources/i18n/ru/cura.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -269,16 +269,16 @@ UM.MainWindow
if(drop.urls.length > 0)
{
// Import models
var imported_model = -1;
for(var i in drop.urls)
{
// There is no endsWith in this version of JS...
if ((drop.urls[i].length <= 12) || (drop.urls[i].substring(drop.urls[i].length-12) !== ".curaprofile")) {
// Drop an object
UM.MeshFileHandler.readLocalFile(drop.urls[i]);
if (i == drop.urls.length - 1)
Printer.readLocalFile(drop.urls[i]);
if (imported_model == -1)
{
var meshName = backgroundItem.getMeshName(drop.urls[i].toString());
backgroundItem.hasMesh(decodeURIComponent(meshName));
imported_model = i;
}
}
}
@ -297,6 +297,11 @@ UM.MainWindow
}
messageDialog.open()
}
if (imported_model != -1)
{
var meshName = backgroundItem.getMeshName(drop.urls[imported_model].toString())
backgroundItem.hasMesh(decodeURIComponent(meshName))
}
}
}
}
@ -406,7 +411,8 @@ UM.MainWindow
iconSource: UM.Theme.getIcon("viewmode");
style: UM.Theme.styles.tool_button;
tooltip: '';
tooltip: "";
enabled: !PrintInformation.preSliced
menu: ViewMenu { }
}
@ -731,14 +737,11 @@ UM.MainWindow
for(var i in fileUrls)
{
UM.MeshFileHandler.readLocalFile(fileUrls[i])
if (i == fileUrls.length - 1)
{
var meshName = backgroundItem.getMeshName(fileUrls.toString())
backgroundItem.hasMesh(decodeURIComponent(meshName))
}
Printer.readLocalFile(fileUrls[i])
}
var meshName = backgroundItem.getMeshName(fileUrls[0].toString())
backgroundItem.hasMesh(decodeURIComponent(meshName))
}
}

View File

@ -26,7 +26,7 @@ Menu
return (index + 1) + ". " + path.slice(path.lastIndexOf("/") + 1);
}
onTriggered: {
UM.MeshFileHandler.readLocalFile(modelData);
Printer.readLocalFile(modelData);
var meshName = backgroundItem.getMeshName(modelData.toString())
backgroundItem.hasMesh(decodeURIComponent(meshName))
}

View File

@ -11,6 +11,7 @@ Menu
{
title: catalog.i18nc("@title:menu menubar:toplevel", "&View");
id: menu
enabled: !PrintInformation.preSliced
Instantiator
{
model: UM.ViewModel { }

View File

@ -97,6 +97,7 @@ UM.PreferencesPage
append({ text: "Français", code: "fr" })
append({ text: "Italiano", code: "it" })
append({ text: "Nederlands", code: "nl" })
append({ text: "Русский", code: "ru" })
append({ text: "Türkçe", code: "tr" })
}
}

View File

@ -34,6 +34,8 @@ Rectangle {
return catalog.i18nc("@label:PrintjobStatus %1 is target operation","Ready to %1").arg(UM.OutputDeviceManager.activeDeviceShortDescription);
case 4:
return catalog.i18nc("@label:PrintjobStatus", "Unable to Slice");
case 5:
return catalog.i18nc("@label:PrintjobStatus", "Slicing unavailable");
default:
return "";
}
@ -104,7 +106,7 @@ Rectangle {
id: saveToButton
tooltip: UM.OutputDeviceManager.activeDeviceDescription;
enabled: base.backendState == 3 && base.activity == true
enabled: (base.backendState == 3 || base.backendState == 5) && base.activity == true
height: UM.Theme.getSize("save_button_save_to_button").height
anchors.top: parent.top
@ -179,7 +181,7 @@ Rectangle {
anchors.rightMargin: UM.Theme.getSize("default_margin").width
width: UM.Theme.getSize("save_button_save_to_button").height
height: UM.Theme.getSize("save_button_save_to_button").height
enabled: base.backendState == 3 && base.activity == true
enabled: (base.backendState == 3 || base.backendState == 5) && base.activity == true
visible: devicesModel.deviceCount > 1

View File

@ -167,7 +167,7 @@ Item
id: definitionsModel;
containerId: Cura.MachineManager.activeDefinitionId
visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
exclude: ["machine_settings", "command_line_settings", "infill_mesh", "infill_mesh_order"] // TODO: infill_mesh settigns are excluded hardcoded, but should be based on the fact that settable_globally, settable_per_meshgroup and settable_per_extruder are false.
exclude: ["machine_settings", "command_line_settings", "infill_mesh", "infill_mesh_order", "support_mesh", "anti_overhang_mesh"] // TODO: infill_mesh settigns are excluded hardcoded, but should be based on the fact that settable_globally, settable_per_meshgroup and settable_per_extruder are false.
expanded: Printer.expandedCategories
onExpandedChanged:
{

View File

@ -16,6 +16,7 @@ Rectangle
property int currentModeIndex;
property bool monitoringPrint: false
property bool hideSettings: PrintInformation.preSliced
Connections
{
target: Printer
@ -288,7 +289,7 @@ Rectangle
Label {
id: settingsModeLabel
text: catalog.i18nc("@label:listbox", "Print Setup");
text: !hideSettings ? catalog.i18nc("@label:listbox", "Print Setup") : catalog.i18nc("@label:listbox","Print Setup disabled\nG-code files cannot be modified");
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width;
anchors.top: headerSeparator.bottom
@ -308,7 +309,7 @@ Rectangle
anchors.rightMargin: UM.Theme.getSize("default_margin").width
anchors.top: headerSeparator.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
visible: !monitoringPrint
visible: !monitoringPrint && !hideSettings
Component{
id: wizardDelegate
Button {
@ -384,7 +385,7 @@ Rectangle
height: settingsModeSelection.height
width: visible ? height : 0
visible: !monitoringPrint && modesListModel.get(base.currentModeIndex) != undefined && modesListModel.get(base.currentModeIndex).showFilterButton
visible: !monitoringPrint && !hideSettings && modesListModel.get(base.currentModeIndex) != undefined && modesListModel.get(base.currentModeIndex).showFilterButton
opacity: visible ? 1 : 0
onClicked: sidebarContents.currentItem.toggleFilterField()
@ -432,7 +433,7 @@ Rectangle
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: base.left
anchors.right: base.right
visible: !monitoringPrint
visible: !monitoringPrint && !hideSettings
delegate: StackViewDelegate
{