Merge branch 'master' into recommended_sidebar

This commit is contained in:
Jack Ha 2016-12-01 11:34:41 +01:00
commit 4cd940cc5e
13 changed files with 359 additions and 174 deletions

View File

@ -49,6 +49,7 @@ Third party plugins
* [Barbarian Plugin](https://github.com/nallath/BarbarianPlugin): Simple scale tool for imperial to metric.
* [X3G Writer](https://github.com/Ghostkeeper/X3GWriter): Adds support for exporting X3G files.
* [Auto orientation](https://github.com/nallath/CuraOrientationPlugin): Calculate the optimal orientation for a model.
* [OctoPrint Plugin](https://github.com/fieldofview/OctoPrintPlugin): Send printjobs directly to OctoPrint and monitor their progress in Cura.
Making profiles for other printers
----------------------------------

View File

@ -10,6 +10,7 @@ from UM.Application import Application
from UM.Resources import Resources
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Math.Vector import Vector
from UM.Math.Matrix import Matrix
from UM.Math.Color import Color
from UM.Math.AxisAlignedBox import AxisAlignedBox
from UM.Math.Polygon import Polygon
@ -22,6 +23,7 @@ catalog = i18nCatalog("cura")
import numpy
import copy
import math
import UM.Settings.ContainerRegistry
@ -45,6 +47,7 @@ class BuildVolume(SceneNode):
self._width = 0
self._height = 0
self._depth = 0
self._shape = ""
self._shader = None
@ -139,6 +142,9 @@ class BuildVolume(SceneNode):
def setDepth(self, depth):
if depth: self._depth = depth
def setShape(self, shape):
if shape: self._shape = shape
def getDisallowedAreas(self):
return self._disallowed_areas
@ -177,27 +183,70 @@ class BuildVolume(SceneNode):
min_d = -self._depth / 2
max_d = self._depth / 2
mb = MeshBuilder()
z_fight_distance = 0.2 # Distance between buildplate and disallowed area meshes to prevent z-fighting
# Outline 'cube' of the build volume
mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
if self._shape != "elliptic":
# Outline 'cube' of the build volume
mb = MeshBuilder()
mb.addLine(Vector(min_w, min_h, min_d), Vector(max_w, min_h, min_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, max_h, min_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, max_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, max_h, min_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, min_h, max_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, min_h, max_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, max_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(max_w, min_h, max_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, min_h, min_d), Vector(min_w, min_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(max_w, min_h, min_d), Vector(max_w, min_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(min_w, max_h, min_d), Vector(min_w, max_h, max_d), color = self.VolumeOutlineColor)
mb.addLine(Vector(max_w, max_h, min_d), Vector(max_w, max_h, max_d), color = self.VolumeOutlineColor)
self.setMeshData(mb.build())
self.setMeshData(mb.build())
mb = MeshBuilder()
# Build plate grid mesh
mb = MeshBuilder()
mb.addQuad(
Vector(min_w, min_h - z_fight_distance, min_d),
Vector(max_w, min_h - z_fight_distance, min_d),
Vector(max_w, min_h - z_fight_distance, max_d),
Vector(min_w, min_h - z_fight_distance, max_d)
)
for n in range(0, 6):
v = mb.getVertex(n)
mb.setVertexUVCoordinates(n, v[0], v[2])
self._grid_mesh = mb.build()
else:
# Bottom and top 'ellipse' of the build volume
aspect = 1.0
scale_matrix = Matrix()
if self._width != 0:
# Scale circular meshes by aspect ratio if width != height
aspect = self._height / self._width
scale_matrix.compose(scale = Vector(1, 1, aspect))
mb = MeshBuilder()
mb.addArc(max_w, Vector.Unit_Y, center = (0, min_h - z_fight_distance, 0), color = self.VolumeOutlineColor)
mb.addArc(max_w, Vector.Unit_Y, center = (0, max_h, 0), color = self.VolumeOutlineColor)
self.setMeshData(mb.build().getTransformed(scale_matrix))
# Build plate grid mesh
mb = MeshBuilder()
mb.addVertex(0, min_h - z_fight_distance, 0)
mb.addArc(max_w, Vector.Unit_Y, center = Vector(0, min_h - z_fight_distance, 0))
sections = mb.getVertexCount() - 1 # Center point is not an arc section
indices = []
for n in range(0, sections - 1):
indices.append([0, n + 2, n + 1])
mb.addIndices(numpy.asarray(indices, dtype = numpy.int32))
mb.calculateNormals()
for n in range(0, mb.getVertexCount()):
v = mb.getVertex(n)
mb.setVertexUVCoordinates(n, v[0], v[2] * aspect)
self._grid_mesh = mb.build().getTransformed(scale_matrix)
# Indication of the machine origin
if self._global_container_stack.getProperty("machine_center_is_zero", "value"):
@ -205,6 +254,7 @@ class BuildVolume(SceneNode):
else:
origin = Vector(min_w, min_h, max_d)
mb = MeshBuilder()
mb.addCube(
width = self._origin_line_length,
height = self._origin_line_width,
@ -228,19 +278,6 @@ class BuildVolume(SceneNode):
)
self._origin_mesh = mb.build()
mb = MeshBuilder()
mb.addQuad(
Vector(min_w, min_h - 0.2, min_d),
Vector(max_w, min_h - 0.2, min_d),
Vector(max_w, min_h - 0.2, max_d),
Vector(min_w, min_h - 0.2, max_d)
)
for n in range(0, 6):
v = mb.getVertex(n)
mb.setVertexUVCoordinates(n, v[0], v[2])
self._grid_mesh = mb.build()
disallowed_area_height = 0.1
disallowed_area_size = 0
if self._disallowed_areas:
@ -353,6 +390,7 @@ class BuildVolume(SceneNode):
self._height = self._global_container_stack.getProperty("machine_height", "value")
self._build_volume_message.hide()
self._depth = self._global_container_stack.getProperty("machine_depth", "value")
self._shape = self._global_container_stack.getProperty("machine_shape", "value")
self._updateDisallowedAreas()
self._updateRaftThickness()
@ -581,34 +619,79 @@ class BuildVolume(SceneNode):
bottom_unreachable_border = max(bottom_unreachable_border, other_offset_y - offset_y)
half_machine_width = self._global_container_stack.getProperty("machine_width", "value") / 2
half_machine_depth = self._global_container_stack.getProperty("machine_depth", "value") / 2
if border_size - left_unreachable_border > 0:
result[extruder_id].append(Polygon(numpy.array([
[-half_machine_width, -half_machine_depth],
[-half_machine_width, half_machine_depth],
[-half_machine_width + border_size - left_unreachable_border, half_machine_depth - border_size - bottom_unreachable_border],
[-half_machine_width + border_size - left_unreachable_border, -half_machine_depth + border_size - top_unreachable_border]
], numpy.float32)))
if border_size + right_unreachable_border > 0:
result[extruder_id].append(Polygon(numpy.array([
[half_machine_width, half_machine_depth],
[half_machine_width, -half_machine_depth],
[half_machine_width - border_size - right_unreachable_border, -half_machine_depth + border_size - top_unreachable_border],
[half_machine_width - border_size - right_unreachable_border, half_machine_depth - border_size - bottom_unreachable_border]
], numpy.float32)))
if border_size + bottom_unreachable_border > 0:
result[extruder_id].append(Polygon(numpy.array([
[-half_machine_width, half_machine_depth],
[half_machine_width, half_machine_depth],
[half_machine_width - border_size - right_unreachable_border, half_machine_depth - border_size - bottom_unreachable_border],
[-half_machine_width + border_size - left_unreachable_border, half_machine_depth - border_size - bottom_unreachable_border]
], numpy.float32)))
if border_size - top_unreachable_border > 0:
result[extruder_id].append(Polygon(numpy.array([
[half_machine_width, -half_machine_depth],
[-half_machine_width, -half_machine_depth],
[-half_machine_width + border_size - left_unreachable_border, -half_machine_depth + border_size - top_unreachable_border],
[half_machine_width - border_size - right_unreachable_border, -half_machine_depth + border_size - top_unreachable_border]
], numpy.float32)))
if self._shape != "elliptic":
if border_size - left_unreachable_border > 0:
result[extruder_id].append(Polygon(numpy.array([
[-half_machine_width, -half_machine_depth],
[-half_machine_width, half_machine_depth],
[-half_machine_width + border_size - left_unreachable_border, half_machine_depth - border_size - bottom_unreachable_border],
[-half_machine_width + border_size - left_unreachable_border, -half_machine_depth + border_size - top_unreachable_border]
], numpy.float32)))
if border_size + right_unreachable_border > 0:
result[extruder_id].append(Polygon(numpy.array([
[half_machine_width, half_machine_depth],
[half_machine_width, -half_machine_depth],
[half_machine_width - border_size - right_unreachable_border, -half_machine_depth + border_size - top_unreachable_border],
[half_machine_width - border_size - right_unreachable_border, half_machine_depth - border_size - bottom_unreachable_border]
], numpy.float32)))
if border_size + bottom_unreachable_border > 0:
result[extruder_id].append(Polygon(numpy.array([
[-half_machine_width, half_machine_depth],
[half_machine_width, half_machine_depth],
[half_machine_width - border_size - right_unreachable_border, half_machine_depth - border_size - bottom_unreachable_border],
[-half_machine_width + border_size - left_unreachable_border, half_machine_depth - border_size - bottom_unreachable_border]
], numpy.float32)))
if border_size - top_unreachable_border > 0:
result[extruder_id].append(Polygon(numpy.array([
[half_machine_width, -half_machine_depth],
[-half_machine_width, -half_machine_depth],
[-half_machine_width + border_size - left_unreachable_border, -half_machine_depth + border_size - top_unreachable_border],
[half_machine_width - border_size - right_unreachable_border, -half_machine_depth + border_size - top_unreachable_border]
], numpy.float32)))
else:
sections = 32
arc_vertex = [0, half_machine_depth - border_size]
for i in range(0, sections):
quadrant = math.floor(4 * i / sections)
vertices = []
if quadrant == 0:
vertices.append([-half_machine_width, half_machine_depth])
elif quadrant == 1:
vertices.append([-half_machine_width, -half_machine_depth])
elif quadrant == 2:
vertices.append([half_machine_width, -half_machine_depth])
elif quadrant == 3:
vertices.append([half_machine_width, half_machine_depth])
vertices.append(arc_vertex)
angle = 2 * math.pi * (i + 1) / sections
arc_vertex = [-(half_machine_width - border_size) * math.sin(angle), (half_machine_depth - border_size) * math.cos(angle)]
vertices.append(arc_vertex)
result[extruder_id].append(Polygon(numpy.array(vertices, numpy.float32)))
if border_size > 0:
result[extruder_id].append(Polygon(numpy.array([
[-half_machine_width, -half_machine_depth],
[-half_machine_width, half_machine_depth],
[-half_machine_width + border_size, 0]
], numpy.float32)))
result[extruder_id].append(Polygon(numpy.array([
[-half_machine_width, half_machine_depth],
[ half_machine_width, half_machine_depth],
[ 0, half_machine_depth - border_size]
], numpy.float32)))
result[extruder_id].append(Polygon(numpy.array([
[ half_machine_width, half_machine_depth],
[ half_machine_width, -half_machine_depth],
[ half_machine_width - border_size, 0]
], numpy.float32)))
result[extruder_id].append(Polygon(numpy.array([
[ half_machine_width,-half_machine_depth],
[-half_machine_width,-half_machine_depth],
[ 0, -half_machine_depth + border_size]
], numpy.float32)))
return result

View File

@ -50,43 +50,12 @@ from PyQt5.QtGui import QColor, QIcon
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
from contextlib import contextmanager
import sys
import os.path
import numpy
import copy
import urllib
import os
import time
CONFIG_LOCK_FILENAME = "cura.lock"
## Contextmanager to create a lock file and remove it afterwards.
@contextmanager
def lockFile(filename):
try:
with open(filename, 'w') as lock_file:
lock_file.write("Lock file - Cura is currently writing")
except:
Logger.log("e", "Could not create lock file [%s]" % filename)
yield
try:
if os.path.exists(filename):
os.remove(filename)
except:
Logger.log("e", "Could not delete lock file [%s]" % filename)
## Wait for a lock file to disappear
# the maximum allowable age is settable; if the file is too old, it will be ignored too
def waitFileDisappear(filename, max_age_seconds=10, msg=""):
now = time.time()
while os.path.exists(filename) and now < os.path.getmtime(filename) + max_age_seconds and now > os.path.getmtime(filename):
if msg:
Logger.log("d", msg)
time.sleep(1)
now = time.time()
numpy.seterr(all="ignore")
@ -235,10 +204,8 @@ class CuraApplication(QtApplication):
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
# Set the filename to create if cura is writing in the config dir.
self._config_lock_filename = os.path.join(Resources.getConfigStoragePath(), CONFIG_LOCK_FILENAME)
self.waitConfigLockFile()
ContainerRegistry.getInstance().load()
with ContainerRegistry.getInstance().lockFile():
ContainerRegistry.getInstance().load()
Preferences.getInstance().addPreference("cura/active_mode", "simple")
Preferences.getInstance().addPreference("cura/recent_files", "")
@ -264,6 +231,8 @@ class CuraApplication(QtApplication):
shell
wall_thickness
top_bottom_thickness
z_seam_x
z_seam_y
infill
infill_sparse_density
material
@ -318,12 +287,6 @@ class CuraApplication(QtApplication):
self._recent_files.append(QUrl.fromLocalFile(f))
## Lock file check: if (another) Cura is writing in the Config dir.
# one may not be able to read a valid set of files while writing. Not entirely fool-proof,
# but works when you start Cura shortly after shutting down.
def waitConfigLockFile(self):
waitFileDisappear(self._config_lock_filename, max_age_seconds=10, msg="Waiting for Cura to finish writing in the config dir...")
def _onEngineCreated(self):
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
@ -351,11 +314,8 @@ class CuraApplication(QtApplication):
if not self._started: # Do not do saving during application start
return
self.waitConfigLockFile()
# When starting Cura, we check for the lockFile which is created and deleted here
with lockFile(self._config_lock_filename):
# Lock file for "more" atomically loading and saving to/from config dir.
with ContainerRegistry.getInstance().lockFile():
for instance in ContainerRegistry.getInstance().findInstanceContainers():
if not instance.isDirty():
continue
@ -1000,7 +960,7 @@ class CuraApplication(QtApplication):
def _reloadMeshFinished(self, job):
# TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh!
mesh_data = job.getResult().getMeshData()
mesh_data = job.getResult()[0].getMeshData()
if mesh_data:
job._node.setMeshData(mesh_data)
else:

View File

@ -128,11 +128,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
return WorkspaceReader.PreReadResult.accepted
def read(self, file_name):
# Load all the nodes / meshdata of the workspace
nodes = self._3mf_mesh_reader.read(file_name)
if nodes is None:
nodes = []
archive = zipfile.ZipFile(file_name, "r")
cura_file_names = [name for name in archive.namelist() if name.startswith("Cura/")]
@ -144,8 +139,19 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
# Copy a number of settings from the temp preferences to the global
global_preferences = Preferences.getInstance()
global_preferences.setValue("general/visible_settings", temp_preferences.getValue("general/visible_settings"))
global_preferences.setValue("cura/categories_expanded", temp_preferences.getValue("cura/categories_expanded"))
visible_settings = temp_preferences.getValue("general/visible_settings")
if visible_settings is None:
Logger.log("w", "Workspace did not contain visible settings. Leaving visibility unchanged")
else:
global_preferences.setValue("general/visible_settings", visible_settings)
categories_expanded = temp_preferences.getValue("cura/categories_expanded")
if categories_expanded is None:
Logger.log("w", "Workspace did not contain expanded categories. Leaving them unchanged")
else:
global_preferences.setValue("cura/categories_expanded", categories_expanded)
Application.getInstance().expandedCategoriesChanged.emit() # Notify the GUI of the change
self._id_mapping = {}
@ -388,6 +394,11 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
# Actually change the active machine.
Application.getInstance().setGlobalContainerStack(global_stack)
# Load all the nodes / meshdata of the workspace
nodes = self._3mf_mesh_reader.read(file_name)
if nodes is None:
nodes = []
return nodes
def _stripFileToId(self, file):

View File

@ -5,7 +5,7 @@ from UM.Mesh.MeshWriter import MeshWriter
from UM.Math.Vector import Vector
from UM.Logger import Logger
from UM.Math.Matrix import Matrix
from UM.Settings.SettingRelation import RelationType
from UM.Application import Application
try:
import xml.etree.cElementTree as ET
@ -78,6 +78,12 @@ class ThreeMFWriter(MeshWriter):
model_relation_element = ET.SubElement(relations_element, "Relationship", Target = "/3D/3dmodel.model", Id = "rel0", Type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel")
model = ET.Element("model", unit = "millimeter", xmlns = self._namespaces["3mf"])
# Add the version of Cura this was created with. As "CuraVersion" is not a recognised metadata name
# by 3mf itself, we place it in our own namespace.
version_metadata = ET.SubElement(model, "metadata", xmlns = self._namespaces["cura"], name = "CuraVersion")
version_metadata.text = Application.getInstance().getVersion()
resources = ET.SubElement(model, "resources")
build = ET.SubElement(model, "build")

View File

@ -163,22 +163,17 @@ class StartSliceJob(Job):
obj.id = id(object)
verts = mesh_data.getVertices()
indices = mesh_data.getIndices()
if indices is not None:
#TODO: This is a very slow way of doing it! It also locks up the GUI.
flat_vert_list = []
for face in indices:
for vert_index in face:
flat_vert_list.append(verts[vert_index])
Job.yieldThread()
verts = numpy.array(flat_vert_list)
flat_verts = numpy.take(verts, indices.flatten(), axis=0)
else:
verts = numpy.array(verts)
flat_verts = numpy.array(verts)
# Convert from Y up axes to Z up axes. Equals a 90 degree rotation.
verts[:, [1, 2]] = verts[:, [2, 1]]
verts[:, 1] *= -1
flat_verts[:, [1, 2]] = flat_verts[:, [2, 1]]
flat_verts[:, 1] *= -1
obj.vertices = verts
obj.vertices = flat_verts
self._handlePerObjectSettings(object, obj)

View File

@ -120,19 +120,73 @@ Cura.MachineAction
Column
{
CheckBox
Row
{
id: heatedBedCheckBox
text: catalog.i18nc("@option:check", "Heated Bed")
checked: String(machineHeatedBedProvider.properties.value).toLowerCase() != 'false'
onClicked: machineHeatedBedProvider.setPropertyValue("value", checked)
spacing: UM.Theme.getSize("default_margin").width
Label
{
text: catalog.i18nc("@label", "Build Plate Shape")
}
ComboBox
{
id: shapeComboBox
model: ListModel
{
id: shapesModel
Component.onCompleted:
{
// Options come in as a string-representation of an OrderedDict
var options = machineShapeProvider.properties.options.match(/^OrderedDict\(\[\((.*)\)\]\)$/);
if(options)
{
options = options[1].split("), (")
for(var i = 0; i < options.length; i++)
{
var option = options[i].substring(1, options[i].length - 1).split("', '")
shapesModel.append({text: option[1], value: option[0]});
}
}
}
}
currentIndex:
{
var currentValue = machineShapeProvider.properties.value;
var index = 0;
for(var i = 0; i < shapesModel.count; i++)
{
if(shapesModel.get(i).value == currentValue) {
index = i;
break;
}
}
return index
}
onActivated:
{
machineShapeProvider.setPropertyValue("value", shapesModel.get(index).value);
manager.forceUpdate();
}
}
}
CheckBox
{
id: centerIsZeroCheckBox
text: catalog.i18nc("@option:check", "Machine Center is Zero")
checked: String(machineCenterIsZeroProvider.properties.value).toLowerCase() != 'false'
onClicked: machineCenterIsZeroProvider.setPropertyValue("value", checked)
onClicked:
{
machineCenterIsZeroProvider.setPropertyValue("value", checked);
manager.forceUpdate();
}
}
CheckBox
{
id: heatedBedCheckBox
text: catalog.i18nc("@option:check", "Heated Bed")
checked: String(machineHeatedBedProvider.properties.value).toLowerCase() != 'false'
onClicked: machineHeatedBedProvider.setPropertyValue("value", checked)
}
}
@ -428,6 +482,16 @@ Cura.MachineAction
storeIndex: manager.containerIndex
}
UM.SettingPropertyProvider
{
id: machineShapeProvider
containerStackId: Cura.MachineManager.activeMachineId
key: "machine_shape"
watchedProperties: [ "value", "options" ]
storeIndex: manager.containerIndex
}
UM.SettingPropertyProvider
{
id: machineHeatedBedProvider

View File

@ -532,6 +532,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
Application.getInstance().showPrintMonitor.emit(True)
self._print_finished = True
self.writeStarted.emit(self)
self._gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list")
print_information = Application.getInstance().getPrintInformation()

View File

@ -700,7 +700,11 @@ class X3DReader(MeshReader):
if not c is None:
pt = c.attrib.get("point")
if pt:
co = [float(x) for x in pt.split()]
# allow the list of float values in 'point' attribute to
# be separated by commas or whitespace as per spec of
# XML encoding of X3D
# Ref ISO/IEC 19776-1:2015 : Section 5.1.2
co = [float(x) for vec in pt.split(',') for x in vec.split()]
num_verts = len(co) // 3
self.verts = numpy.empty((4, num_verts), dtype=numpy.float32)
self.verts[3,:] = numpy.ones((num_verts), dtype=numpy.float32)

View File

@ -137,6 +137,21 @@
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"machine_shape":
{
"label": "Build plate shape",
"description": "The shape of the build plate without taking unprintable areas into account.",
"default_value": "rectangular",
"type": "enum",
"options":
{
"rectangular": "Rectangular",
"elliptic": "Elliptic"
},
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"machine_height":
{
"label": "Machine height",
@ -946,17 +961,39 @@
"z_seam_type":
{
"label": "Z Seam Alignment",
"description": "Starting point of each path in a layer. When paths in consecutive layers start at the same point a vertical seam may show on the print. When aligning these at the back, the seam is easiest to remove. When placed randomly the inaccuracies at the paths' start will be less noticeable. When taking the shortest path the print will be quicker.",
"description": "Starting point of each path in a layer. When paths in consecutive layers start at the same point a vertical seam may show on the print. When aligning these near a user specified location, the seam is easiest to remove. When placed randomly the inaccuracies at the paths' start will be less noticeable. When taking the shortest path the print will be quicker.",
"type": "enum",
"options":
{
"back": "Back",
"back": "User Specified",
"shortest": "Shortest",
"random": "Random"
},
"default_value": "shortest",
"settable_per_mesh": true
},
"z_seam_x":
{
"label": "Z Seam X",
"description": "The X coordinate of the position near where to start printing each part in a layer.",
"unit": "mm",
"type": "float",
"default_value": 100.0,
"value": "machine_width / 2",
"enabled": "z_seam_type == 'back'",
"settable_per_mesh": true
},
"z_seam_y":
{
"label": "Z Seam Y",
"description": "The Y coordinate of the position near where to start printing each part in a layer.",
"unit": "mm",
"type": "float",
"default_value": 100.0,
"value": "machine_depth / 2",
"enabled": "z_seam_type == 'back'",
"settable_per_mesh": true
},
"skin_no_small_gaps_heuristic":
{
"label": "Ignore Small Z Gaps",
@ -996,7 +1033,7 @@
"default_value": 2,
"minimum_value": "0",
"minimum_value_warning": "infill_line_width",
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == 'grid' else (3 if infill_pattern == 'triangles' or infill_pattern == 'cubic' else (4 if infill_pattern == 'tetrahedral' else 1)))",
"value": "0 if infill_sparse_density == 0 else (infill_line_width * 100) / infill_sparse_density * (2 if infill_pattern == 'grid' else (3 if infill_pattern == 'triangles' or infill_pattern == 'cubic' or infill_pattern == 'cubicsubdiv' else (4 if infill_pattern == 'tetrahedral' else 1)))",
"settable_per_mesh": true
}
}
@ -1012,6 +1049,7 @@
"lines": "Lines",
"triangles": "Triangles",
"cubic": "Cubic",
"cubicsubdiv": "Cubic Subdivision",
"tetrahedral": "Tetrahedral",
"concentric": "Concentric",
"concentric_3d": "Concentric 3D",
@ -1022,6 +1060,32 @@
"value": "'lines' if infill_sparse_density > 25 else 'grid'",
"settable_per_mesh": true
},
"sub_div_rad_mult":
{
"label": "Cubic Subdivision Radius",
"description": "A multiplier on the radius from the center of each cube to check for the boundary of the model, as to decide whether this cube should be subdivided. Larger values lead to more subdivisions, i.e. more small cubes.",
"unit": "%",
"type": "float",
"default_value": 100,
"minimum_value": "0",
"minimum_value_warning": "100",
"maximum_value_warning": "200",
"enabled": "infill_sparse_density > 0 and infill_pattern == 'cubicsubdiv'",
"settable_per_mesh": true
},
"sub_div_rad_add":
{
"label": "Cubic Subdivision Shell",
"description": "An addition to the radius from the center of each cube to check for the boundary of the model, as to decide whether this cube should be subdivided. Larger values lead to a thicker shell of small cubes near the boundary of the model.",
"unit": "mm",
"type": "float",
"default_value": 0.4,
"value": "wall_line_width_x",
"minimum_value_warning": "-1 * infill_line_distance",
"maximum_value_warning": "5 * infill_line_distance",
"enabled": "infill_sparse_density > 0 and infill_pattern == 'cubicsubdiv'",
"settable_per_mesh": true
},
"infill_overlap":
{
"label": "Infill Overlap Percentage",
@ -1116,7 +1180,7 @@
"minimum_value": "0",
"maximum_value_warning": "4",
"maximum_value": "20 - math.log(infill_line_distance) / math.log(2)",
"enabled": "infill_sparse_density > 0",
"enabled": "infill_sparse_density > 0 and infill_pattern != 'cubicsubdiv'",
"settable_per_mesh": true
},
"gradual_infill_step_height":
@ -1129,7 +1193,7 @@
"minimum_value": "0.0001",
"minimum_value_warning": "3 * resolveOrValue('layer_height')",
"maximum_value_warning": "100",
"enabled": "infill_sparse_density > 0 and gradual_infill_steps > 0",
"enabled": "infill_sparse_density > 0 and gradual_infill_steps > 0 and infill_pattern != 'cubicsubdiv'",
"settable_per_mesh": true
},
"infill_before_walls":
@ -2434,20 +2498,6 @@
"settable_per_extruder": true,
"children":
{
"cool_fan_speed_0":
{
"label": "Initial Fan Speed",
"description": "The speed at which the fans spin at the start of the print. In subsequent layers the fan speed is gradually increased up to the layer corresponding to Regular Fan Speed at Height.",
"unit": "%",
"type": "float",
"minimum_value": "0",
"maximum_value": "100",
"value": "cool_fan_speed",
"default_value": 100,
"enabled": "cool_fan_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"cool_fan_speed_min":
{
"label": "Regular Fan Speed",
@ -2490,6 +2540,19 @@
"settable_per_mesh": false,
"settable_per_extruder": true
},
"cool_fan_speed_0":
{
"label": "Initial Fan Speed",
"description": "The speed at which the fans spin at the start of the print. In subsequent layers the fan speed is gradually increased up to the layer corresponding to Regular Fan Speed at Height.",
"unit": "%",
"type": "float",
"minimum_value": "0",
"maximum_value": "100",
"default_value": 0,
"enabled": "cool_fan_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"cool_fan_full_at_height":
{
"label": "Regular Fan Speed at Height",
@ -3616,7 +3679,6 @@
"type": "category",
"icon": "category_dual",
"description": "Settings used for printing with multiple extruders.",
"enabled": "machine_extruder_count > 1",
"children":
{
"prime_tower_enable":
@ -3742,17 +3804,6 @@
"settable_per_mesh": false,
"settable_per_extruder": true
},
"multiple_mesh_overlap":
{
"label": "Dual Extrusion Overlap",
"description": "Make the models printed with different extruder trains overlap a bit. This makes the different materials bond together better.",
"type": "float",
"unit": "mm",
"default_value": 0.15,
"minimum_value": "0",
"maximum_value_warning": "1.0",
"settable_per_mesh": true
},
"ooze_shield_enabled":
{
"label": "Enable Ooze Shield",
@ -3833,6 +3884,17 @@
"default_value": false,
"settable_per_mesh": true
},
"multiple_mesh_overlap":
{
"label": "Merged Meshes Overlap",
"description": "Make meshes which are touching each other overlap a bit. This makes them bond together better.",
"type": "float",
"unit": "mm",
"default_value": 0.15,
"minimum_value": "0",
"maximum_value_warning": "1.0",
"settable_per_mesh": true
},
"carve_multiple_volumes":
{
"label": "Remove Mesh Intersection",
@ -4106,6 +4168,7 @@
"type": "bool",
"default_value": false,
"enabled": "support_enable",
"limit_to_extruder": "support_infill_extruder_nr",
"settable_per_mesh": true
},
"support_conical_angle":

View File

@ -290,7 +290,7 @@ Item
Action
{
id: loadWorkspaceAction
text: catalog.i18nc("@action:inmenu menubar:file","&Open Workspace...");
text: catalog.i18nc("@action:inmenu menubar:file","&Import project...");
}
Action

View File

@ -110,7 +110,7 @@ UM.MainWindow
MenuItem
{
id: saveWorkspaceMenu
text: catalog.i18nc("@title:menu menubar:file","Save Workspace")
text: catalog.i18nc("@title:menu menubar:file","Export project")
onTriggered: UM.OutputDeviceManager.requestWriteToDevice("local_file", PrintInformation.jobName, { "filter_by_machine": false, "file_type": "workspace" });
}

View File

@ -166,15 +166,6 @@ Rectangle
anchors.topMargin: UM.Theme.getSize("default_margin").height
}
currentModeIndex:
{
var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
if(index)
{
return index;
}
return 0;
}
onCurrentModeIndexChanged:
{
UM.Preferences.setValue("cura/active_mode", currentModeIndex);
@ -268,7 +259,7 @@ Rectangle
height: settingsModeSelection.height
width: visible ? height : 0
visible: !monitoringPrint && modesListModel.get(base.currentModeIndex).showFilterButton
visible: !monitoringPrint && modesListModel.get(base.currentModeIndex) != undefined && modesListModel.get(base.currentModeIndex).showFilterButton
opacity: visible ? 1 : 0
onClicked: sidebarContents.currentItem.toggleFilterField()
@ -284,7 +275,7 @@ Rectangle
}
label: UM.RecolorImage
{
anchors.verticalCenter: control.verticalCenter
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: UM.Theme.getSize("default_margin").width / 2
@ -420,6 +411,12 @@ Rectangle
modesListModel.append({ text: catalog.i18nc("@title:tab", "Recommended"), item: sidebarSimple, showFilterButton: false })
modesListModel.append({ text: catalog.i18nc("@title:tab", "Custom"), item: sidebarAdvanced, showFilterButton: true })
sidebarContents.push({ "item": modesListModel.get(base.currentModeIndex).item, "immediate": true });
var index = parseInt(UM.Preferences.getValue("cura/active_mode"))
if(index)
{
currentModeIndex = index;
}
}
UM.SettingPropertyProvider