mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-12 17:18:58 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
52d2fa47e9
1
.github/workflows/cicd.yml
vendored
1
.github/workflows/cicd.yml
vendored
@ -6,6 +6,7 @@ on:
|
||||
- master
|
||||
- 'WIP**'
|
||||
- '4.*'
|
||||
- 'CURA-*'
|
||||
pull_request:
|
||||
jobs:
|
||||
build:
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Copyright (c) 2020 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant # For communicating data and events to Qt.
|
||||
@ -275,6 +275,25 @@ class ExtruderManager(QObject):
|
||||
Logger.log("e", "Unable to find one or more of the extruders in %s", used_extruder_stack_ids)
|
||||
return []
|
||||
|
||||
## Get the extruder that the print will start with.
|
||||
#
|
||||
# This should mirror the implementation in CuraEngine of
|
||||
# ``FffGcodeWriter::getStartExtruder()``.
|
||||
def getInitialExtruderNr(self) -> int:
|
||||
application = cura.CuraApplication.CuraApplication.getInstance()
|
||||
global_stack = application.getGlobalContainerStack()
|
||||
|
||||
# Starts with the adhesion extruder.
|
||||
if global_stack.getProperty("adhesion_type", "value") != "none":
|
||||
return global_stack.getProperty("adhesion_extruder_nr", "value")
|
||||
|
||||
# No adhesion? Well maybe there is still support brim.
|
||||
if (global_stack.getProperty("support_enable", "value") or global_stack.getProperty("support_tree_enable", "value")) and global_stack.getProperty("support_brim_enable", "value"):
|
||||
return global_stack.getProperty("support_infill_extruder_nr", "value")
|
||||
|
||||
# REALLY no adhesion? Use the first used extruder.
|
||||
return self.getUsedExtruderStacks()[0].getProperty("extruder_nr", "value")
|
||||
|
||||
## Removes the container stack and user profile for the extruders for a specific machine.
|
||||
#
|
||||
# \param machine_id The machine to remove the extruders for.
|
||||
|
@ -17,24 +17,40 @@ cd "${PROJECT_DIR}"
|
||||
# Clone Uranium and set PYTHONPATH first
|
||||
#
|
||||
|
||||
# Check the branch to use:
|
||||
# 1. Use the Uranium branch with the branch same if it exists.
|
||||
# 2. Otherwise, use the default branch name "master"
|
||||
# Check the branch to use for Uranium.
|
||||
# It tries the following branch names and uses the first one that's available.
|
||||
# - GITHUB_HEAD_REF: the branch name of a PR. If it's not a PR, it will be empty.
|
||||
# - GITHUB_BASE_REF: the branch a PR is based on. If it's not a PR, it will be empty.
|
||||
# - GITHUB_REF: the branch name if it's a branch on the repository;
|
||||
# refs/pull/123/merge if it's a pull_request.
|
||||
# - master: the master branch. It should always exist.
|
||||
|
||||
# For debugging.
|
||||
echo "GITHUB_REF: ${GITHUB_REF}"
|
||||
echo "GITHUB_HEAD_REF: ${GITHUB_HEAD_REF}"
|
||||
echo "GITHUB_BASE_REF: ${GITHUB_BASE_REF}"
|
||||
|
||||
GIT_REF_NAME="${GITHUB_REF}"
|
||||
if [ -n "${GITHUB_BASE_REF}" ]; then
|
||||
GIT_REF_NAME="${GITHUB_BASE_REF}"
|
||||
fi
|
||||
GIT_REF_NAME="$(basename "${GIT_REF_NAME}")"
|
||||
|
||||
URANIUM_BRANCH="${GIT_REF_NAME:-master}"
|
||||
output="$(git ls-remote --heads https://github.com/Ultimaker/Uranium.git "${URANIUM_BRANCH}")"
|
||||
if [ -z "${output}" ]; then
|
||||
echo "Could not find Uranium banch ${URANIUM_BRANCH}, fallback to use master."
|
||||
URANIUM_BRANCH="master"
|
||||
fi
|
||||
GIT_REF_NAME_LIST=( "${GITHUB_HEAD_REF}" "${GITHUB_BASE_REF}" "${GITHUB_REF}" "master" )
|
||||
for git_ref_name in "${GIT_REF_NAME_LIST[@]}"
|
||||
do
|
||||
if [ -z "${git_ref_name}" ]; then
|
||||
continue
|
||||
fi
|
||||
git_ref_name="$(basename "${git_ref_name}")"
|
||||
# Skip refs/pull/1234/merge as pull requests use it as GITHUB_REF
|
||||
if [[ "${git_ref_name}" == "merge" ]]; then
|
||||
echo "Skip [${git_ref_name}]"
|
||||
continue
|
||||
fi
|
||||
URANIUM_BRANCH="${git_ref_name}"
|
||||
output="$(git ls-remote --heads https://github.com/Ultimaker/Uranium.git "${URANIUM_BRANCH}")"
|
||||
if [ -n "${output}" ]; then
|
||||
echo "Found Uranium branch [${URANIUM_BRANCH}]."
|
||||
break
|
||||
else
|
||||
echo "Could not find Uranium banch [${URANIUM_BRANCH}], try next."
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Using Uranium branch ${URANIUM_BRANCH} ..."
|
||||
git clone --depth=1 -b "${URANIUM_BRANCH}" https://github.com/Ultimaker/Uranium.git "${PROJECT_DIR}"/Uranium
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Copyright (c) 2020 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import numpy
|
||||
@ -171,146 +171,145 @@ class StartSliceJob(Job):
|
||||
self.setResult(StartJobResult.ObjectSettingError)
|
||||
return
|
||||
|
||||
with self._scene.getSceneLock():
|
||||
# Remove old layer data.
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if node.callDecoration("getLayerData") and node.callDecoration("getBuildPlateNumber") == self._build_plate_number:
|
||||
# Singe we walk through all nodes in the scene, they always have a parent.
|
||||
cast(SceneNode, node.getParent()).removeChild(node)
|
||||
break
|
||||
# Remove old layer data.
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
if node.callDecoration("getLayerData") and node.callDecoration("getBuildPlateNumber") == self._build_plate_number:
|
||||
# Singe we walk through all nodes in the scene, they always have a parent.
|
||||
cast(SceneNode, node.getParent()).removeChild(node)
|
||||
break
|
||||
|
||||
# Get the objects in their groups to print.
|
||||
object_groups = []
|
||||
if stack.getProperty("print_sequence", "value") == "one_at_a_time":
|
||||
for node in OneAtATimeIterator(self._scene.getRoot()):
|
||||
temp_list = []
|
||||
|
||||
# Node can't be printed, so don't bother sending it.
|
||||
if getattr(node, "_outside_buildarea", False):
|
||||
continue
|
||||
|
||||
# Filter on current build plate
|
||||
build_plate_number = node.callDecoration("getBuildPlateNumber")
|
||||
if build_plate_number is not None and build_plate_number != self._build_plate_number:
|
||||
continue
|
||||
|
||||
children = node.getAllChildren()
|
||||
children.append(node)
|
||||
for child_node in children:
|
||||
mesh_data = child_node.getMeshData()
|
||||
if mesh_data and mesh_data.getVertices() is not None:
|
||||
temp_list.append(child_node)
|
||||
|
||||
if temp_list:
|
||||
object_groups.append(temp_list)
|
||||
Job.yieldThread()
|
||||
if len(object_groups) == 0:
|
||||
Logger.log("w", "No objects suitable for one at a time found, or no correct order found")
|
||||
else:
|
||||
# Get the objects in their groups to print.
|
||||
object_groups = []
|
||||
if stack.getProperty("print_sequence", "value") == "one_at_a_time":
|
||||
for node in OneAtATimeIterator(self._scene.getRoot()):
|
||||
temp_list = []
|
||||
has_printing_mesh = False
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
mesh_data = node.getMeshData()
|
||||
if node.callDecoration("isSliceable") and mesh_data and mesh_data.getVertices() is not None:
|
||||
is_non_printing_mesh = bool(node.callDecoration("isNonPrintingMesh"))
|
||||
|
||||
# Find a reason not to add the node
|
||||
if node.callDecoration("getBuildPlateNumber") != self._build_plate_number:
|
||||
continue
|
||||
if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh:
|
||||
continue
|
||||
# Node can't be printed, so don't bother sending it.
|
||||
if getattr(node, "_outside_buildarea", False):
|
||||
continue
|
||||
|
||||
temp_list.append(node)
|
||||
if not is_non_printing_mesh:
|
||||
has_printing_mesh = True
|
||||
# Filter on current build plate
|
||||
build_plate_number = node.callDecoration("getBuildPlateNumber")
|
||||
if build_plate_number is not None and build_plate_number != self._build_plate_number:
|
||||
continue
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
# If the list doesn't have any model with suitable settings then clean the list
|
||||
# otherwise CuraEngine will crash
|
||||
if not has_printing_mesh:
|
||||
temp_list.clear()
|
||||
children = node.getAllChildren()
|
||||
children.append(node)
|
||||
for child_node in children:
|
||||
mesh_data = child_node.getMeshData()
|
||||
if mesh_data and mesh_data.getVertices() is not None:
|
||||
temp_list.append(child_node)
|
||||
|
||||
if temp_list:
|
||||
object_groups.append(temp_list)
|
||||
Job.yieldThread()
|
||||
if len(object_groups) == 0:
|
||||
Logger.log("w", "No objects suitable for one at a time found, or no correct order found")
|
||||
else:
|
||||
temp_list = []
|
||||
has_printing_mesh = False
|
||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||
mesh_data = node.getMeshData()
|
||||
if node.callDecoration("isSliceable") and mesh_data and mesh_data.getVertices() is not None:
|
||||
is_non_printing_mesh = bool(node.callDecoration("isNonPrintingMesh"))
|
||||
|
||||
global_stack = CuraApplication.getInstance().getGlobalContainerStack()
|
||||
if not global_stack:
|
||||
return
|
||||
extruders_enabled = {position: stack.isEnabled for position, stack in global_stack.extruders.items()}
|
||||
filtered_object_groups = []
|
||||
has_model_with_disabled_extruders = False
|
||||
associated_disabled_extruders = set()
|
||||
for group in object_groups:
|
||||
stack = global_stack
|
||||
skip_group = False
|
||||
for node in group:
|
||||
# Only check if the printing extruder is enabled for printing meshes
|
||||
is_non_printing_mesh = node.callDecoration("evaluateIsNonPrintingMesh")
|
||||
extruder_position = node.callDecoration("getActiveExtruderPosition")
|
||||
if not is_non_printing_mesh and not extruders_enabled[extruder_position]:
|
||||
skip_group = True
|
||||
has_model_with_disabled_extruders = True
|
||||
associated_disabled_extruders.add(extruder_position)
|
||||
if not skip_group:
|
||||
filtered_object_groups.append(group)
|
||||
|
||||
if has_model_with_disabled_extruders:
|
||||
self.setResult(StartJobResult.ObjectsWithDisabledExtruder)
|
||||
associated_disabled_extruders = {str(c) for c in sorted([int(p) + 1 for p in associated_disabled_extruders])}
|
||||
self.setMessage(", ".join(associated_disabled_extruders))
|
||||
return
|
||||
|
||||
# There are cases when there is nothing to slice. This can happen due to one at a time slicing not being
|
||||
# able to find a possible sequence or because there are no objects on the build plate (or they are outside
|
||||
# the build volume)
|
||||
if not filtered_object_groups:
|
||||
self.setResult(StartJobResult.NothingToSlice)
|
||||
return
|
||||
|
||||
self._buildGlobalSettingsMessage(stack)
|
||||
self._buildGlobalInheritsStackMessage(stack)
|
||||
|
||||
# Build messages for extruder stacks
|
||||
for extruder_stack in global_stack.extruderList:
|
||||
self._buildExtruderMessage(extruder_stack)
|
||||
|
||||
for group in filtered_object_groups:
|
||||
group_message = self._slice_message.addRepeatedMessage("object_lists")
|
||||
parent = group[0].getParent()
|
||||
if parent is not None and parent.callDecoration("isGroup"):
|
||||
self._handlePerObjectSettings(cast(CuraSceneNode, parent), group_message)
|
||||
|
||||
for object in group:
|
||||
mesh_data = object.getMeshData()
|
||||
if mesh_data is None:
|
||||
# Find a reason not to add the node
|
||||
if node.callDecoration("getBuildPlateNumber") != self._build_plate_number:
|
||||
continue
|
||||
if getattr(node, "_outside_buildarea", False) and not is_non_printing_mesh:
|
||||
continue
|
||||
rot_scale = object.getWorldTransformation().getTransposed().getData()[0:3, 0:3]
|
||||
translate = object.getWorldTransformation().getData()[:3, 3]
|
||||
|
||||
# This effectively performs a limited form of MeshData.getTransformed that ignores normals.
|
||||
verts = mesh_data.getVertices()
|
||||
verts = verts.dot(rot_scale)
|
||||
verts += translate
|
||||
temp_list.append(node)
|
||||
if not is_non_printing_mesh:
|
||||
has_printing_mesh = True
|
||||
|
||||
# Convert from Y up axes to Z up axes. Equals a 90 degree rotation.
|
||||
verts[:, [1, 2]] = verts[:, [2, 1]]
|
||||
verts[:, 1] *= -1
|
||||
Job.yieldThread()
|
||||
|
||||
obj = group_message.addRepeatedMessage("objects")
|
||||
obj.id = id(object)
|
||||
obj.name = object.getName()
|
||||
indices = mesh_data.getIndices()
|
||||
if indices is not None:
|
||||
flat_verts = numpy.take(verts, indices.flatten(), axis=0)
|
||||
else:
|
||||
flat_verts = numpy.array(verts)
|
||||
# If the list doesn't have any model with suitable settings then clean the list
|
||||
# otherwise CuraEngine will crash
|
||||
if not has_printing_mesh:
|
||||
temp_list.clear()
|
||||
|
||||
obj.vertices = flat_verts
|
||||
if temp_list:
|
||||
object_groups.append(temp_list)
|
||||
|
||||
self._handlePerObjectSettings(cast(CuraSceneNode, object), obj)
|
||||
global_stack = CuraApplication.getInstance().getGlobalContainerStack()
|
||||
if not global_stack:
|
||||
return
|
||||
extruders_enabled = {position: stack.isEnabled for position, stack in global_stack.extruders.items()}
|
||||
filtered_object_groups = []
|
||||
has_model_with_disabled_extruders = False
|
||||
associated_disabled_extruders = set()
|
||||
for group in object_groups:
|
||||
stack = global_stack
|
||||
skip_group = False
|
||||
for node in group:
|
||||
# Only check if the printing extruder is enabled for printing meshes
|
||||
is_non_printing_mesh = node.callDecoration("evaluateIsNonPrintingMesh")
|
||||
extruder_position = node.callDecoration("getActiveExtruderPosition")
|
||||
if not is_non_printing_mesh and not extruders_enabled[extruder_position]:
|
||||
skip_group = True
|
||||
has_model_with_disabled_extruders = True
|
||||
associated_disabled_extruders.add(extruder_position)
|
||||
if not skip_group:
|
||||
filtered_object_groups.append(group)
|
||||
|
||||
Job.yieldThread()
|
||||
if has_model_with_disabled_extruders:
|
||||
self.setResult(StartJobResult.ObjectsWithDisabledExtruder)
|
||||
associated_disabled_extruders = {str(c) for c in sorted([int(p) + 1 for p in associated_disabled_extruders])}
|
||||
self.setMessage(", ".join(associated_disabled_extruders))
|
||||
return
|
||||
|
||||
# There are cases when there is nothing to slice. This can happen due to one at a time slicing not being
|
||||
# able to find a possible sequence or because there are no objects on the build plate (or they are outside
|
||||
# the build volume)
|
||||
if not filtered_object_groups:
|
||||
self.setResult(StartJobResult.NothingToSlice)
|
||||
return
|
||||
|
||||
self._buildGlobalSettingsMessage(stack)
|
||||
self._buildGlobalInheritsStackMessage(stack)
|
||||
|
||||
# Build messages for extruder stacks
|
||||
for extruder_stack in global_stack.extruderList:
|
||||
self._buildExtruderMessage(extruder_stack)
|
||||
|
||||
for group in filtered_object_groups:
|
||||
group_message = self._slice_message.addRepeatedMessage("object_lists")
|
||||
parent = group[0].getParent()
|
||||
if parent is not None and parent.callDecoration("isGroup"):
|
||||
self._handlePerObjectSettings(cast(CuraSceneNode, parent), group_message)
|
||||
|
||||
for object in group:
|
||||
mesh_data = object.getMeshData()
|
||||
if mesh_data is None:
|
||||
continue
|
||||
rot_scale = object.getWorldTransformation().getTransposed().getData()[0:3, 0:3]
|
||||
translate = object.getWorldTransformation().getData()[:3, 3]
|
||||
|
||||
# This effectively performs a limited form of MeshData.getTransformed that ignores normals.
|
||||
verts = mesh_data.getVertices()
|
||||
verts = verts.dot(rot_scale)
|
||||
verts += translate
|
||||
|
||||
# Convert from Y up axes to Z up axes. Equals a 90 degree rotation.
|
||||
verts[:, [1, 2]] = verts[:, [2, 1]]
|
||||
verts[:, 1] *= -1
|
||||
|
||||
obj = group_message.addRepeatedMessage("objects")
|
||||
obj.id = id(object)
|
||||
obj.name = object.getName()
|
||||
indices = mesh_data.getIndices()
|
||||
if indices is not None:
|
||||
flat_verts = numpy.take(verts, indices.flatten(), axis=0)
|
||||
else:
|
||||
flat_verts = numpy.array(verts)
|
||||
|
||||
obj.vertices = flat_verts
|
||||
|
||||
self._handlePerObjectSettings(cast(CuraSceneNode, object), obj)
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
self.setResult(StartJobResult.Finished)
|
||||
|
||||
@ -344,10 +343,7 @@ class StartSliceJob(Job):
|
||||
result["time"] = time.strftime("%H:%M:%S") #Some extra settings.
|
||||
result["date"] = time.strftime("%d-%m-%Y")
|
||||
result["day"] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][int(time.strftime("%w"))]
|
||||
|
||||
initial_extruder_stack = CuraApplication.getInstance().getExtruderManager().getUsedExtruderStacks()[0]
|
||||
initial_extruder_nr = initial_extruder_stack.getProperty("extruder_nr", "value")
|
||||
result["initial_extruder_nr"] = initial_extruder_nr
|
||||
result["initial_extruder_nr"] = CuraApplication.getInstance().getExtruderManager().getInitialExtruderNr()
|
||||
|
||||
return result
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user