mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-12 20:19:13 +08:00
Merge branch 'master' of github.com:Ultimaker/Cura
This commit is contained in:
commit
0e30f0bb6b
@ -1,6 +1,6 @@
|
|||||||
# Copyright (c) 2020 Ultimaker B.V.
|
# Copyright (c) 2020 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
from typing import List, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
@ -16,18 +16,17 @@ from collections import namedtuple
|
|||||||
import numpy
|
import numpy
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
|
|
||||||
## Return object for bestSpot
|
## Return object for bestSpot
|
||||||
LocationSuggestion = namedtuple("LocationSuggestion", ["x", "y", "penalty_points", "priority"])
|
LocationSuggestion = namedtuple("LocationSuggestion", ["x", "y", "penalty_points", "priority"])
|
||||||
|
|
||||||
|
|
||||||
## The Arrange classed is used together with ShapeArray. Use it to find
|
|
||||||
# good locations for objects that you try to put on a build place.
|
|
||||||
# Different priority schemes can be defined so it alters the behavior while using
|
|
||||||
# the same logic.
|
|
||||||
#
|
|
||||||
# Note: Make sure the scale is the same between ShapeArray objects and the Arrange instance.
|
|
||||||
class Arrange:
|
class Arrange:
|
||||||
|
"""
|
||||||
|
The Arrange classed is used together with ShapeArray. Use it to find good locations for objects that you try to put
|
||||||
|
on a build place. Different priority schemes can be defined so it alters the behavior while using the same logic.
|
||||||
|
|
||||||
|
Note: Make sure the scale is the same between ShapeArray objects and the Arrange instance.
|
||||||
|
"""
|
||||||
build_volume = None # type: Optional[BuildVolume]
|
build_volume = None # type: Optional[BuildVolume]
|
||||||
|
|
||||||
def __init__(self, x, y, offset_x, offset_y, scale = 0.5):
|
def __init__(self, x, y, offset_x, offset_y, scale = 0.5):
|
||||||
@ -42,14 +41,21 @@ class Arrange:
|
|||||||
self._last_priority = 0
|
self._last_priority = 0
|
||||||
self._is_empty = True
|
self._is_empty = True
|
||||||
|
|
||||||
## Helper to create an Arranger instance
|
|
||||||
#
|
|
||||||
# Either fill in scene_root and create will find all sliceable nodes by itself,
|
|
||||||
# or use fixed_nodes to provide the nodes yourself.
|
|
||||||
# \param scene_root Root for finding all scene nodes
|
|
||||||
# \param fixed_nodes Scene nodes to be placed
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, scene_root = None, fixed_nodes = None, scale = 0.5, x = 350, y = 250, min_offset = 8):
|
def create(cls, scene_root = None, fixed_nodes = None, scale = 0.5, x = 350, y = 250, min_offset = 8):
|
||||||
|
"""
|
||||||
|
Helper to create an Arranger instance
|
||||||
|
|
||||||
|
Either fill in scene_root and create will find all sliceable nodes by itself, or use fixed_nodes to provide the
|
||||||
|
nodes yourself.
|
||||||
|
:param scene_root: Root for finding all scene nodes
|
||||||
|
:param fixed_nodes: Scene nodes to be placed
|
||||||
|
:param scale:
|
||||||
|
:param x:
|
||||||
|
:param y:
|
||||||
|
:param min_offset:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
arranger = Arrange(x, y, x // 2, y // 2, scale = scale)
|
arranger = Arrange(x, y, x // 2, y // 2, scale = scale)
|
||||||
arranger.centerFirst()
|
arranger.centerFirst()
|
||||||
|
|
||||||
@ -88,12 +94,15 @@ class Arrange:
|
|||||||
def resetLastPriority(self):
|
def resetLastPriority(self):
|
||||||
self._last_priority = 0
|
self._last_priority = 0
|
||||||
|
|
||||||
## Find placement for a node (using offset shape) and place it (using hull shape)
|
|
||||||
# return the nodes that should be placed
|
|
||||||
# \param node
|
|
||||||
# \param offset_shape_arr ShapeArray with offset, for placing the shape
|
|
||||||
# \param hull_shape_arr ShapeArray without offset, used to find location
|
|
||||||
def findNodePlacement(self, node: SceneNode, offset_shape_arr: ShapeArray, hull_shape_arr: ShapeArray, step = 1):
|
def findNodePlacement(self, node: SceneNode, offset_shape_arr: ShapeArray, hull_shape_arr: ShapeArray, step = 1):
|
||||||
|
"""
|
||||||
|
Find placement for a node (using offset shape) and place it (using hull shape)
|
||||||
|
:param node:
|
||||||
|
:param offset_shape_arr: hapeArray with offset, for placing the shape
|
||||||
|
:param hull_shape_arr: ShapeArray without offset, used to find location
|
||||||
|
:param step:
|
||||||
|
:return: the nodes that should be placed
|
||||||
|
"""
|
||||||
best_spot = self.bestSpot(
|
best_spot = self.bestSpot(
|
||||||
hull_shape_arr, start_prio = self._last_priority, step = step)
|
hull_shape_arr, start_prio = self._last_priority, step = step)
|
||||||
x, y = best_spot.x, best_spot.y
|
x, y = best_spot.x, best_spot.y
|
||||||
@ -119,29 +128,35 @@ class Arrange:
|
|||||||
node.setPosition(Vector(200, center_y, 100))
|
node.setPosition(Vector(200, center_y, 100))
|
||||||
return found_spot
|
return found_spot
|
||||||
|
|
||||||
## Fill priority, center is best. Lower value is better
|
|
||||||
# This is a strategy for the arranger.
|
|
||||||
def centerFirst(self):
|
def centerFirst(self):
|
||||||
|
"""
|
||||||
|
Fill priority, center is best. Lower value is better.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
# Square distance: creates a more round shape
|
# Square distance: creates a more round shape
|
||||||
self._priority = numpy.fromfunction(
|
self._priority = numpy.fromfunction(
|
||||||
lambda j, i: (self._offset_x - i) ** 2 + (self._offset_y - j) ** 2, self._shape, dtype=numpy.int32)
|
lambda j, i: (self._offset_x - i) ** 2 + (self._offset_y - j) ** 2, self._shape, dtype=numpy.int32)
|
||||||
self._priority_unique_values = numpy.unique(self._priority)
|
self._priority_unique_values = numpy.unique(self._priority)
|
||||||
self._priority_unique_values.sort()
|
self._priority_unique_values.sort()
|
||||||
|
|
||||||
## Fill priority, back is best. Lower value is better
|
|
||||||
# This is a strategy for the arranger.
|
|
||||||
def backFirst(self):
|
def backFirst(self):
|
||||||
|
"""
|
||||||
|
Fill priority, back is best. Lower value is better
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
self._priority = numpy.fromfunction(
|
self._priority = numpy.fromfunction(
|
||||||
lambda j, i: 10 * j + abs(self._offset_x - i), self._shape, dtype=numpy.int32)
|
lambda j, i: 10 * j + abs(self._offset_x - i), self._shape, dtype=numpy.int32)
|
||||||
self._priority_unique_values = numpy.unique(self._priority)
|
self._priority_unique_values = numpy.unique(self._priority)
|
||||||
self._priority_unique_values.sort()
|
self._priority_unique_values.sort()
|
||||||
|
|
||||||
## Return the amount of "penalty points" for polygon, which is the sum of priority
|
|
||||||
# None if occupied
|
|
||||||
# \param x x-coordinate to check shape
|
|
||||||
# \param y y-coordinate
|
|
||||||
# \param shape_arr the ShapeArray object to place
|
|
||||||
def checkShape(self, x, y, shape_arr):
|
def checkShape(self, x, y, shape_arr):
|
||||||
|
"""
|
||||||
|
Return the amount of "penalty points" for polygon, which is the sum of priority
|
||||||
|
:param x: x-coordinate to check shape
|
||||||
|
:param y:
|
||||||
|
:param shape_arr: the ShapeArray object to place
|
||||||
|
:return: None if occupied
|
||||||
|
"""
|
||||||
x = int(self._scale * x)
|
x = int(self._scale * x)
|
||||||
y = int(self._scale * y)
|
y = int(self._scale * y)
|
||||||
offset_x = x + self._offset_x + shape_arr.offset_x
|
offset_x = x + self._offset_x + shape_arr.offset_x
|
||||||
@ -165,12 +180,14 @@ class Arrange:
|
|||||||
offset_x:offset_x + shape_arr.arr.shape[1]]
|
offset_x:offset_x + shape_arr.arr.shape[1]]
|
||||||
return numpy.sum(prio_slice[numpy.where(shape_arr.arr == 1)])
|
return numpy.sum(prio_slice[numpy.where(shape_arr.arr == 1)])
|
||||||
|
|
||||||
## Find "best" spot for ShapeArray
|
|
||||||
# Return namedtuple with properties x, y, penalty_points, priority.
|
|
||||||
# \param shape_arr ShapeArray
|
|
||||||
# \param start_prio Start with this priority value (and skip the ones before)
|
|
||||||
# \param step Slicing value, higher = more skips = faster but less accurate
|
|
||||||
def bestSpot(self, shape_arr, start_prio = 0, step = 1):
|
def bestSpot(self, shape_arr, start_prio = 0, step = 1):
|
||||||
|
"""
|
||||||
|
Find "best" spot for ShapeArray
|
||||||
|
:param shape_arr:
|
||||||
|
:param start_prio: Start with this priority value (and skip the ones before)
|
||||||
|
:param step: Slicing value, higher = more skips = faster but less accurate
|
||||||
|
:return: namedtuple with properties x, y, penalty_points, priority.
|
||||||
|
"""
|
||||||
start_idx_list = numpy.where(self._priority_unique_values == start_prio)
|
start_idx_list = numpy.where(self._priority_unique_values == start_prio)
|
||||||
if start_idx_list:
|
if start_idx_list:
|
||||||
try:
|
try:
|
||||||
@ -192,13 +209,16 @@ class Arrange:
|
|||||||
return LocationSuggestion(x = projected_x, y = projected_y, penalty_points = penalty_points, priority = priority)
|
return LocationSuggestion(x = projected_x, y = projected_y, penalty_points = penalty_points, priority = priority)
|
||||||
return LocationSuggestion(x = None, y = None, penalty_points = None, priority = priority) # No suitable location found :-(
|
return LocationSuggestion(x = None, y = None, penalty_points = None, priority = priority) # No suitable location found :-(
|
||||||
|
|
||||||
## Place the object.
|
|
||||||
# Marks the locations in self._occupied and self._priority
|
|
||||||
# \param x x-coordinate
|
|
||||||
# \param y y-coordinate
|
|
||||||
# \param shape_arr ShapeArray object
|
|
||||||
# \param update_empty updates the _is_empty, used when adding disallowed areas
|
|
||||||
def place(self, x, y, shape_arr, update_empty = True):
|
def place(self, x, y, shape_arr, update_empty = True):
|
||||||
|
"""
|
||||||
|
Place the object.
|
||||||
|
Marks the locations in self._occupied and self._priority
|
||||||
|
:param x:
|
||||||
|
:param y:
|
||||||
|
:param shape_arr:
|
||||||
|
:param update_empty: updates the _is_empty, used when adding disallowed areas
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
x = int(self._scale * x)
|
x = int(self._scale * x)
|
||||||
y = int(self._scale * y)
|
y = int(self._scale * y)
|
||||||
offset_x = x + self._offset_x + shape_arr.offset_x
|
offset_x = x + self._offset_x + shape_arr.offset_x
|
||||||
|
@ -72,8 +72,6 @@ class DiscoveredPrinter(QObject):
|
|||||||
# Human readable machine type string
|
# Human readable machine type string
|
||||||
@pyqtProperty(str, notify = machineTypeChanged)
|
@pyqtProperty(str, notify = machineTypeChanged)
|
||||||
def readableMachineType(self) -> str:
|
def readableMachineType(self) -> str:
|
||||||
from cura.CuraApplication import CuraApplication
|
|
||||||
machine_manager = CuraApplication.getInstance().getMachineManager()
|
|
||||||
# In NetworkOutputDevice, when it updates a printer information, it updates the machine type using the field
|
# In NetworkOutputDevice, when it updates a printer information, it updates the machine type using the field
|
||||||
# "machine_variant", and for some reason, it's not the machine type ID/codename/... but a human-readable string
|
# "machine_variant", and for some reason, it's not the machine type ID/codename/... but a human-readable string
|
||||||
# like "Ultimaker 3". The code below handles this case.
|
# like "Ultimaker 3". The code below handles this case.
|
||||||
|
@ -4,13 +4,12 @@
|
|||||||
import collections
|
import collections
|
||||||
from PyQt5.QtCore import Qt, QTimer
|
from PyQt5.QtCore import Qt, QTimer
|
||||||
from typing import TYPE_CHECKING, Optional, Dict
|
from typing import TYPE_CHECKING, Optional, Dict
|
||||||
from cura.Machines.Models.IntentTranslations import intent_translations
|
|
||||||
|
|
||||||
from cura.Machines.Models.IntentModel import IntentModel
|
from cura.Machines.Models.IntentModel import IntentModel
|
||||||
from cura.Settings.IntentManager import IntentManager
|
from cura.Settings.IntentManager import IntentManager
|
||||||
from UM.Qt.ListModel import ListModel
|
from UM.Qt.ListModel import ListModel
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry #To update the list if anything changes.
|
from UM.Settings.ContainerRegistry import ContainerRegistry #To update the list if anything changes.
|
||||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal
|
from PyQt5.QtCore import pyqtSignal
|
||||||
import cura.CuraApplication
|
import cura.CuraApplication
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from UM.Settings.ContainerRegistry import ContainerInterface
|
from UM.Settings.ContainerRegistry import ContainerInterface
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
from typing import Dict, Optional, List, Set
|
from typing import Dict, Optional, List, Set
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtSlot
|
|
||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Util import parseBool
|
from UM.Util import parseBool
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ from typing import Optional
|
|||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Operations import Operation
|
from UM.Operations import Operation
|
||||||
|
|
||||||
from UM.Math.Vector import Vector
|
|
||||||
|
|
||||||
|
|
||||||
## An operation that parents a scene node to another scene node.
|
## An operation that parents a scene node to another scene node.
|
||||||
|
@ -111,7 +111,7 @@ class NetworkMJPGImage(QQuickPaintedItem):
|
|||||||
|
|
||||||
if not self._image_reply.isFinished():
|
if not self._image_reply.isFinished():
|
||||||
self._image_reply.close()
|
self._image_reply.close()
|
||||||
except Exception as e: # RuntimeError
|
except Exception: # RuntimeError
|
||||||
pass # It can happen that the wrapped c++ object is already deleted.
|
pass # It can happen that the wrapped c++ object is already deleted.
|
||||||
|
|
||||||
self._image_reply = None
|
self._image_reply = None
|
||||||
|
@ -9,7 +9,6 @@ from UM.Settings.Interfaces import DefinitionContainerInterface
|
|||||||
from UM.Settings.InstanceContainer import InstanceContainer
|
from UM.Settings.InstanceContainer import InstanceContainer
|
||||||
|
|
||||||
from cura.Machines.ContainerTree import ContainerTree
|
from cura.Machines.ContainerTree import ContainerTree
|
||||||
from cura.Machines.MachineNode import MachineNode
|
|
||||||
from .GlobalStack import GlobalStack
|
from .GlobalStack import GlobalStack
|
||||||
from .ExtruderStack import ExtruderStack
|
from .ExtruderStack import ExtruderStack
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
|
||||||
from typing import Any, Dict, List, Optional, Set, Tuple, TYPE_CHECKING
|
from typing import Any, Dict, List, Set, Tuple, TYPE_CHECKING
|
||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer
|
from UM.Settings.InstanceContainer import InstanceContainer
|
||||||
|
@ -333,7 +333,7 @@ class MachineManager(QObject):
|
|||||||
self.setVariantByName(extruder.getMetaDataEntry("position"), machine_node.preferred_variant_name)
|
self.setVariantByName(extruder.getMetaDataEntry("position"), machine_node.preferred_variant_name)
|
||||||
variant_node = machine_node.variants.get(machine_node.preferred_variant_name)
|
variant_node = machine_node.variants.get(machine_node.preferred_variant_name)
|
||||||
|
|
||||||
material_node = variant_node.materials.get(extruder.material.getId())
|
material_node = variant_node.materials.get(extruder.material.getMetaDataEntry("base_file"))
|
||||||
if material_node is None:
|
if material_node is None:
|
||||||
Logger.log("w", "An extruder has an unknown material, switching it to the preferred material")
|
Logger.log("w", "An extruder has an unknown material, switching it to the preferred material")
|
||||||
self.setMaterialById(extruder.getMetaDataEntry("position"), machine_node.preferred_material)
|
self.setMaterialById(extruder.getMetaDataEntry("position"), machine_node.preferred_material)
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
# Copyright (c) 2017 Ultimaker B.V.
|
# Copyright (c) 2017 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
from typing import Set
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
|
||||||
|
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
import re
|
import re
|
||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import Dict, List, Optional, Union
|
||||||
|
|
||||||
from PyQt5.QtCore import QTimer, Qt
|
from PyQt5.QtCore import QTimer, Qt
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ from UM.Version import Version
|
|||||||
|
|
||||||
import urllib.request
|
import urllib.request
|
||||||
from urllib.error import URLError
|
from urllib.error import URLError
|
||||||
from typing import Dict, Optional
|
from typing import Dict
|
||||||
import ssl
|
import ssl
|
||||||
|
|
||||||
import certifi
|
import certifi
|
||||||
|
@ -79,7 +79,7 @@ class ModelChecker(QObject, Extension):
|
|||||||
# This function can be triggered in the middle of a machine change, so do not proceed if the machine change
|
# This function can be triggered in the middle of a machine change, so do not proceed if the machine change
|
||||||
# has not done yet.
|
# has not done yet.
|
||||||
try:
|
try:
|
||||||
extruder = global_container_stack.extruderList[int(node_extruder_position)]
|
global_container_stack.extruderList[int(node_extruder_position)]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
Application.getInstance().callLater(lambda: self.onChanged.emit())
|
Application.getInstance().callLater(lambda: self.onChanged.emit())
|
||||||
return False
|
return False
|
||||||
|
@ -23,16 +23,13 @@ class BQ_PauseAtHeight(Script):
|
|||||||
}"""
|
}"""
|
||||||
|
|
||||||
def execute(self, data):
|
def execute(self, data):
|
||||||
x = 0.
|
|
||||||
y = 0.
|
|
||||||
current_z = 0.
|
|
||||||
pause_z = self.getSettingValueByKey("pause_height")
|
pause_z = self.getSettingValueByKey("pause_height")
|
||||||
for layer in data:
|
for layer in data:
|
||||||
lines = layer.split("\n")
|
lines = layer.split("\n")
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if self.getValue(line, 'G') == 1 or self.getValue(line, 'G') == 0:
|
if self.getValue(line, 'G') == 1 or self.getValue(line, 'G') == 0:
|
||||||
current_z = self.getValue(line, 'Z')
|
current_z = self.getValue(line, 'Z')
|
||||||
if current_z != None:
|
if current_z is not None:
|
||||||
if current_z >= pause_z:
|
if current_z >= pause_z:
|
||||||
prepend_gcode = ";TYPE:CUSTOM\n"
|
prepend_gcode = ";TYPE:CUSTOM\n"
|
||||||
prepend_gcode += "; -- Pause at height (%.2f mm) --\n" % pause_z
|
prepend_gcode += "; -- Pause at height (%.2f mm) --\n" % pause_z
|
||||||
|
@ -170,7 +170,7 @@ class ColorMix(Script):
|
|||||||
modelNumber = 0
|
modelNumber = 0
|
||||||
for active_layer in data:
|
for active_layer in data:
|
||||||
modified_gcode = ""
|
modified_gcode = ""
|
||||||
lineIndex = 0;
|
lineIndex = 0
|
||||||
lines = active_layer.split("\n")
|
lines = active_layer.split("\n")
|
||||||
for line in lines:
|
for line in lines:
|
||||||
#dont leave blanks
|
#dont leave blanks
|
||||||
|
@ -10,10 +10,10 @@ WARNING This script has never been tested with several extruders
|
|||||||
from ..Script import Script
|
from ..Script import Script
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Application import Application
|
|
||||||
import re
|
import re
|
||||||
from cura.Settings.ExtruderManager import ExtruderManager
|
from cura.Settings.ExtruderManager import ExtruderManager
|
||||||
|
|
||||||
|
|
||||||
def _getValue(line, key, default=None):
|
def _getValue(line, key, default=None):
|
||||||
"""
|
"""
|
||||||
Convenience function that finds the value in a line of g-code.
|
Convenience function that finds the value in a line of g-code.
|
||||||
@ -30,6 +30,7 @@ def _getValue(line, key, default=None):
|
|||||||
return default
|
return default
|
||||||
return float(number.group(0))
|
return float(number.group(0))
|
||||||
|
|
||||||
|
|
||||||
class GCodeStep():
|
class GCodeStep():
|
||||||
"""
|
"""
|
||||||
Class to store the current value of each G_Code parameter
|
Class to store the current value of each G_Code parameter
|
||||||
@ -85,7 +86,7 @@ class GCodeStep():
|
|||||||
|
|
||||||
|
|
||||||
# Execution part of the stretch plugin
|
# Execution part of the stretch plugin
|
||||||
class Stretcher():
|
class Stretcher:
|
||||||
"""
|
"""
|
||||||
Execution part of the stretch algorithm
|
Execution part of the stretch algorithm
|
||||||
"""
|
"""
|
||||||
@ -207,7 +208,6 @@ class Stretcher():
|
|||||||
return False
|
return False
|
||||||
return True # New sequence
|
return True # New sequence
|
||||||
|
|
||||||
|
|
||||||
def processLayer(self, layer_steps):
|
def processLayer(self, layer_steps):
|
||||||
"""
|
"""
|
||||||
Computes the new coordinates of g-code steps
|
Computes the new coordinates of g-code steps
|
||||||
@ -291,7 +291,6 @@ class Stretcher():
|
|||||||
else:
|
else:
|
||||||
self.layergcode = self.layergcode + layer_steps[i].comment + "\n"
|
self.layergcode = self.layergcode + layer_steps[i].comment + "\n"
|
||||||
|
|
||||||
|
|
||||||
def workOnSequence(self, orig_seq, modif_seq):
|
def workOnSequence(self, orig_seq, modif_seq):
|
||||||
"""
|
"""
|
||||||
Computes new coordinates for a sequence
|
Computes new coordinates for a sequence
|
||||||
|
@ -49,7 +49,7 @@ class OSXRemovableDrivePlugin(RemovableDrivePlugin.RemovableDrivePlugin):
|
|||||||
|
|
||||||
def performEjectDevice(self, device):
|
def performEjectDevice(self, device):
|
||||||
p = subprocess.Popen(["diskutil", "eject", device.getId()], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
p = subprocess.Popen(["diskutil", "eject", device.getId()], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||||
output = p.communicate()
|
p.communicate()
|
||||||
|
|
||||||
return_code = p.wait()
|
return_code = p.wait()
|
||||||
if return_code != 0:
|
if return_code != 0:
|
||||||
|
@ -6,7 +6,6 @@ from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
|
|||||||
|
|
||||||
from UM.Job import Job
|
from UM.Job import Job
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Settings import ContainerRegistry
|
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
from ..Models.Http.ClusterMaterial import ClusterMaterial
|
from ..Models.Http.ClusterMaterial import ClusterMaterial
|
||||||
|
@ -299,7 +299,7 @@ class UltimakerNetworkedPrinterOutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
new_print_jobs = []
|
new_print_jobs = []
|
||||||
|
|
||||||
# Check which print jobs need to be created or updated.
|
# Check which print jobs need to be created or updated.
|
||||||
for index, print_job_data in enumerate(remote_jobs):
|
for print_job_data in remote_jobs:
|
||||||
print_job = next(
|
print_job = next(
|
||||||
iter(print_job for print_job in self._print_jobs if print_job.key == print_job_data.uuid), None)
|
iter(print_job for print_job in self._print_jobs if print_job.key == print_job_data.uuid), None)
|
||||||
if not print_job:
|
if not print_job:
|
||||||
|
@ -50,7 +50,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin):
|
|||||||
|
|
||||||
# The method updates/reset the USB settings for all connected USB devices
|
# The method updates/reset the USB settings for all connected USB devices
|
||||||
def updateUSBPrinterOutputDevices(self):
|
def updateUSBPrinterOutputDevices(self):
|
||||||
for key, device in self._usb_output_devices.items():
|
for device in self._usb_output_devices.values():
|
||||||
if isinstance(device, USBPrinterOutputDevice.USBPrinterOutputDevice):
|
if isinstance(device, USBPrinterOutputDevice.USBPrinterOutputDevice):
|
||||||
device.resetDeviceSettings()
|
device.resetDeviceSettings()
|
||||||
|
|
||||||
|
@ -653,7 +653,7 @@ class X3DReader(MeshReader):
|
|||||||
|
|
||||||
def processGeometryTriangleSet2D(self, node):
|
def processGeometryTriangleSet2D(self, node):
|
||||||
verts = readFloatArray(node, "vertices", ())
|
verts = readFloatArray(node, "vertices", ())
|
||||||
num_faces = len(verts) // 6;
|
num_faces = len(verts) // 6
|
||||||
verts = [(verts[i], verts[i+1], 0) for i in range(0, 6 * num_faces, 2)]
|
verts = [(verts[i], verts[i+1], 0) for i in range(0, 6 * num_faces, 2)]
|
||||||
self.reserveFaceAndVertexCount(num_faces, num_faces * 3)
|
self.reserveFaceAndVertexCount(num_faces, num_faces * 3)
|
||||||
for vert in verts:
|
for vert in verts:
|
||||||
@ -904,6 +904,7 @@ def findOuterNormal(face):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
# Given two *collinear* vectors a and b, returns the coefficient that takes b to a.
|
# Given two *collinear* vectors a and b, returns the coefficient that takes b to a.
|
||||||
# No error handling.
|
# No error handling.
|
||||||
# For stability, taking the ration between the biggest coordinates would be better...
|
# For stability, taking the ration between the biggest coordinates would be better...
|
||||||
@ -915,12 +916,13 @@ def ratio(a, b):
|
|||||||
else:
|
else:
|
||||||
return a.z / b.z
|
return a.z / b.z
|
||||||
|
|
||||||
|
|
||||||
def pointInsideTriangle(vx, next, prev, nextXprev):
|
def pointInsideTriangle(vx, next, prev, nextXprev):
|
||||||
vxXprev = vx.cross(prev)
|
vxXprev = vx.cross(prev)
|
||||||
r = ratio(vxXprev, nextXprev)
|
r = ratio(vxXprev, nextXprev)
|
||||||
if r < 0:
|
if r < 0:
|
||||||
return False
|
return False
|
||||||
vxXnext = vx.cross(next);
|
vxXnext = vx.cross(next)
|
||||||
s = -ratio(vxXnext, nextXprev)
|
s = -ratio(vxXnext, nextXprev)
|
||||||
return s > 0 and (s + r) < 1
|
return s > 0 and (s + r) < 1
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import copy
|
|||||||
import io
|
import io
|
||||||
import json #To parse the product-to-id mapping file.
|
import json #To parse the product-to-id mapping file.
|
||||||
import os.path #To find the product-to-id mapping.
|
import os.path #To find the product-to-id mapping.
|
||||||
import sys
|
|
||||||
from typing import Any, Dict, List, Optional, Tuple, cast, Set, Union
|
from typing import Any, Dict, List, Optional, Tuple, cast, Set, Union
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
@ -18,7 +17,6 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
|
|||||||
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
|
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage
|
||||||
|
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from cura.Machines.ContainerTree import ContainerTree
|
|
||||||
from cura.Machines.VariantType import VariantType
|
from cura.Machines.VariantType import VariantType
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
# Prevents error: "PyCapsule_GetPointer called with incorrect name" with conflicting SIP configurations between Arcus and PyQt: Import Arcus and Savitar first!
|
# Prevents error: "PyCapsule_GetPointer called with incorrect name" with conflicting SIP configurations between Arcus and PyQt: Import Arcus and Savitar first!
|
||||||
import Savitar # Dont remove this line
|
import Savitar # Dont remove this line
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import patch, MagicMock
|
||||||
import pytest
|
import pytest
|
||||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
|
||||||
from cura.Machines.ContainerTree import ContainerTree
|
from cura.Machines.ContainerTree import ContainerTree
|
||||||
from cura.Settings.GlobalStack import GlobalStack
|
from cura.Settings.GlobalStack import GlobalStack
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import os #To find the directory with test files and find the test files.
|
|||||||
import pytest #To parameterize tests.
|
import pytest #To parameterize tests.
|
||||||
import unittest.mock #To mock and monkeypatch stuff.
|
import unittest.mock #To mock and monkeypatch stuff.
|
||||||
|
|
||||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
|
||||||
from cura.ReaderWriters.ProfileReader import NoProfileException
|
from cura.ReaderWriters.ProfileReader import NoProfileException
|
||||||
from cura.Settings.ExtruderStack import ExtruderStack #Testing for returning the correct types of stacks.
|
from cura.Settings.ExtruderStack import ExtruderStack #Testing for returning the correct types of stacks.
|
||||||
from cura.Settings.GlobalStack import GlobalStack #Testing for returning the correct types of stacks.
|
from cura.Settings.GlobalStack import GlobalStack #Testing for returning the correct types of stacks.
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from UM.Math.Polygon import Polygon
|
from UM.Math.Polygon import Polygon
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
|
||||||
def createMockedExtruder(extruder_id):
|
def createMockedExtruder(extruder_id):
|
||||||
|
@ -108,9 +108,9 @@ def test_addMachineAction(machine_action_manager):
|
|||||||
# Adding unknown action should not crash.
|
# Adding unknown action should not crash.
|
||||||
machine_action_manager.addFirstStartAction(test_machine, "key_that_doesnt_exists")
|
machine_action_manager.addFirstStartAction(test_machine, "key_that_doesnt_exists")
|
||||||
|
|
||||||
|
|
||||||
def test_removeMachineAction(machine_action_manager):
|
def test_removeMachineAction(machine_action_manager):
|
||||||
test_action = MachineAction(key="test_action")
|
test_action = MachineAction(key="test_action")
|
||||||
test_machine = Machine("test_machine")
|
|
||||||
machine_action_manager.addMachineAction(test_action)
|
machine_action_manager.addMachineAction(test_action)
|
||||||
|
|
||||||
# Remove the machine action
|
# Remove the machine action
|
||||||
|
@ -5,7 +5,6 @@ from cura.UI import PrintInformation
|
|||||||
from cura.Settings.MachineManager import MachineManager
|
from cura.Settings.MachineManager import MachineManager
|
||||||
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
from UM.Application import Application
|
|
||||||
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user