mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-08 06:23:59 -06:00
Merge branch 'master' of github.com:Ultimaker/Cura
This commit is contained in:
commit
b3bf77524b
31 changed files with 267 additions and 273 deletions
|
@ -41,11 +41,11 @@ class IntentCategoryModel(ListModel):
|
|||
}
|
||||
_translations["engineering"] = {
|
||||
"name": catalog.i18nc("@label", "Engineering"),
|
||||
"description": catalog.i18nc("@text", "Suitable for engineering work")
|
||||
"description": catalog.i18nc("@text", "Optimized for higher accuracy")
|
||||
}
|
||||
_translations["smooth"] = {
|
||||
"name": catalog.i18nc("@label", "Smooth"),
|
||||
"description": catalog.i18nc("@text", "Optimized for a smooth surfaces")
|
||||
_translations["quick"] = {
|
||||
"name": catalog.i18nc("@label", "Draft"),
|
||||
"description": catalog.i18nc("@text", "Optimized for fast results")
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import numpy
|
||||
|
@ -72,7 +72,7 @@ class GcodeStartEndFormatter(Formatter):
|
|||
value = default_value_str
|
||||
# "-1" is global stack, and if the setting value exists in the global stack, use it as the fallback value.
|
||||
if key in kwargs["-1"]:
|
||||
value = kwargs["-1"]
|
||||
value = kwargs["-1"][key]
|
||||
if str(extruder_nr) in kwargs and key in kwargs[str(extruder_nr)]:
|
||||
value = kwargs[str(extruder_nr)][key]
|
||||
|
||||
|
|
|
@ -143,6 +143,52 @@ UM.Dialog
|
|||
}
|
||||
}
|
||||
|
||||
UM.TooltipArea {
|
||||
Layout.fillWidth:true
|
||||
height: childrenRect.height
|
||||
text: catalog.i18nc("@info:tooltip","For lithophanes a simple logarithmic model for translucency is available. For height maps the pixel values correspond to heights linearly.")
|
||||
Row {
|
||||
width: parent.width
|
||||
|
||||
Label {
|
||||
text: "Color Model"
|
||||
width: 150 * screenScaleFactor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
ComboBox {
|
||||
id: color_model
|
||||
objectName: "ColorModel"
|
||||
model: [ catalog.i18nc("@item:inlistbox","Linear"), catalog.i18nc("@item:inlistbox","Translucency") ]
|
||||
width: 180 * screenScaleFactor
|
||||
onCurrentIndexChanged: { manager.onColorModelChanged(currentIndex) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UM.TooltipArea {
|
||||
Layout.fillWidth:true
|
||||
height: childrenRect.height
|
||||
text: catalog.i18nc("@info:tooltip","The percentage of light penetrating a print with a thickness of 1 millimeter. Lowering this value increases the contrast in dark regions and decreases the contrast in light regions of the image.")
|
||||
visible: color_model.currentText == catalog.i18nc("@item:inlistbox","Translucency")
|
||||
Row {
|
||||
width: parent.width
|
||||
|
||||
Label {
|
||||
text: catalog.i18nc("@action:label", "1mm Transmittance (%)")
|
||||
width: 150 * screenScaleFactor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
TextField {
|
||||
id: transmittance
|
||||
objectName: "Transmittance"
|
||||
focus: true
|
||||
validator: RegExpValidator {regExp: /^[1-9]\d{0,2}([\,|\.]\d*)?$/}
|
||||
width: 180 * screenScaleFactor
|
||||
onTextChanged: { manager.onTransmittanceChanged(text) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UM.TooltipArea {
|
||||
Layout.fillWidth:true
|
||||
height: childrenRect.height
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
import numpy
|
||||
|
||||
import math
|
||||
|
||||
from PyQt5.QtGui import QImage, qRed, qGreen, qBlue
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
|
@ -46,9 +48,9 @@ class ImageReader(MeshReader):
|
|||
|
||||
def _read(self, file_name):
|
||||
size = max(self._ui.getWidth(), self._ui.getDepth())
|
||||
return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.lighter_is_higher)
|
||||
return self._generateSceneNode(file_name, size, self._ui.peak_height, self._ui.base_height, self._ui.smoothing, 512, self._ui.lighter_is_higher, self._ui.use_transparency_model, self._ui.transmittance_1mm)
|
||||
|
||||
def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, lighter_is_higher):
|
||||
def _generateSceneNode(self, file_name, xz_size, peak_height, base_height, blur_iterations, max_size, lighter_is_higher, use_transparency_model, transmittance_1mm):
|
||||
scene_node = SceneNode()
|
||||
|
||||
mesh = MeshBuilder()
|
||||
|
@ -99,12 +101,14 @@ class ImageReader(MeshReader):
|
|||
for x in range(0, width):
|
||||
for y in range(0, height):
|
||||
qrgb = img.pixel(x, y)
|
||||
avg = float(qRed(qrgb) + qGreen(qrgb) + qBlue(qrgb)) / (3 * 255)
|
||||
height_data[y, x] = avg
|
||||
if use_transparency_model:
|
||||
height_data[y, x] = (0.299 * math.pow(qRed(qrgb) / 255.0, 2.2) + 0.587 * math.pow(qGreen(qrgb) / 255.0, 2.2) + 0.114 * math.pow(qBlue(qrgb) / 255.0, 2.2))
|
||||
else:
|
||||
height_data[y, x] = (0.212655 * qRed(qrgb) + 0.715158 * qGreen(qrgb) + 0.072187 * qBlue(qrgb)) / 255 # fast computation ignoring gamma and degamma
|
||||
|
||||
Job.yieldThread()
|
||||
|
||||
if not lighter_is_higher:
|
||||
if lighter_is_higher == use_transparency_model:
|
||||
height_data = 1 - height_data
|
||||
|
||||
for _ in range(0, blur_iterations):
|
||||
|
@ -124,8 +128,15 @@ class ImageReader(MeshReader):
|
|||
|
||||
Job.yieldThread()
|
||||
|
||||
height_data *= scale_vector.y
|
||||
height_data += base_height
|
||||
if use_transparency_model:
|
||||
divisor = 1.0 / math.log(transmittance_1mm / 100.0) # log-base doesn't matter here. Precompute this value for faster computation of each pixel.
|
||||
min_luminance = (transmittance_1mm / 100.0) ** (peak_height - base_height)
|
||||
for (y, x) in numpy.ndindex(height_data.shape):
|
||||
mapped_luminance = min_luminance + (1.0 - min_luminance) * height_data[y, x]
|
||||
height_data[y, x] = base_height + divisor * math.log(mapped_luminance) # use same base as a couple lines above this
|
||||
else:
|
||||
height_data *= scale_vector.y
|
||||
height_data += base_height
|
||||
|
||||
heightmap_face_count = 2 * height_minus_one * width_minus_one
|
||||
total_face_count = heightmap_face_count + (width_minus_one * 2) * (height_minus_one * 2) + 2
|
||||
|
|
|
@ -34,6 +34,8 @@ class ImageReaderUI(QObject):
|
|||
self.peak_height = 2.5
|
||||
self.smoothing = 1
|
||||
self.lighter_is_higher = False;
|
||||
self.use_transparency_model = True;
|
||||
self.transmittance_1mm = 50.0; # based on pearl PLA
|
||||
|
||||
self._ui_lock = threading.Lock()
|
||||
self._cancelled = False
|
||||
|
@ -75,6 +77,7 @@ class ImageReaderUI(QObject):
|
|||
|
||||
self._ui_view.findChild(QObject, "Base_Height").setProperty("text", str(self.base_height))
|
||||
self._ui_view.findChild(QObject, "Peak_Height").setProperty("text", str(self.peak_height))
|
||||
self._ui_view.findChild(QObject, "Transmittance").setProperty("text", str(self.transmittance_1mm))
|
||||
self._ui_view.findChild(QObject, "Smoothing").setProperty("value", self.smoothing)
|
||||
|
||||
def _createConfigUI(self):
|
||||
|
@ -144,3 +147,11 @@ class ImageReaderUI(QObject):
|
|||
@pyqtSlot(int)
|
||||
def onImageColorInvertChanged(self, value):
|
||||
self.lighter_is_higher = (value == 1)
|
||||
|
||||
@pyqtSlot(int)
|
||||
def onColorModelChanged(self, value):
|
||||
self.use_transparency_model = (value == 0)
|
||||
|
||||
@pyqtSlot(int)
|
||||
def onTransmittanceChanged(self, value):
|
||||
self.transmittance_1mm = value
|
||||
|
|
|
@ -66,6 +66,13 @@ class VersionUpgrade43to44(VersionUpgrade):
|
|||
# Alternate skin rotation should be translated to top/bottom line directions.
|
||||
if "skin_alternate_rotation" in parser["values"] and parseBool(parser["values"]["skin_alternate_rotation"]):
|
||||
parser["values"]["skin_angles"] = "[45, 135, 0, 90]"
|
||||
# Unit of adaptive layers topography size changed.
|
||||
if "adaptive_layer_height_threshold" in parser["values"]:
|
||||
val = parser["values"]["adaptive_layer_height_threshold"]
|
||||
if val.startswith("="):
|
||||
val = val[1:]
|
||||
val = "=({val}) / 1000".format(val = val) # Convert microns to millimetres. Works even if the profile contained a formula.
|
||||
parser["values"]["adaptive_layer_height_threshold"] = val
|
||||
|
||||
result = io.StringIO()
|
||||
parser.write(result)
|
||||
|
|
|
@ -7074,11 +7074,12 @@
|
|||
},
|
||||
"adaptive_layer_height_threshold":
|
||||
{
|
||||
"label": "Adaptive Layers Threshold",
|
||||
"description": "Threshold whether to use a smaller layer or not. This number is compared to the tan of the steepest slope in a layer.",
|
||||
"label": "Adaptive Layers Topography Size",
|
||||
"description": "Target horizontal distance between two adjacent layers. Reducing this setting causes thinner layers to be used to bring the edges of the layers closer together.",
|
||||
"type": "float",
|
||||
"enabled": "adaptive_layer_height_enabled",
|
||||
"default_value": 200.0,
|
||||
"default_value": 0.2,
|
||||
"unit": "mm",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": false,
|
||||
"settable_per_meshgroup": false
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
"supports_usb_connection": false,
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
"0": "alya3dp_extruder_0"
|
||||
"0": "kupido_extruder_0"
|
||||
}
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": "ALYA 3DP" },
|
||||
"machine_name": { "default_value": "KUPIDO" },
|
||||
"machine_heated_bed": { "default_value": true },
|
||||
"machine_width": { "default_value": 195 },
|
||||
"machine_height": { "default_value": 190 },
|
||||
|
|
|
@ -67,8 +67,6 @@
|
|||
"extruder_prime_pos_abs": { "default_value": true },
|
||||
"machine_start_gcode": { "default_value": "" },
|
||||
"machine_end_gcode": { "default_value": "" },
|
||||
"prime_tower_position_x": { "value": "345" },
|
||||
"prime_tower_position_y": { "value": "222.5" },
|
||||
"prime_blob_enable": { "enabled": true, "default_value": false },
|
||||
|
||||
"speed_travel":
|
||||
|
|
|
@ -1,45 +1,45 @@
|
|||
{
|
||||
"version": 2,
|
||||
"name": "Extruder 1",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "BIBO2 dual",
|
||||
"position": "0"
|
||||
},
|
||||
"overrides": {
|
||||
"extruder_nr": {
|
||||
"default_value": 0,
|
||||
"maximum_value": "1"
|
||||
},
|
||||
"material_diameter": {
|
||||
"default_value": 1.75
|
||||
},
|
||||
"machine_nozzle_size": {
|
||||
"default_value": 0.4
|
||||
},
|
||||
"machine_nozzle_offset_x": {
|
||||
"default_value": 0.0
|
||||
},
|
||||
"machine_nozzle_offset_y": {
|
||||
"default_value": 0.0
|
||||
},
|
||||
"machine_extruder_start_pos_abs": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_extruder_start_pos_x": {
|
||||
"value": "prime_tower_position_x"
|
||||
},
|
||||
"machine_extruder_start_pos_y": {
|
||||
"value": "prime_tower_position_y"
|
||||
},
|
||||
"machine_extruder_end_pos_abs": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_extruder_end_pos_x": {
|
||||
"value": "prime_tower_position_x"
|
||||
},
|
||||
"machine_extruder_end_pos_y": {
|
||||
"value": "prime_tower_position_y"
|
||||
}
|
||||
}
|
||||
"version": 2,
|
||||
"name": "Extruder 1",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "bibo2_dual",
|
||||
"position": "0"
|
||||
},
|
||||
"overrides": {
|
||||
"extruder_nr": {
|
||||
"default_value": 0,
|
||||
"maximum_value": "1"
|
||||
},
|
||||
"material_diameter": {
|
||||
"default_value": 1.75
|
||||
},
|
||||
"machine_nozzle_size": {
|
||||
"default_value": 0.4
|
||||
},
|
||||
"machine_nozzle_offset_x": {
|
||||
"default_value": 0.0
|
||||
},
|
||||
"machine_nozzle_offset_y": {
|
||||
"default_value": 0.0
|
||||
},
|
||||
"machine_extruder_start_pos_abs": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_extruder_start_pos_x": {
|
||||
"value": "prime_tower_position_x"
|
||||
},
|
||||
"machine_extruder_start_pos_y": {
|
||||
"value": "prime_tower_position_y"
|
||||
},
|
||||
"machine_extruder_end_pos_abs": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_extruder_end_pos_x": {
|
||||
"value": "prime_tower_position_x"
|
||||
},
|
||||
"machine_extruder_end_pos_y": {
|
||||
"value": "prime_tower_position_y"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,45 +1,45 @@
|
|||
{
|
||||
"version": 2,
|
||||
"name": "Extruder 2",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "BIBO2 dual",
|
||||
"position": "1"
|
||||
},
|
||||
"overrides": {
|
||||
"extruder_nr": {
|
||||
"default_value": 1,
|
||||
"maximum_value": "1"
|
||||
},
|
||||
"material_diameter": {
|
||||
"default_value": 1.75
|
||||
},
|
||||
"machine_nozzle_size": {
|
||||
"default_value": 0.4
|
||||
},
|
||||
"machine_nozzle_offset_x": {
|
||||
"default_value": 0.0
|
||||
},
|
||||
"machine_nozzle_offset_y": {
|
||||
"default_value": 0.0
|
||||
},
|
||||
"machine_extruder_start_pos_abs": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_extruder_start_pos_x": {
|
||||
"value": "prime_tower_position_x"
|
||||
},
|
||||
"machine_extruder_start_pos_y": {
|
||||
"value": "prime_tower_position_y"
|
||||
},
|
||||
"machine_extruder_end_pos_abs": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_extruder_end_pos_x": {
|
||||
"value": "prime_tower_position_x"
|
||||
},
|
||||
"machine_extruder_end_pos_y": {
|
||||
"value": "prime_tower_position_y"
|
||||
}
|
||||
}
|
||||
"version": 2,
|
||||
"name": "Extruder 2",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "bibo2_dual",
|
||||
"position": "1"
|
||||
},
|
||||
"overrides": {
|
||||
"extruder_nr": {
|
||||
"default_value": 1,
|
||||
"maximum_value": "1"
|
||||
},
|
||||
"material_diameter": {
|
||||
"default_value": 1.75
|
||||
},
|
||||
"machine_nozzle_size": {
|
||||
"default_value": 0.4
|
||||
},
|
||||
"machine_nozzle_offset_x": {
|
||||
"default_value": 0.0
|
||||
},
|
||||
"machine_nozzle_offset_y": {
|
||||
"default_value": 0.0
|
||||
},
|
||||
"machine_extruder_start_pos_abs": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_extruder_start_pos_x": {
|
||||
"value": "prime_tower_position_x"
|
||||
},
|
||||
"machine_extruder_start_pos_y": {
|
||||
"value": "prime_tower_position_y"
|
||||
},
|
||||
"machine_extruder_end_pos_abs": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_extruder_end_pos_x": {
|
||||
"value": "prime_tower_position_x"
|
||||
},
|
||||
"machine_extruder_end_pos_y": {
|
||||
"value": "prime_tower_position_y"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Left Extruder",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "Creality CR-X",
|
||||
"machine": "creality_cr-x",
|
||||
"position": "0"
|
||||
},
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Right Extruder",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "Creality CR-X",
|
||||
"machine": "creality_cr-x",
|
||||
"position": "1"
|
||||
},
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Extruder 1",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "Creatable_D3",
|
||||
"machine": "creatable_d3",
|
||||
"position": "0"
|
||||
},
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Extruder 1",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "hellbot_magna_i",
|
||||
"machine": "hellbot_magna_I",
|
||||
"position": "0"
|
||||
},
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "0.4mm Nozzle",
|
||||
"inherits": "fdmextruder",
|
||||
"metadata": {
|
||||
"machine": "Tyro",
|
||||
"machine": "key3d_tyro",
|
||||
"position": "0"
|
||||
},
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ definition = ultimaker_s3
|
|||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
intent_category = smooth
|
||||
intent_category = quick
|
||||
quality_type = draft
|
||||
material = generic_abs
|
||||
variant = AA 0.4
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = Visual
|
||||
definition = ultimaker_s3
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
intent_category = visual
|
||||
quality_type = draft
|
||||
material = generic_abs
|
||||
variant = AA 0.4
|
||||
|
||||
[values]
|
||||
speed_infill = 50
|
||||
wall_thickness = =wall_line_width * 3
|
||||
top_bottom_thickness = =wall_thickness
|
|
@ -6,7 +6,7 @@ definition = ultimaker_s3
|
|||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
intent_category = smooth
|
||||
intent_category = quick
|
||||
quality_type = draft
|
||||
material = generic_pla
|
||||
variant = AA 0.4
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = Visual
|
||||
definition = ultimaker_s3
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
quality_type = draft
|
||||
intent_category = visual
|
||||
material = generic_pla
|
||||
variant = AA 0.4
|
||||
|
||||
[values]
|
||||
speed_infill = 50
|
||||
wall_thickness = =wall_line_width * 3
|
||||
top_bottom_thickness = =wall_thickness
|
|
@ -6,7 +6,7 @@ definition = ultimaker_s3
|
|||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
intent_category = smooth
|
||||
intent_category = quick
|
||||
quality_type = draft
|
||||
material = generic_tough_pla
|
||||
variant = AA 0.4
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = Visual
|
||||
definition = ultimaker_s3
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
quality_type = draft
|
||||
intent_category = visual
|
||||
material = generic_tough_pla
|
||||
variant = AA 0.4
|
||||
|
||||
[values]
|
||||
speed_infill = 50
|
||||
wall_thickness = =wall_line_width * 3
|
||||
top_bottom_thickness = =wall_thickness
|
|
@ -6,7 +6,7 @@ definition = ultimaker_s5
|
|||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
intent_category = smooth
|
||||
intent_category = quick
|
||||
quality_type = draft
|
||||
material = generic_abs
|
||||
variant = AA 0.4
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = Visual
|
||||
definition = ultimaker_s5
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
intent_category = visualquality_type = draft
|
||||
material = generic_abs
|
||||
variant = AA 0.4
|
||||
|
||||
[values]
|
||||
speed_infill = 50
|
||||
wall_thickness = =wall_line_width * 3
|
||||
top_bottom_thickness = =wall_thickness
|
|
@ -6,7 +6,7 @@ definition = ultimaker_s5
|
|||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
intent_category = smooth
|
||||
intent_category = quick
|
||||
quality_type = draft
|
||||
material = generic_pla
|
||||
variant = AA 0.4
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = Visual
|
||||
definition = ultimaker_s5
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
quality_type = draft
|
||||
intent_category = visual
|
||||
material = generic_pla
|
||||
variant = AA 0.4
|
||||
|
||||
[values]
|
||||
speed_infill = 50
|
||||
wall_thickness = =wall_line_width * 3
|
||||
top_bottom_thickness = =wall_thickness
|
|
@ -6,7 +6,7 @@ definition = ultimaker_s5
|
|||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
intent_category = smooth
|
||||
intent_category = quick
|
||||
quality_type = draft
|
||||
material = generic_tough_pla
|
||||
variant = AA 0.4
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
[general]
|
||||
version = 4
|
||||
name = Visual
|
||||
definition = ultimaker_s5
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
||||
type = intent
|
||||
intent_category = visual
|
||||
material = generic_tough_pla
|
||||
variant = AA 0.4
|
||||
|
||||
[values]
|
||||
speed_infill = 50
|
||||
wall_thickness = =wall_line_width * 3
|
||||
top_bottom_thickness = =wall_thickness
|
|
@ -124,18 +124,6 @@ Item
|
|||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
NoIntentIcon
|
||||
{
|
||||
affected_extruders: Cura.MachineManager.extruderPositionsWithNonActiveIntent
|
||||
intent_type: model.name
|
||||
anchors.right: intentCategoryLabel.right
|
||||
anchors.rightMargin: UM.Theme.getSize("narrow_margin").width
|
||||
width: intentCategoryLabel.height * 0.75
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: width
|
||||
visible: Cura.MachineManager.activeIntentCategory == model.intent_category && affected_extruders.length
|
||||
}
|
||||
|
||||
Cura.RadioCheckbar
|
||||
{
|
||||
anchors
|
||||
|
@ -164,8 +152,9 @@ Item
|
|||
isCheckedFunction: checkedFunction
|
||||
}
|
||||
|
||||
MouseArea // tooltip hover area
|
||||
MouseArea // Intent description tooltip hover area
|
||||
{
|
||||
id: intentDescriptionHoverArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
enabled: model.description !== undefined
|
||||
|
@ -181,6 +170,20 @@ Item
|
|||
}
|
||||
onExited: base.hideTooltip()
|
||||
}
|
||||
|
||||
NoIntentIcon // This icon has hover priority over intentDescriptionHoverArea, so draw it above it.
|
||||
{
|
||||
affected_extruders: Cura.MachineManager.extruderPositionsWithNonActiveIntent
|
||||
intent_type: model.name
|
||||
anchors.right: intentCategoryLabel.right
|
||||
anchors.rightMargin: UM.Theme.getSize("narrow_margin").width
|
||||
width: intentCategoryLabel.height * 0.75
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: width
|
||||
visible: Cura.MachineManager.activeIntentCategory == model.intent_category && affected_extruders.length
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -137,38 +137,17 @@ def test_materialAdded_update(container_registry, machine_node, metadata, change
|
|||
def test_preferredMaterialExactMatch(empty_variant_node):
|
||||
empty_variant_node.materials = {
|
||||
"some_different_material": MagicMock(getMetaDataEntry = lambda x: 3),
|
||||
"preferred_material_base_file": MagicMock(getMetaDataEntry = lambda x: 3) # Exact match.
|
||||
"preferred_material": MagicMock(getMetaDataEntry = lambda x: 3) # Exact match.
|
||||
}
|
||||
|
||||
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["preferred_material_base_file"], "It should match exactly on this one since it's the preferred material."
|
||||
|
||||
## Tests the preferred material when a submaterial is available in the
|
||||
# materials list for this node.
|
||||
def test_preferredMaterialSubmaterial(empty_variant_node):
|
||||
empty_variant_node.materials = {
|
||||
"some_different_material": MagicMock(getMetaDataEntry = lambda x: 3),
|
||||
"preferred_material_base_file_aa04": MagicMock(getMetaDataEntry = lambda x: 3) # This is a submaterial of the preferred material.
|
||||
}
|
||||
|
||||
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["preferred_material_base_file_aa04"], "It should match on the submaterial just as well."
|
||||
|
||||
## Tests the preferred material matching on the approximate diameter of the
|
||||
# filament.
|
||||
def test_preferredMaterialDiameter(empty_variant_node):
|
||||
empty_variant_node.materials = {
|
||||
"some_different_material": MagicMock(getMetaDataEntry = lambda x: 3),
|
||||
"preferred_material_wrong_diameter": MagicMock(getMetaDataEntry = lambda x: 2), # Approximate diameter is 2 instead of 3.
|
||||
"preferred_material_correct_diameter": MagicMock(getMetaDataEntry = lambda x: 3) # Correct approximate diameter.
|
||||
}
|
||||
|
||||
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["preferred_material_correct_diameter"], "It should match only on the material with correct diameter."
|
||||
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["preferred_material"], "It should match exactly on this one since it's the preferred material."
|
||||
|
||||
## Tests the preferred material matching on a different material if the
|
||||
# diameter is wrong.
|
||||
def test_preferredMaterialDiameterNoMatch(empty_variant_node):
|
||||
empty_variant_node.materials = collections.OrderedDict()
|
||||
empty_variant_node.materials["some_different_material"] = MagicMock(getMetaDataEntry = lambda x: 3) # This one first so that it gets iterated over first.
|
||||
empty_variant_node.materials["preferred_material_wrong_diameter"] = MagicMock(getMetaDataEntry = lambda x: 2)
|
||||
empty_variant_node.materials["preferred_material"] = MagicMock(getMetaDataEntry = lambda x: 2) # Wrong diameter.
|
||||
|
||||
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["some_different_material"], "It should match on another material with the correct diameter if the preferred one is unavailable."
|
||||
|
||||
|
@ -177,7 +156,7 @@ def test_preferredMaterialDiameterNoMatch(empty_variant_node):
|
|||
def test_preferredMaterialDiameterPreference(empty_variant_node):
|
||||
empty_variant_node.materials = collections.OrderedDict()
|
||||
empty_variant_node.materials["some_different_material"] = MagicMock(getMetaDataEntry = lambda x: 2) # This one first so that it gets iterated over first.
|
||||
empty_variant_node.materials["preferred_material_wrong_diameter"] = MagicMock(getMetaDataEntry = lambda x: 2) # Matches on ID but not diameter.
|
||||
empty_variant_node.materials["preferred_material"] = MagicMock(getMetaDataEntry = lambda x: 2) # Matches on ID but not diameter.
|
||||
empty_variant_node.materials["not_preferred_but_correct_diameter"] = MagicMock(getMetaDataEntry = lambda x: 3) # Matches diameter but not ID.
|
||||
|
||||
assert empty_variant_node.preferredMaterial(approximate_diameter = 3) == empty_variant_node.materials["not_preferred_but_correct_diameter"], "It should match on the correct diameter even if it's not the preferred one."
|
|
@ -17,6 +17,10 @@ Resources.addSearchPath(os.path.abspath(os.path.join(os.path.dirname(__file__),
|
|||
|
||||
|
||||
machine_filepaths = sorted(os.listdir(os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions")))
|
||||
machine_filepaths = [os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions", filename) for filename in machine_filepaths]
|
||||
extruder_filepaths = sorted(os.listdir(os.path.join(os.path.dirname(__file__), "..", "..", "resources", "extruders")))
|
||||
extruder_filepaths = [os.path.join(os.path.dirname(__file__), "..", "..", "resources", "extruders", filename) for filename in extruder_filepaths]
|
||||
definition_filepaths = machine_filepaths + extruder_filepaths
|
||||
all_meshes = os.listdir(os.path.join(os.path.dirname(__file__), "..", "..", "resources", "meshes"))
|
||||
all_images = os.listdir(os.path.join(os.path.dirname(__file__), "..", "..", "resources", "images"))
|
||||
|
||||
|
@ -29,17 +33,16 @@ def definition_container():
|
|||
|
||||
|
||||
## Tests all definition containers
|
||||
@pytest.mark.parametrize("file_name", machine_filepaths)
|
||||
def test_validateMachineDefinitionContainer(file_name, definition_container):
|
||||
@pytest.mark.parametrize("file_path", machine_filepaths)
|
||||
def test_validateMachineDefinitionContainer(file_path, definition_container):
|
||||
file_name = os.path.basename(file_path)
|
||||
if file_name == "fdmprinter.def.json" or file_name == "fdmextruder.def.json":
|
||||
return # Stop checking, these are root files.
|
||||
|
||||
definition_path = os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions")
|
||||
assertIsDefinitionValid(definition_container, definition_path, file_name)
|
||||
assertIsDefinitionValid(definition_container, file_path)
|
||||
|
||||
|
||||
def assertIsDefinitionValid(definition_container, path, file_name):
|
||||
with open(os.path.join(path, file_name), encoding = "utf-8") as data:
|
||||
def assertIsDefinitionValid(definition_container, file_path):
|
||||
with open(file_path, encoding = "utf-8") as data:
|
||||
json = data.read()
|
||||
parser, is_valid = definition_container.readAndValidateSerialized(json)
|
||||
assert is_valid #The definition has invalid JSON structure.
|
||||
|
@ -57,10 +60,9 @@ def assertIsDefinitionValid(definition_container, path, file_name):
|
|||
# When a definition container defines a "default_value" but inherits from a
|
||||
# definition that defines a "value", the "default_value" is ineffective. This
|
||||
# test fails on those things.
|
||||
@pytest.mark.parametrize("file_name", machine_filepaths)
|
||||
def test_validateOverridingDefaultValue(file_name: str):
|
||||
definition_path = os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions", file_name)
|
||||
with open(definition_path, encoding = "utf-8") as f:
|
||||
@pytest.mark.parametrize("file_path", definition_filepaths)
|
||||
def test_validateOverridingDefaultValue(file_path: str):
|
||||
with open(file_path, encoding = "utf-8") as f:
|
||||
doc = json.load(f)
|
||||
|
||||
if "inherits" not in doc:
|
||||
|
@ -69,8 +71,8 @@ def test_validateOverridingDefaultValue(file_name: str):
|
|||
return # No settings are being overridden. No need to check anything.
|
||||
parent_settings = getInheritedSettings(doc["inherits"])
|
||||
for key, val in doc["overrides"].items():
|
||||
if "value" in parent_settings[key]:
|
||||
assert "default_value" not in val, "Unnecessary default_value for {key} in {file_name}".format(key = key, file_name = file_name) # If there is a value in the parent settings, then the default_value is not effective.
|
||||
if key in parent_settings and "value" in parent_settings[key]:
|
||||
assert "default_value" not in val, "Unnecessary default_value for {key} in {file_name}".format(key = key, file_name = file_path) # If there is a value in the parent settings, then the default_value is not effective.
|
||||
|
||||
## Get all settings and their properties from a definition we're inheriting
|
||||
# from.
|
||||
|
@ -130,10 +132,46 @@ def merge_dicts(base: Dict[str, Any], overrides: Dict[str, Any]) -> Dict[str, An
|
|||
#
|
||||
# ID fields are legacy. They should not be used any more. This is legacy that
|
||||
# people don't seem to be able to get used to.
|
||||
@pytest.mark.parametrize("file_name", machine_filepaths)
|
||||
def test_noId(file_name):
|
||||
definition_path = os.path.join(os.path.dirname(__file__), "..", "..", "resources", "definitions", file_name)
|
||||
with open(definition_path, encoding = "utf-8") as f:
|
||||
@pytest.mark.parametrize("file_path", definition_filepaths)
|
||||
def test_noId(file_path: str):
|
||||
with open(file_path, encoding = "utf-8") as f:
|
||||
doc = json.load(f)
|
||||
|
||||
assert "id" not in doc, "Definitions should not have an ID field."
|
||||
assert "id" not in doc, "Definitions should not have an ID field."
|
||||
|
||||
## Verifies that extruders say that they work on the same extruder_nr as what
|
||||
# is listed in their machine definition.
|
||||
@pytest.mark.parametrize("file_path", extruder_filepaths)
|
||||
def test_extruderMatch(file_path: str):
|
||||
extruder_id = os.path.basename(file_path).split(".")[0]
|
||||
with open(file_path, encoding = "utf-8") as f:
|
||||
doc = json.load(f)
|
||||
|
||||
if "metadata" not in doc:
|
||||
return # May not be desirable either, but it's probably unfinished then.
|
||||
if "machine" not in doc["metadata"] or "position" not in doc["metadata"]:
|
||||
return # FDMextruder doesn't have this since it's not linked to a particular printer.
|
||||
machine = doc["metadata"]["machine"]
|
||||
position = doc["metadata"]["position"]
|
||||
|
||||
# Find the machine definition.
|
||||
for machine_filepath in machine_filepaths:
|
||||
machine_id = os.path.basename(machine_filepath).split(".")[0]
|
||||
if machine_id == machine:
|
||||
break
|
||||
else:
|
||||
assert False, "The machine ID {machine} is not found.".format(machine = machine)
|
||||
with open(machine_filepath, encoding = "utf-8") as f:
|
||||
machine_doc = json.load(f)
|
||||
|
||||
# Make sure that the two match up.
|
||||
assert "metadata" in machine_doc, "Machine definition missing metadata entry."
|
||||
assert "machine_extruder_trains" in machine_doc["metadata"], "Machine must define extruder trains."
|
||||
extruder_trains = machine_doc["metadata"]["machine_extruder_trains"]
|
||||
assert position in extruder_trains, "There must be a reference to the extruder in the machine definition."
|
||||
assert extruder_trains[position] == extruder_id, "The extruder referenced in the machine definition must match up."
|
||||
|
||||
# Also test if the extruder_nr setting is properly overridden.
|
||||
if "overrides" not in doc or "extruder_nr" not in doc["overrides"] or "default_value" not in doc["overrides"]["extruder_nr"]:
|
||||
assert position == "0" # Default to 0 is allowed.
|
||||
assert doc["overrides"]["extruder_nr"]["default_value"] == int(position)
|
Loading…
Add table
Add a link
Reference in a new issue