Merge remote-tracking branch 'upstream/master' into UM3NPP_merge

This commit is contained in:
Thomas Karl Pietrowski 2016-11-21 14:44:19 +01:00
commit a0ba393673
81 changed files with 1789 additions and 376 deletions

View File

@ -24,7 +24,7 @@ if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
CREATE_TRANSLATION_TARGETS()
endif()
find_package(PythonInterp 3.4.0 REQUIRED)
find_package(PythonInterp 3.5.0 REQUIRED)
install(DIRECTORY resources
DESTINATION ${CMAKE_INSTALL_DATADIR}/cura)

View File

@ -5,6 +5,7 @@ Name[de]=Cura
GenericName=3D Printing Software
GenericName[de]=3D-Druck-Software
Comment=Cura converts 3D models into paths for a 3D printer. It prepares your print for maximum accuracy, minimum printing time and good reliability with many extra features that make your print come out great.
Comment[de]=Cura wandelt 3D-Modelle in Pfade für einen 3D-Drucker um. Es bereitet Ihren Druck für maximale Genauigkeit, minimale Druckzeit und guter Zuverlässigkeit mit vielen zusätzlichen Funktionen vor, damit Ihr Druck großartig wird.
Exec=@CMAKE_INSTALL_FULL_BINDIR@/cura %F
TryExec=@CMAKE_INSTALL_FULL_BINDIR@/cura
Icon=@CMAKE_INSTALL_FULL_DATADIR@/cura/resources/images/cura-icon.png

View File

@ -27,7 +27,7 @@ import UM.Settings.ContainerRegistry
# Setting for clearance around the prime
PRIME_CLEARANCE = 1.5
PRIME_CLEARANCE = 6.5
## Build volume is a special kind of node that is responsible for rendering the printable area & disallowed areas.
@ -75,8 +75,8 @@ class BuildVolume(SceneNode):
self._has_errors = False
Application.getInstance().getController().getScene().sceneChanged.connect(self._onSceneChanged)
# Number of objects loaded at the moment.
self._number_of_objects = 0
#Objects loaded at the moment. We are connected to the property changed events of these objects.
self._scene_objects = set()
self._change_timer = QTimer()
self._change_timer.setInterval(100)
@ -102,14 +102,33 @@ class BuildVolume(SceneNode):
def _onChangeTimerFinished(self):
root = Application.getInstance().getController().getScene().getRoot()
new_number_of_objects = len([node for node in BreadthFirstIterator(root) if node.getMeshData() and type(node) is SceneNode])
if new_number_of_objects != self._number_of_objects:
recalculate = False
if self._global_container_stack.getProperty("print_sequence", "value") == "one_at_a_time":
recalculate = (new_number_of_objects < 2 and self._number_of_objects > 1) or (new_number_of_objects > 1 and self._number_of_objects < 2)
self._number_of_objects = new_number_of_objects
if recalculate:
self._onSettingPropertyChanged("print_sequence", "value") # Create fake event, so right settings are triggered.
new_scene_objects = set(node for node in BreadthFirstIterator(root) if node.getMeshData() and type(node) is SceneNode)
if new_scene_objects != self._scene_objects:
for node in new_scene_objects - self._scene_objects: #Nodes that were added to the scene.
node.decoratorsChanged.connect(self._onNodeDecoratorChanged)
for node in self._scene_objects - new_scene_objects: #Nodes that were removed from the scene.
per_mesh_stack = node.callDecoration("getStack")
if per_mesh_stack:
per_mesh_stack.propertyChanged.disconnect(self._onSettingPropertyChanged)
active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal")
if active_extruder_changed is not None:
node.callDecoration("getActiveExtruderChangedSignal").disconnect(self._updateDisallowedAreasAndRebuild)
node.decoratorsChanged.disconnect(self._onNodeDecoratorChanged)
self._scene_objects = new_scene_objects
self._onSettingPropertyChanged("print_sequence", "value") # Create fake event, so right settings are triggered.
## Updates the listeners that listen for changes in per-mesh stacks.
#
# \param node The node for which the decorators changed.
def _onNodeDecoratorChanged(self, node):
per_mesh_stack = node.callDecoration("getStack")
if per_mesh_stack:
per_mesh_stack.propertyChanged.connect(self._onSettingPropertyChanged)
active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal")
if active_extruder_changed is not None:
active_extruder_changed.connect(self._updateDisallowedAreasAndRebuild)
self._updateDisallowedAreasAndRebuild()
def setWidth(self, width):
if width: self._width = width
@ -324,7 +343,7 @@ class BuildVolume(SceneNode):
self._width = self._global_container_stack.getProperty("machine_width", "value")
machine_height = self._global_container_stack.getProperty("machine_height", "value")
if self._global_container_stack.getProperty("print_sequence", "value") == "one_at_a_time" and self._number_of_objects > 1:
if self._global_container_stack.getProperty("print_sequence", "value") == "one_at_a_time" and len(self._scene_objects) > 1:
self._height = min(self._global_container_stack.getProperty("gantry_height", "value"), machine_height)
if self._height < machine_height:
self._build_volume_message.show()
@ -347,7 +366,7 @@ class BuildVolume(SceneNode):
rebuild_me = False
if setting_key == "print_sequence":
machine_height = self._global_container_stack.getProperty("machine_height", "value")
if Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time" and self._number_of_objects > 1:
if Application.getInstance().getGlobalContainerStack().getProperty("print_sequence", "value") == "one_at_a_time" and len(self._scene_objects) > 1:
self._height = min(self._global_container_stack.getProperty("gantry_height", "value"), machine_height)
if self._height < machine_height:
self._build_volume_message.show()
@ -358,7 +377,7 @@ class BuildVolume(SceneNode):
self._build_volume_message.hide()
rebuild_me = True
if setting_key in self._skirt_settings or setting_key in self._prime_settings or setting_key in self._tower_settings or setting_key == "print_sequence" or setting_key in self._ooze_shield_settings or setting_key in self._distance_settings:
if setting_key in self._skirt_settings or setting_key in self._prime_settings or setting_key in self._tower_settings or setting_key == "print_sequence" or setting_key in self._ooze_shield_settings or setting_key in self._distance_settings or setting_key in self._extruder_settings:
self._updateDisallowedAreas()
rebuild_me = True
@ -372,24 +391,109 @@ class BuildVolume(SceneNode):
def hasErrors(self):
return self._has_errors
## Calls _updateDisallowedAreas and makes sure the changes appear in the
# scene.
#
# This is required for a signal to trigger the update in one go. The
# ``_updateDisallowedAreas`` method itself shouldn't call ``rebuild``,
# since there may be other changes before it needs to be rebuilt, which
# would hit performance.
def _updateDisallowedAreasAndRebuild(self):
self._updateDisallowedAreas()
self.rebuild()
def _updateDisallowedAreas(self):
if not self._global_container_stack:
return
self._has_errors = False # Reset.
self._error_areas = []
disallowed_areas = copy.deepcopy(
self._global_container_stack.getProperty("machine_disallowed_areas", "value"))
areas = []
machine_width = self._global_container_stack.getProperty("machine_width", "value")
machine_depth = self._global_container_stack.getProperty("machine_depth", "value")
prime_tower_area = None
extruder_manager = ExtruderManager.getInstance()
used_extruders = extruder_manager.getUsedExtruderStacks()
disallowed_border_size = self._getEdgeDisallowedSize()
result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) #Normal machine disallowed areas can always be added.
prime_areas = self._computeDisallowedAreasPrime(disallowed_border_size, used_extruders)
prime_disallowed_areas = self._computeDisallowedAreasStatic(0, used_extruders) #Where the priming is not allowed to happen. This is not added to the result, just for collision checking.
#Check if prime positions intersect with disallowed areas.
for extruder in used_extruders:
extruder_id = extruder.getId()
collision = False
for prime_polygon in prime_areas[extruder_id]:
for disallowed_polygon in prime_disallowed_areas[extruder_id]:
if prime_polygon.intersectsPolygon(disallowed_polygon) is not None:
collision = True
break
if collision:
break
#Also check other prime positions (without additional offset).
for other_extruder_id in prime_areas:
if extruder_id == other_extruder_id: #It is allowed to collide with itself.
continue
for other_prime_polygon in prime_areas[other_extruder_id]:
if prime_polygon.intersectsPolygon(other_prime_polygon):
collision = True
break
if collision:
break
if collision:
break
if not collision:
#Prime areas are valid. Add as normal.
result_areas[extruder_id].extend(prime_areas[extruder_id])
nozzle_disallowed_areas = extruder.getProperty("nozzle_disallowed_areas", "value")
for area in nozzle_disallowed_areas:
polygon = Polygon(numpy.array(area, numpy.float32))
polygon = polygon.getMinkowskiHull(Polygon.approximatedCircle(disallowed_border_size))
result_areas[extruder_id].append(polygon) #Don't perform the offset on these.
# Add prime tower location as disallowed area.
prime_tower_collision = False
prime_tower_areas = self._computeDisallowedAreasPrinted(used_extruders)
for extruder_id in prime_tower_areas:
for prime_tower_area in prime_tower_areas[extruder_id]:
for area in result_areas[extruder_id]:
if prime_tower_area.intersectsPolygon(area) is not None:
prime_tower_collision = True
break
if prime_tower_collision: #Already found a collision.
break
if not prime_tower_collision:
result_areas[extruder_id].extend(prime_tower_areas[extruder_id])
else:
self._error_areas.extend(prime_tower_areas[extruder_id])
self._has_errors = len(self._error_areas) > 0
self._disallowed_areas = []
for extruder_id in result_areas:
self._disallowed_areas.extend(result_areas[extruder_id])
## Computes the disallowed areas for objects that are printed with print
# features.
#
# This means that the brim, travel avoidance and such will be applied to
# these features.
#
# \return A dictionary with for each used extruder ID the disallowed areas
# where that extruder may not print.
def _computeDisallowedAreasPrinted(self, used_extruders):
result = {}
for extruder in used_extruders:
result[extruder.getId()] = []
#Currently, the only normally printed object is the prime tower.
if ExtruderManager.getInstance().getResolveOrValue("prime_tower_enable") == True:
prime_tower_size = self._global_container_stack.getProperty("prime_tower_size", "value")
prime_tower_x = self._global_container_stack.getProperty("prime_tower_position_x", "value") - machine_width / 2
machine_width = self._global_container_stack.getProperty("machine_width", "value")
machine_depth = self._global_container_stack.getProperty("machine_depth", "value")
prime_tower_x = self._global_container_stack.getProperty("prime_tower_position_x", "value") - machine_width / 2 #Offset by half machine_width and _depth to put the origin in the front-left.
prime_tower_y = - self._global_container_stack.getProperty("prime_tower_position_y", "value") + machine_depth / 2
prime_tower_area = Polygon([
@ -398,118 +502,118 @@ class BuildVolume(SceneNode):
[prime_tower_x, prime_tower_y],
[prime_tower_x - prime_tower_size, prime_tower_y],
])
disallowed_polygons = []
prime_tower_area = prime_tower_area.getMinkowskiHull(Polygon.approximatedCircle(0))
for extruder in used_extruders:
result[extruder.getId()].append(prime_tower_area) #The prime tower location is the same for each extruder, regardless of offset.
# Check if prime positions intersect with disallowed areas
prime_collision = False
if disallowed_areas:
for area in disallowed_areas:
poly = Polygon(numpy.array(area, numpy.float32))
return result
# Minkowski with zero, to ensure that the polygon is correct & watertight.
poly = poly.getMinkowskiHull(Polygon.approximatedCircle(0))
disallowed_polygons.append(poly)
## Computes the disallowed areas for the prime locations.
#
# These are special because they are not subject to things like brim or
# travel avoidance. They do get a dilute with the border size though
# because they may not intersect with brims and such of other objects.
#
# \param border_size The size with which to offset the disallowed areas
# due to skirt, brim, travel avoid distance, etc.
# \param used_extruders The extruder stacks to generate disallowed areas
# for.
# \return A dictionary with for each used extruder ID the prime areas.
def _computeDisallowedAreasPrime(self, border_size, used_extruders):
result = {}
extruder_manager = ExtruderManager.getInstance()
extruders = extruder_manager.getMachineExtruders(self._global_container_stack.getId())
prime_polygons = []
# Each extruder has it's own prime location
for extruder in extruders:
prime_x = extruder.getProperty("extruder_prime_pos_x", "value") - machine_width / 2
prime_y = machine_depth / 2 - extruder.getProperty("extruder_prime_pos_y", "value")
machine_width = self._global_container_stack.getProperty("machine_width", "value")
machine_depth = self._global_container_stack.getProperty("machine_depth", "value")
for extruder in used_extruders:
prime_x = extruder.getProperty("extruder_prime_pos_x", "value") - machine_width / 2 #Offset by half machine_width and _depth to put the origin in the front-left.
prime_y = machine_depth / 2 - extruder.getProperty("extruder_prime_pos_y", "value")
prime_polygon = Polygon([
[prime_x - PRIME_CLEARANCE, prime_y - PRIME_CLEARANCE],
[prime_x + PRIME_CLEARANCE, prime_y - PRIME_CLEARANCE],
[prime_x + PRIME_CLEARANCE, prime_y + PRIME_CLEARANCE],
[prime_x - PRIME_CLEARANCE, prime_y + PRIME_CLEARANCE],
])
prime_polygon = prime_polygon.getMinkowskiHull(Polygon.approximatedCircle(0))
collision = False
prime_polygon = Polygon.approximatedCircle(PRIME_CLEARANCE)
prime_polygon = prime_polygon.translate(prime_x, prime_y)
prime_polygon = prime_polygon.getMinkowskiHull(Polygon.approximatedCircle(border_size))
result[extruder.getId()] = [prime_polygon]
# Check if prime polygon is intersecting with any of the other disallowed areas.
# Note that we check the prime area without bed adhesion.
for poly in disallowed_polygons:
if prime_polygon.intersectsPolygon(poly) is not None:
collision = True
break
return result
# Also collide with other prime positions
for poly in prime_polygons:
if prime_polygon.intersectsPolygon(poly) is not None:
collision = True
break
## Computes the disallowed areas that are statically placed in the machine.
#
# It computes different disallowed areas depending on the offset of the
# extruder. The resulting dictionary will therefore have an entry for each
# extruder that is used.
#
# \param border_size The size with which to offset the disallowed areas
# due to skirt, brim, travel avoid distance, etc.
# \param used_extruders The extruder stacks to generate disallowed areas
# for.
# \return A dictionary with for each used extruder ID the disallowed areas
# where that extruder may not print.
def _computeDisallowedAreasStatic(self, border_size, used_extruders):
#Convert disallowed areas to polygons and dilate them.
machine_disallowed_polygons = []
for area in self._global_container_stack.getProperty("machine_disallowed_areas", "value"):
polygon = Polygon(numpy.array(area, numpy.float32))
polygon = polygon.getMinkowskiHull(Polygon.approximatedCircle(border_size))
machine_disallowed_polygons.append(polygon)
if not collision:
# Prime area is valid. Add as normal.
# Once it's added like this, it will recieve a bed adhesion offset, just like the others.
prime_polygons.append(prime_polygon)
else:
self._error_areas.append(prime_polygon)
prime_collision = collision or prime_collision
result = {}
for extruder in used_extruders:
extruder_id = extruder.getId()
offset_x = extruder.getProperty("machine_nozzle_offset_x", "value")
if offset_x is None:
offset_x = 0
offset_y = extruder.getProperty("machine_nozzle_offset_y", "value")
if offset_y is None:
offset_y = 0
result[extruder_id] = []
disallowed_polygons.extend(prime_polygons)
for polygon in machine_disallowed_polygons:
result[extruder_id].append(polygon.translate(offset_x, offset_y)) #Compensate for the nozzle offset of this extruder.
disallowed_border_size = self._getEdgeDisallowedSize()
# Extend every area already in the disallowed_areas with the skirt size.
if disallowed_areas:
for poly in disallowed_polygons:
poly = poly.getMinkowskiHull(Polygon.approximatedCircle(disallowed_border_size))
areas.append(poly)
# Add the skirt areas around the borders of the build plate.
if disallowed_border_size > 0:
#Add the border around the edge of the build volume.
left_unreachable_border = 0
right_unreachable_border = 0
top_unreachable_border = 0
bottom_unreachable_border = 0
#The build volume is defined as the union of the area that all extruders can reach, so we need to know the relative offset to all extruders.
for other_extruder in ExtruderManager.getInstance().getActiveExtruderStacks():
other_offset_x = other_extruder.getProperty("machine_nozzle_offset_x", "value")
other_offset_y = other_extruder.getProperty("machine_nozzle_offset_y", "value")
left_unreachable_border = min(left_unreachable_border, other_offset_x - offset_x)
right_unreachable_border = max(right_unreachable_border, other_offset_x - offset_x)
top_unreachable_border = min(top_unreachable_border, other_offset_y - offset_y)
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)))
areas.append(Polygon(numpy.array([
[-half_machine_width, -half_machine_depth],
[-half_machine_width, half_machine_depth],
[-half_machine_width + disallowed_border_size, half_machine_depth - disallowed_border_size],
[-half_machine_width + disallowed_border_size, -half_machine_depth + disallowed_border_size]
], numpy.float32)))
areas.append(Polygon(numpy.array([
[half_machine_width, half_machine_depth],
[half_machine_width, -half_machine_depth],
[half_machine_width - disallowed_border_size, -half_machine_depth + disallowed_border_size],
[half_machine_width - disallowed_border_size, half_machine_depth - disallowed_border_size]
], numpy.float32)))
areas.append(Polygon(numpy.array([
[-half_machine_width, half_machine_depth],
[half_machine_width, half_machine_depth],
[half_machine_width - disallowed_border_size, half_machine_depth - disallowed_border_size],
[-half_machine_width + disallowed_border_size, half_machine_depth - disallowed_border_size]
], numpy.float32)))
areas.append(Polygon(numpy.array([
[half_machine_width, -half_machine_depth],
[-half_machine_width, -half_machine_depth],
[-half_machine_width + disallowed_border_size, -half_machine_depth + disallowed_border_size],
[half_machine_width - disallowed_border_size, -half_machine_depth + disallowed_border_size]
], numpy.float32)))
# Check if the prime tower area intersects with any of the other areas.
# If this is the case, add it to the error area's so it can be drawn in red.
# If not, add it back to disallowed area's, so it's rendered as normal.
prime_tower_collision = False
if prime_tower_area:
# Using Minkowski of 0 fixes the prime tower area so it's rendered correctly
prime_tower_area = prime_tower_area.getMinkowskiHull(Polygon.approximatedCircle(0))
for area in areas:
if prime_tower_area.intersectsPolygon(area) is not None:
prime_tower_collision = True
break
if not prime_tower_collision:
areas.append(prime_tower_area)
else:
self._error_areas.append(prime_tower_area)
# The buildplate has errors if either prime tower or prime has a colission.
self._has_errors = prime_tower_collision or prime_collision
self._disallowed_areas = areas
return result
## Private convenience function to get a setting from the adhesion
# extruder.
@ -520,6 +624,15 @@ class BuildVolume(SceneNode):
def _getSettingFromAdhesionExtruder(self, setting_key, property = "value"):
return self._getSettingFromExtruder(setting_key, "adhesion_extruder_nr", property)
## Private convenience function to get a setting from every extruder.
#
# For single extrusion machines, this gets the setting from the global
# stack.
#
# \return A sequence of setting values, one for each extruder.
def _getSettingFromAllExtruders(self, setting_key, property = "value"):
return ExtruderManager.getInstance().getAllExtruderSettings(setting_key, property)
## Private convenience function to get a setting from the support infill
# extruder.
#
@ -588,6 +701,8 @@ class BuildVolume(SceneNode):
bed_adhesion_size += value
elif adhesion_type == "raft":
bed_adhesion_size = self._getSettingFromAdhesionExtruder("raft_margin")
elif adhesion_type == "none":
bed_adhesion_size = 0
else:
raise Exception("Unknown bed adhesion type. Did you forget to update the build volume calculations for your new bed adhesion type?")
@ -602,10 +717,12 @@ class BuildVolume(SceneNode):
farthest_shield_distance = max(farthest_shield_distance, container_stack.getProperty("ooze_shield_dist", "value"))
move_from_wall_radius = 0 # Moves that start from outer wall.
if self._getSettingFromAdhesionExtruder("infill_wipe_dist"):
move_from_wall_radius = max(move_from_wall_radius, self._getSettingFromAdhesionExtruder("infill_wipe_dist"))
if self._getSettingFromAdhesionExtruder("travel_avoid_distance") and self._getSettingFromAdhesionExtruder("travel_avoid_other_parts"):
move_from_wall_radius = max(move_from_wall_radius, self._getSettingFromAdhesionExtruder("travel_avoid_distance"))
move_from_wall_radius = max(move_from_wall_radius, max(self._getSettingFromAllExtruders("infill_wipe_dist")))
avoid_enabled_per_extruder = self._getSettingFromAllExtruders(("travel_avoid_other_parts"))
avoid_distance_per_extruder = self._getSettingFromAllExtruders("travel_avoid_distance")
for index, avoid_other_parts_enabled in enumerate(avoid_enabled_per_extruder): #For each extruder (or just global).
if avoid_other_parts_enabled:
move_from_wall_radius = max(move_from_wall_radius, avoid_distance_per_extruder[index]) #Index of the same extruder.
#Now combine our different pieces of data to get the final border size.
#Support expansion is added to the bed adhesion, since the bed adhesion goes around support.
@ -622,3 +739,4 @@ class BuildVolume(SceneNode):
_tower_settings = ["prime_tower_enable", "prime_tower_size", "prime_tower_position_x", "prime_tower_position_y"]
_ooze_shield_settings = ["ooze_shield_enabled", "ooze_shield_dist"]
_distance_settings = ["infill_wipe_dist", "travel_avoid_distance", "support_offset", "support_enable", "travel_avoid_other_parts"]
_extruder_settings = ["support_enable", "support_interface_enable", "support_infill_extruder_nr", "support_extruder_nr_layer_0", "support_interface_extruder_nr", "brim_line_count", "adhesion_extruder_nr", "adhesion_type"] #Settings that can affect which extruders are used.

View File

@ -236,6 +236,8 @@ class ConvexHullDecorator(SceneNodeDecorator):
extra_margin = max(0, self._getSettingProperty("raft_margin", "value"))
elif adhesion_type == "brim":
extra_margin = max(0, self._getSettingProperty("brim_line_count", "value") * self._getSettingProperty("skirt_brim_line_width", "value"))
elif adhesion_type == "none":
extra_margin = 0
elif adhesion_type == "skirt":
extra_margin = max(
0, self._getSettingProperty("skirt_gap", "value") +

View File

@ -258,7 +258,7 @@ class CuraApplication(QtApplication):
Preferences.getInstance().setDefault("general/visible_settings", """
machine_settings
resolution
resolution
layer_height
shell
wall_thickness
@ -558,7 +558,9 @@ class CuraApplication(QtApplication):
qmlRegisterSingletonType(cura.Settings.ContainerManager, "Cura", 1, 0, "ContainerManager", cura.Settings.ContainerManager.createContainerManager)
qmlRegisterSingletonType(QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")), "Cura", 1, 0, "Actions")
# As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work.
actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")))
qmlRegisterSingletonType(actions_url, "Cura", 1, 0, "Actions")
engine.rootContext().setContextProperty("ExtruderManager", cura.Settings.ExtruderManager.getInstance())
@ -571,11 +573,19 @@ class CuraApplication(QtApplication):
def onSelectionChanged(self):
if Selection.hasSelection():
if not self.getController().getActiveTool():
if self.getController().getActiveTool():
# If the tool has been disabled by the new selection
if not self.getController().getActiveTool().getEnabled():
# Default
self.getController().setActiveTool("TranslateTool")
else:
if self._previous_active_tool:
self.getController().setActiveTool(self._previous_active_tool)
if not self.getController().getActiveTool().getEnabled():
self.getController().setActiveTool("TranslateTool")
self._previous_active_tool = None
else:
# Default
self.getController().setActiveTool("TranslateTool")
if Preferences.getInstance().getValue("view/center_on_select"):
self._center_after_select = True
@ -686,10 +696,9 @@ class CuraApplication(QtApplication):
while current_node.getParent() and current_node.getParent().callDecoration("isGroup"):
current_node = current_node.getParent()
new_node = copy.deepcopy(current_node)
op = GroupedOperation()
for _ in range(count):
new_node = copy.deepcopy(current_node)
op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
op.push()
@ -770,7 +779,11 @@ class CuraApplication(QtApplication):
for node in nodes:
# Ensure that the object is above the build platform
node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
op.addOperation(SetTransformOperation(node, Vector(0, node.getWorldPosition().y - node.getBoundingBox().bottom, 0)))
if node.getBoundingBox():
center_y = node.getWorldPosition().y - node.getBoundingBox().bottom
else:
center_y = 0
op.addOperation(SetTransformOperation(node, Vector(0, center_y, 0)))
op.push()
## Reset all transformations on nodes with mesh data.
@ -792,11 +805,10 @@ class CuraApplication(QtApplication):
for node in nodes:
# Ensure that the object is above the build platform
node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
center_y = 0
if node.callDecoration("isGroup"):
if node.getBoundingBox():
center_y = node.getWorldPosition().y - node.getBoundingBox().bottom
else:
center_y = node.getMeshData().getCenterPosition().y
center_y = 0
op.addOperation(SetTransformOperation(node, Vector(0, center_y, 0), Quaternion(), Vector(1, 1, 1)))
op.push()
@ -865,8 +877,15 @@ class CuraApplication(QtApplication):
Logger.log("d", "mergeSelected: Exception:", e)
return
# Compute the center of the objects when their origins are aligned.
object_centers = [node.getMeshData().getCenterPosition().scale(node.getScale()) for node in group_node.getChildren() if node.getMeshData()]
meshes = [node.getMeshData() for node in group_node.getAllChildren() if node.getMeshData()]
# Compute the center of the objects
object_centers = []
for mesh, node in zip(meshes, group_node.getChildren()):
orientation = node.getOrientation().toMatrix()
rotated_mesh = mesh.getTransformed(orientation)
center = rotated_mesh.getCenterPosition().scale(node.getScale())
object_centers.append(center)
if object_centers and len(object_centers) > 0:
middle_x = sum([v.x for v in object_centers]) / len(object_centers)
middle_y = sum([v.y for v in object_centers]) / len(object_centers)
@ -876,9 +895,13 @@ class CuraApplication(QtApplication):
offset = Vector(0, 0, 0)
# Move each node to the same position.
for center, node in zip(object_centers, group_node.getChildren()):
# Align the object and also apply the offset to center it inside the group.
node.setPosition(center - offset)
for mesh, node in zip(meshes, group_node.getChildren()):
orientation = node.getOrientation().toMatrix()
rotated_mesh = mesh.getTransformed(orientation)
# Align the object around its zero position
# and also apply the offset to center it inside the group.
node.setPosition(-rotated_mesh.getZeroPosition().scale(node.getScale()) - offset)
# Use the previously found center of the group bounding box as the new location of the group
group_node.setPosition(group_node.getBoundingBox().center)
@ -932,15 +955,16 @@ class CuraApplication(QtApplication):
fileLoaded = pyqtSignal(str)
def _onFileLoaded(self, job):
node = job.getResult()
if node != None:
self.fileLoaded.emit(job.getFileName())
node.setSelectable(True)
node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
op.push()
nodes = job.getResult()
for node in nodes:
if node is not None:
self.fileLoaded.emit(job.getFileName())
node.setSelectable(True)
node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
op.push()
self.getController().getScene().sceneChanged.emit(node) #Force scene change.
self.getController().getScene().sceneChanged.emit(node) #Force scene change.
def _onJobFinished(self, job):
if type(job) is not ReadMeshJob or not job.getResult():

View File

@ -134,6 +134,20 @@ class PrinterOutputDevice(QObject, OutputDevice):
def _setJobState(self, job_state):
Logger.log("w", "_setJobState is not implemented by this output device")
@pyqtSlot()
def startCamera(self):
self._startCamera()
def _startCamera(self):
Logger.log("w", "_startCamera is not implemented by this output device")
@pyqtSlot()
def stopCamera(self):
self._stopCamera()
def _stopCamera(self):
Logger.log("w", "_stopCamera is not implemented by this output device")
@pyqtProperty(str, notify = jobNameChanged)
def jobName(self):
return self._job_name

View File

@ -27,10 +27,17 @@ class QualityManager:
# specified then the currently selected machine definition is used.
# \param material_containers (Optional) \type{List[ContainerInstance]} If nothing is specified then
# the current set of selected materials is used.
# \return the matching quality containers \type{List[ContainerInstance]}
# \return the matching quality container \type{ContainerInstance}
def findQualityByName(self, quality_name, machine_definition=None, material_containers=None):
criteria = {"type": "quality", "name": quality_name}
return self._getFilteredContainersForStack(machine_definition, material_containers, **criteria)
result = self._getFilteredContainersForStack(machine_definition, material_containers, **criteria)
# Fall back to using generic materials and qualities if nothing could be found.
if not result and material_containers and len(material_containers) == 1:
basic_materials = self._getBasicMaterials(material_containers[0])
result = self._getFilteredContainersForStack(machine_definition, basic_materials, **criteria)
return result[0] if result else None
## Find a quality changes container by name.
#

View File

@ -4,7 +4,7 @@
import os.path
import urllib
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal, QUrl
from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal, QUrl, QVariant
from PyQt5.QtWidgets import QMessageBox
import UM.PluginRegistry
@ -261,8 +261,9 @@ class ContainerManager(QObject):
@pyqtSlot(str, result = bool)
def isContainerUsed(self, container_id):
UM.Logger.log("d", "Checking if container %s is currently used in the active stacks", container_id)
for stack in cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
UM.Logger.log("d", "Checking if container %s is currently used", container_id)
containers = self._container_registry.findContainerStacks()
for stack in containers:
if container_id in [child.getId() for child in stack.getContainers()]:
UM.Logger.log("d", "The container is in use by %s", stack.getId())
return True
@ -611,13 +612,12 @@ class ContainerManager(QObject):
if base_name is None:
base_name = quality_name
# Try to find a Quality with the name.
containers = QualityManager.getInstance().findQualityByName(quality_name, machine_definition, material_instances)
if containers:
container = containers[0]
container = QualityManager.getInstance().findQualityByName(quality_name, machine_definition, material_instances)
if container:
UM.Logger.log("d", "We found a quality to duplicate.")
return self._duplicateQualityForMachineType(container, base_name, machine_definition)
UM.Logger.log("d", "We found a quality_changes to duplicate.")
# Assume it is a quality changes.
return self._duplicateQualityChangesForMachineType(quality_name, base_name, machine_definition)
@ -791,7 +791,6 @@ class ContainerManager(QObject):
# Create a new quality_changes container for the quality.
quality_changes = UM.Settings.InstanceContainer(self._createUniqueId(base_id, new_name))
print(quality_changes.getId())
quality_changes.setName(new_name)
quality_changes.addMetaDataEntry("type", "quality_changes")
quality_changes.addMetaDataEntry("quality_type", quality_container.getMetaDataEntry("quality_type"))
@ -806,3 +805,50 @@ class ContainerManager(QObject):
else:
quality_changes.setDefinition(QualityManager.getInstance().getParentMachineDefinition(machine_definition))
return quality_changes
## Import profiles from a list of file_urls.
# Each QUrl item must end with .curaprofile, or it will not be imported.
#
# \param QVariant<QUrl>, essentially a list with QUrl objects.
# \return Dict with keys status, text
@pyqtSlot(QVariant, result="QVariantMap")
def importProfiles(self, file_urls):
status = "ok"
results = {"ok": [], "error": []}
for file_url in file_urls:
if not file_url.isValid():
continue
path = file_url.toLocalFile()
if not path:
continue
if not path.endswith(".curaprofile"):
continue
single_result = UM.Settings.ContainerRegistry.getInstance().importProfile(path)
if single_result["status"] == "error":
status = "error"
results[single_result["status"]].append(single_result["message"])
return {
"status": status,
"message": "\n".join(results["ok"] + results["error"])}
## Import single profile, file_url does not have to end with curaprofile
@pyqtSlot(QUrl, result="QVariantMap")
def importProfile(self, file_url):
if not file_url.isValid():
return
path = file_url.toLocalFile()
if not path:
return
return UM.Settings.ContainerRegistry.getInstance().importProfile(path)
@pyqtSlot("QVariantList", QUrl, str)
def exportProfile(self, instance_id, file_url, file_type):
if not file_url.isValid():
return
path = file_url.toLocalFile()
if not path:
return
UM.Settings.ContainerRegistry.getInstance().exportProfile(instance_id, path, file_type)

View File

@ -210,7 +210,7 @@ class CuraContainerRegistry(ContainerRegistry):
return {"status": "ok", "message": catalog.i18nc("@info:status", "Successfully imported profile {0}", profile_or_list[0].getName())}
# If it hasn't returned by now, none of the plugins loaded the profile successfully.
return {"status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type.", file_name)}
return {"status": "error", "message": catalog.i18nc("@info:status", "Profile {0} has an unknown file type or is corrupted.", file_name)}
def _configureProfile(self, profile, id_seed, new_name):
profile.setReadOnly(False)

View File

@ -5,6 +5,8 @@ from PyQt5.QtCore import pyqtSignal, pyqtProperty, pyqtSlot, QObject, QVariant #
import UM.Application #To get the global container stack to find the current machine.
import UM.Logger
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator #To find which extruders are used in the scene.
from UM.Scene.SceneNode import SceneNode #To find which extruders are used in the scene.
import UM.Settings.ContainerRegistry #Finding containers by ID.
import UM.Settings.SettingFunction
@ -268,18 +270,78 @@ class ExtruderManager(QObject):
container_registry.addContainer(container_stack)
def getAllExtruderValues(self, setting_key):
return self.getAllExtruderSettings(setting_key, "value")
## Gets a property of a setting for all extruders.
#
# \param setting_key \type{str} The setting to get the property of.
# \param property \type{str} The property to get.
# \return \type{List} the list of results
def getAllExtruderSettings(self, setting_key, property):
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
if not multi_extrusion:
return [global_container_stack.getProperty(setting_key, "value")]
if global_container_stack.getProperty("machine_extruder_count", "value") <= 1:
return [global_container_stack.getProperty(setting_key, property)]
result = []
for index in self.extruderIds:
extruder_stack_id = self.extruderIds[str(index)]
stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id=extruder_stack_id)[0]
result.append(stack.getProperty(setting_key, "value"))
stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0]
result.append(stack.getProperty(setting_key, property))
return result
## Gets the extruder stacks that are actually being used at the moment.
#
# An extruder stack is being used if it is the extruder to print any mesh
# with, or if it is the support infill extruder, the support interface
# extruder, or the bed adhesion extruder.
#
# If there are no extruders, this returns the global stack as a singleton
# list.
#
# \return A list of extruder stacks.
def getUsedExtruderStacks(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
container_registry = UM.Settings.ContainerRegistry.getInstance()
if global_stack.getProperty("machine_extruder_count", "value") <= 1: #For single extrusion.
return [global_stack]
used_extruder_stack_ids = set()
#Get the extruders of all meshes in the scene.
support_enabled = False
support_interface_enabled = False
scene_root = UM.Application.getInstance().getController().getScene().getRoot()
meshes = [node for node in DepthFirstIterator(scene_root) if type(node) is SceneNode and node.isSelectable()] #Only use the nodes that will be printed.
for mesh in meshes:
extruder_stack_id = mesh.callDecoration("getActiveExtruder")
if not extruder_stack_id: #No per-object settings for this node.
extruder_stack_id = self.extruderIds["0"]
used_extruder_stack_ids.add(extruder_stack_id)
#Get whether any of them use support.
per_mesh_stack = mesh.callDecoration("getStack")
if per_mesh_stack:
support_enabled |= per_mesh_stack.getProperty("support_enable", "value")
support_interface_enabled |= per_mesh_stack.getProperty("support_interface_enable", "value")
else: #Take the setting from the build extruder stack.
extruder_stack = container_registry.findContainerStacks(id = extruder_stack_id)[0]
support_enabled |= extruder_stack.getProperty("support_enable", "value")
support_interface_enabled |= extruder_stack.getProperty("support_enable", "value")
#The support extruders.
if support_enabled:
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_infill_extruder_nr", "value"))])
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_extruder_nr_layer_0", "value"))])
if support_interface_enabled:
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("support_interface_extruder_nr", "value"))])
#The platform adhesion extruder. Not used if using none.
if global_stack.getProperty("adhesion_type", "value") != "none":
used_extruder_stack_ids.add(self.extruderIds[str(global_stack.getProperty("adhesion_extruder_nr", "value"))])
return [container_registry.findContainerStacks(id = stack_id)[0] for stack_id in used_extruder_stack_ids]
## Removes the container stack and user profile for the extruders for a specific machine.
#
# \param machine_id The machine to remove the extruders for.

View File

@ -34,7 +34,7 @@ class MachineManager(QObject):
self.globalContainerChanged.connect(self.activeVariantChanged)
self.globalContainerChanged.connect(self.activeQualityChanged)
self._active_stack_valid = None
self._stacks_have_errors = None
self._onGlobalContainerChanged()
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
@ -85,6 +85,7 @@ class MachineManager(QObject):
globalValueChanged = pyqtSignal() # Emitted whenever a value inside global container is changed.
activeStackValueChanged = pyqtSignal() # Emitted whenever a value inside the active stack is changed.
activeStackValidationChanged = pyqtSignal() # Emitted whenever a validation inside active container is changed
stacksValidationChanged = pyqtSignal() # Emitted whenever a validation is changed
blurSettings = pyqtSignal() # Emitted to force fields in the advanced sidebar to un-focus, so they update properly
@ -246,9 +247,15 @@ class MachineManager(QObject):
quality.nameChanged.connect(self._onQualityNameChanged)
## Update self._stacks_valid according to _checkStacksForErrors and emit if change.
def _updateStacksHaveErrors(self):
old_stacks_have_errors = self._stacks_have_errors
self._stacks_have_errors = self._checkStacksHaveErrors()
if old_stacks_have_errors != self._stacks_have_errors:
self.stacksValidationChanged.emit()
def _onActiveExtruderStackChanged(self):
self.blurSettings.emit() # Ensure no-one has focus.
old_active_container_stack = self._active_container_stack
if self._active_container_stack and self._active_container_stack != self._global_container_stack:
@ -261,10 +268,7 @@ class MachineManager(QObject):
else:
self._active_container_stack = self._global_container_stack
old_active_stack_valid = self._active_stack_valid
self._active_stack_valid = not self._checkStackForErrors(self._active_container_stack)
if old_active_stack_valid != self._active_stack_valid:
self.activeStackValidationChanged.emit()
self._updateStacksHaveErrors()
if old_active_container_stack != self._active_container_stack:
# Many methods and properties related to the active quality actually depend
@ -287,18 +291,18 @@ class MachineManager(QObject):
self.activeStackValueChanged.emit()
if property_name == "validationState":
if self._active_stack_valid:
if not self._stacks_have_errors:
# fast update, we only have to look at the current changed property
if self._active_container_stack.getProperty(key, "settable_per_extruder"):
changed_validation_state = self._active_container_stack.getProperty(key, property_name)
else:
changed_validation_state = self._global_container_stack.getProperty(key, property_name)
if changed_validation_state in (UM.Settings.ValidatorState.Exception, UM.Settings.ValidatorState.MaximumError, UM.Settings.ValidatorState.MinimumError):
self._active_stack_valid = False
self.activeStackValidationChanged.emit()
self._stacks_have_errors = True
self.stacksValidationChanged.emit()
else:
if not self._checkStackForErrors(self._active_container_stack) and not self._checkStackForErrors(self._global_container_stack):
self._active_stack_valid = True
self.activeStackValidationChanged.emit()
# Normal check
self._updateStacksHaveErrors()
@pyqtSlot(str)
def setActiveMachine(self, stack_id):
@ -352,15 +356,17 @@ class MachineManager(QObject):
def _createUniqueName(self, container_type, current_name, new_name, fallback_name):
return UM.Settings.ContainerRegistry.getInstance().createUniqueName(container_type, current_name, new_name, fallback_name)
## Convenience function to check if a stack has errors.
def _checkStackForErrors(self, stack):
if stack is None:
return False
def _checkStacksHaveErrors(self):
if self._global_container_stack is not None and self._global_container_stack.hasErrors():
return True
for key in stack.getAllKeys():
validation_state = stack.getProperty(key, "validationState")
if validation_state in (UM.Settings.ValidatorState.Exception, UM.Settings.ValidatorState.MaximumError, UM.Settings.ValidatorState.MinimumError):
if self._global_container_stack is None:
return False
stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
for stack in stacks:
if stack.hasErrors():
return True
return False
## Remove all instances from the top instanceContainer (effectively removing all user-changed settings)
@ -420,12 +426,12 @@ class MachineManager(QObject):
for container in send_emits_containers:
container.sendPostponedEmits()
## Check if the global profile does not contain error states
# Note that the _active_stack_valid is cached due to performance issues
# Calling _checkStackForErrors on every change is simply too expensive
@pyqtProperty(bool, notify = activeStackValidationChanged)
def isActiveStackValid(self):
return bool(self._active_stack_valid)
## Check if none of the stacks contain error states
# Note that the _stacks_have_errors is cached due to performance issues
# Calling _checkStack(s)ForErrors on every change is simply too expensive
@pyqtProperty(bool, notify = stacksValidationChanged)
def stacksHaveErrors(self):
return bool(self._stacks_have_errors)
@pyqtProperty(str, notify = activeStackChanged)
def activeUserProfileId(self):

View File

@ -28,7 +28,7 @@ class MachineNameValidator(QObject):
# special character, and that up to [machine_name_max_length / 12] times.
maximum_special_characters = int(machine_name_max_length / 12)
unescaped = r"[a-zA-Z0-9_\-\.\/]"
self.machine_name_regex = r"((" + unescaped + "){0,12}|.){0," + str(maximum_special_characters) + r"}"
self.machine_name_regex = r"^((" + unescaped + "){0,12}|.){0," + str(maximum_special_characters) + r"}$"
validationChanged = pyqtSignal()
@ -56,14 +56,11 @@ class MachineNameValidator(QObject):
def updateValidation(self, new_name):
is_valid = self.validate(new_name, 0)
if is_valid == QValidator.Acceptable:
print("VALID")
self.validation_regex = "^.*$" #Matches anything.
else:
print("BROKEN!")
self.validation_regex = "a^" #Never matches (unless you manage to get "a" before the start of the string... good luck).
self.validationChanged.emit()
@pyqtProperty("QRegExp", notify=validationChanged)
def machineNameRegex(self):
print(self.machine_name_regex)
return QRegExp(self.machine_name_regex)

View File

@ -163,13 +163,15 @@ class SettingInheritanceManager(QObject):
for container in containers:
try:
value = container.getProperty(key, "value")
if value is not None:
has_setting_function = isinstance(value, UM.Settings.SettingFunction)
if has_setting_function is False:
has_non_function_value = True
continue
except AttributeError:
continue
if value is not None:
# If a setting doesn't use any keys, it won't change it's value, so treat it as if it's a fixed value
has_setting_function = isinstance(value, UM.Settings.SettingFunction) and len(value.getUsedSettingKeys()) > 0
if has_setting_function is False:
has_non_function_value = True
continue
if has_setting_function:
break # There is a setting function somewhere, stop looking deeper.
return has_setting_function and has_non_function_value

View File

@ -61,6 +61,12 @@ class SettingOverrideDecorator(SceneNodeDecorator):
def getActiveExtruder(self):
return self._extruder_stack
## Gets the signal that emits if the active extruder changed.
#
# This can then be accessed via a decorator.
def getActiveExtruderChangedSignal(self):
return self.activeExtruderChanged
## Gets the currently active extruders position
#
# \return An extruder's position, or None if no position info is available.

BIN
docs/Cura_Data_Model.odg Normal file

Binary file not shown.

View File

@ -10,7 +10,10 @@ from UM.Scene.SceneNode import SceneNode
from UM.Scene.GroupDecorator import GroupDecorator
import UM.Application
from UM.Job import Job
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
from UM.Application import Application
from cura.Settings.ExtruderManager import ExtruderManager
from cura.QualityManager import QualityManager
import os.path
import zipfile
@ -18,6 +21,7 @@ import zipfile
try:
import xml.etree.cElementTree as ET
except ImportError:
Logger.log("w", "Unable to load cElementTree, switching to slower version")
import xml.etree.ElementTree as ET
## Base implementation for reading 3MF files. Has no support for textures. Only loads meshes!
@ -55,6 +59,46 @@ class ThreeMFReader(MeshReader):
vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
Job.yieldThread()
xml_settings = list(object.findall(".//cura:setting", self._namespaces))
# Add the setting override decorator, so we can add settings to this node.
if xml_settings:
node.addDecorator(SettingOverrideDecorator())
global_container_stack = Application.getInstance().getGlobalContainerStack()
# Ensure the correct next container for the SettingOverride decorator is set.
if global_container_stack:
multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
# Ensure that all extruder data is reset
if not multi_extrusion:
default_stack_id = global_container_stack.getId()
else:
default_stack = ExtruderManager.getInstance().getExtruderStack(0)
if default_stack:
default_stack_id = default_stack.getId()
else:
default_stack_id = global_container_stack.getId()
node.callDecoration("setActiveExtruder", default_stack_id)
# Get the definition & set it
definition = QualityManager.getInstance().getParentMachineDefinition(global_container_stack.getBottom())
node.callDecoration("getStack").getTop().setDefinition(definition)
setting_container = node.callDecoration("getStack").getTop()
for setting in xml_settings:
setting_key = setting.get("key")
setting_value = setting.text
# Extruder_nr is a special case.
if setting_key == "extruder_nr":
extruder_stack = ExtruderManager.getInstance().getExtruderStack(int(setting_value))
if extruder_stack:
node.callDecoration("setActiveExtruder", extruder_stack.getId())
else:
Logger.log("w", "Unable to find extruder in position %s", setting_value)
continue
setting_container.setProperty(setting_key,"value", setting_value)
if len(node.getChildren()) > 0:
group_decorator = GroupDecorator()
node.addDecorator(group_decorator)
@ -112,7 +156,7 @@ class ThreeMFReader(MeshReader):
return temp_mat
def read(self, file_name):
result = SceneNode()
result = []
# The base object of 3mf is a zipped archive.
archive = zipfile.ZipFile(file_name, "r")
self._base_name = os.path.basename(file_name)
@ -125,33 +169,58 @@ class ThreeMFReader(MeshReader):
for build_item in build_items:
id = build_item.get("objectid")
object = self._root.find("./3mf:resources/3mf:object[@id='{0}']".format(id), self._namespaces)
if "type" in object.attrib:
if object.attrib["type"] == "support" or object.attrib["type"] == "other":
# Ignore support objects, as cura does not support these.
# We can't guarantee that they wont be made solid.
# We also ignore "other", as I have no idea what to do with them.
Logger.log("w", "3MF file contained an object of type %s which is not supported by Cura", object.attrib["type"])
continue
elif object.attrib["type"] == "solidsupport" or object.attrib["type"] == "model":
pass # Load these as normal
else:
# We should technically fail at this point because it's an invalid 3MF, but try to continue anyway.
Logger.log("e", "3MF file contained an object of type %s which is not supported by the 3mf spec",
object.attrib["type"])
continue
build_item_node = self._createNodeFromObject(object, self._base_name + "_" + str(id))
transform = build_item.get("transform")
if transform is not None:
build_item_node.setTransformation(self._createMatrixFromTransformationString(transform))
result.addChild(build_item_node)
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
# Create a transformation Matrix to convert from 3mf worldspace into ours.
# First step: flip the y and z axis.
transformation_matrix = Matrix()
transformation_matrix._data[1, 1] = 0
transformation_matrix._data[1, 2] = 1
transformation_matrix._data[2, 1] = -1
transformation_matrix._data[2, 2] = 0
# Second step: 3MF defines the left corner of the machine as center, whereas cura uses the center of the
# build volume.
if global_container_stack:
translation_vector = Vector(x = -global_container_stack.getProperty("machine_width", "value") / 2,
y = -global_container_stack.getProperty("machine_depth", "value") / 2,
z = 0)
translation_matrix = Matrix()
translation_matrix.setByTranslation(translation_vector)
transformation_matrix.multiply(translation_matrix)
# Third step: 3MF also defines a unit, wheras Cura always assumes mm.
scale_matrix = Matrix()
scale_matrix.setByScaleVector(self._getScaleFromUnit(self._unit))
transformation_matrix.multiply(scale_matrix)
# Pre multiply the transformation with the loaded transformation, so the data is handled correctly.
build_item_node.setTransformation(build_item_node.getLocalTransformation().preMultiply(transformation_matrix))
result.append(build_item_node)
except Exception as e:
Logger.log("e", "exception occured in 3mf reader: %s", e)
try: # Selftest - There might be more functions that should fail
bounding_box = result.getBoundingBox()
bounding_box.isValid()
except:
return None
Logger.log("e", "An exception occurred in 3mf reader: %s", e)
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
flip_matrix = Matrix()
flip_matrix._data[1, 1] = 0
flip_matrix._data[1, 2] = 1
flip_matrix._data[2, 1] = -1
flip_matrix._data[2, 2] = 0
result.setTransformation(flip_matrix)
if global_container_stack:
translation = Vector(x=-global_container_stack.getProperty("machine_width", "value") / 2, z=0,
y=-global_container_stack.getProperty("machine_depth", "value") / 2)
result.translate(translation)
result.scale(self._getScaleFromUnit(self._unit))
result.setEnabled(False) # The result should not be moved in any way, so disable it.
return result
## Create a scale vector based on a unit string.

View File

@ -1,14 +1,14 @@
[2.3.1]
*Layer Height in Profile Selection
The layer height of each profile is now shown in the profile selection menu.
Added the layer height to the profile selection menu.
*Bug fixes
Editing material settings has actual effect on the prints again
Upgrading from version 2.1 on OSX works again
You can import g-code from related machines as profile
Fixed inheritance taking from the wrong extruder
The i-symbol is updated properly
Fixed a freeze that could sometimes occur while printing via Wi-Fi
Fixed the option to import g-code from related machines as a profile
Fixed a bug where editing material settings has no effect on 3D prints
Fixed an issue with automatic profile importing on Cura 2.1 on Mac OSX
Fixed an inheritance issue for dual extrusion
Fixed an issue with "i" symbol updates
Fixed a freeze that can occur while printing via Wi-Fi
[2.3.0]
*Multi Extrusion Support

View File

@ -220,6 +220,9 @@ class CuraEngineBackend(Backend):
#
# \param job The start slice job that was just finished.
def _onStartSliceCompleted(self, job):
if self._error_message:
self._error_message.hide()
# Note that cancelled slice jobs can still call this method.
if self._start_slice_job is job:
self._start_slice_job = None
@ -239,13 +242,33 @@ class CuraEngineBackend(Backend):
if job.getResult() == StartSliceJob.StartJobResult.SettingError:
if Application.getInstance().getPlatformActivity:
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. Please check your settings for errors."))
extruders = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
error_keys = []
for extruder in extruders:
error_keys.extend(extruder.getErrorKeys())
if not extruders:
error_keys = self._global_container_stack.getErrorKeys()
error_labels = set()
definition_container = self._global_container_stack.getBottom()
for key in error_keys:
error_labels.add(definition_container.findDefinitions(key = key)[0].label)
error_labels = ", ".join(error_labels)
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. The following settings have errors: {0}".format(error_labels)))
self._error_message.show()
self.backendStateChange.emit(BackendState.Error)
else:
self.backendStateChange.emit(BackendState.NotStarted)
return
if job.getResult() == StartSliceJob.StartJobResult.BuildPlateError:
if Application.getInstance().getPlatformActivity:
self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice because the prime tower or prime position(s) are invalid."))
self._error_message.show()
self.backendStateChange.emit(BackendState.Error)
else:
self.backendStateChange.emit(BackendState.NotStarted)
if job.getResult() == StartSliceJob.StartJobResult.NothingToSlice:
if Application.getInstance().getPlatformActivity:
self._error_message = Message(catalog.i18nc("@info:status", "Nothing to slice because none of the models fit the build volume. Please scale or rotate models to fit."))
@ -296,7 +319,7 @@ class CuraEngineBackend(Backend):
self._terminate()
if error.getErrorCode() not in [Arcus.ErrorCode.BindFailedError, Arcus.ErrorCode.ConnectionResetError, Arcus.ErrorCode.Debug]:
Logger.log("e", "A socket error caused the connection to be reset")
Logger.log("w", "A socket error caused the connection to be reset")
## A setting has changed, so check if we must reslice.
#

View File

@ -25,6 +25,7 @@ class StartJobResult(IntEnum):
SettingError = 3
NothingToSlice = 4
MaterialIncompatible = 5
BuildPlateError = 6
## Formatter class that handles token expansion in start/end gcod
@ -75,12 +76,12 @@ class StartSliceJob(Job):
return
# Don't slice if there is a setting with an error value.
if not Application.getInstance().getMachineManager().isActiveStackValid:
if Application.getInstance().getMachineManager().stacksHaveErrors:
self.setResult(StartJobResult.SettingError)
return
if Application.getInstance().getBuildVolume().hasErrors():
self.setResult(StartJobResult.SettingError)
self.setResult(StartJobResult.BuildPlateError)
return
for extruder_stack in cura.Settings.ExtruderManager.getInstance().getMachineExtruders(stack.getId()):
@ -164,7 +165,12 @@ class StartSliceJob(Job):
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.
verts = numpy.array([verts[vert_index] for face in indices for vert_index in face])
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)
else:
verts = numpy.array(verts)
@ -238,6 +244,7 @@ class StartSliceJob(Job):
else:
# Normal case
settings[key] = stack.getProperty(key, "value")
Job.yieldThread()
start_gcode = settings["machine_start_gcode"]
settings["material_bed_temp_prepend"] = "{material_bed_temperature}" not in start_gcode #Pre-compute material material_bed_temp_prepend and material_print_temp_prepend
@ -250,6 +257,7 @@ class StartSliceJob(Job):
setting_message.value = self._expandGcodeTokens(key, value, settings)
else:
setting_message.value = str(value).encode("utf-8")
Job.yieldThread()
## Sends for some settings which extruder they should fallback to if not
# set.
@ -266,6 +274,7 @@ class StartSliceJob(Job):
setting_extruder = self._slice_message.addRepeatedMessage("limit_to_extruder")
setting_extruder.name = key
setting_extruder.extruder = extruder
Job.yieldThread()
## Check if a node has per object settings and ensure that they are set correctly in the message
# \param node \type{SceneNode} Node to check.

View File

@ -99,4 +99,6 @@ class CuraProfileReader(ProfileReader):
return []
filenames, outputs = profile_convert_funcs[0](serialized, profile_id)
if filenames is None and outputs is None:
return []
return list(zip(outputs, filenames))

View File

@ -70,10 +70,19 @@ class GCodeProfileReader(ProfileReader):
json_data = json.loads(serialized)
profile_strings = [json_data["global_quality"]]
profile_strings.extend(json_data.get("extruder_quality", []))
profiles = []
global_profile = readQualityProfileFromString(json_data["global_quality"])
return [readQualityProfileFromString(profile_string) for profile_string in profile_strings]
# This is a fix for profiles created with 2.3.0 For some reason it added the "extruder" property to the
# global profile.
# The fix is simple and safe, as a global profile should never have the extruder entry.
if global_profile.getMetaDataEntry("extruder", None) is not None:
global_profile.setMetaDataEntry("extruder", None)
profiles.append(global_profile)
for profile_string in json_data.get("extruder_quality", []):
profiles.append(readQualityProfileFromString(profile_string))
return profiles
## Unescape a string which has been escaped for use in a gcode comment.
#

View File

@ -401,7 +401,7 @@ Item {
}
visibilityHandler: UM.SettingPreferenceVisibilityHandler {}
expanded: [ "*" ]
exclude: [ "machine_settings" ]
exclude: [ "machine_settings", "command_line_settings" ]
}
delegate:Loader
{

View File

@ -22,6 +22,7 @@ class PerObjectSettingsTool(Tool):
self._advanced_mode = False
self._multi_extrusion = False
self._single_model_selected = False
Selection.selectionChanged.connect(self.propertyChanged)
@ -30,6 +31,8 @@ class PerObjectSettingsTool(Tool):
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
self._onGlobalContainerChanged()
Selection.selectionChanged.connect(self._updateEnabled)
def event(self, event):
super().event(event)
@ -102,4 +105,11 @@ class PerObjectSettingsTool(Tool):
self._updateEnabled()
def _updateEnabled(self):
Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, self._advanced_mode or self._multi_extrusion)
selected_objects = Selection.getAllSelectedObjects()
if len(selected_objects)> 1:
self._single_model_selected = False
elif len(selected_objects) == 1 and selected_objects[0].callDecoration("isGroup"):
self._single_model_selected = False # Group is selected, so tool needs to be disabled
else:
self._single_model_selected = True
Application.getInstance().getController().toolEnabledChanged.emit(self._plugin_id, (self._advanced_mode or self._multi_extrusion) and self._single_model_selected)

View File

@ -20,7 +20,7 @@ class RemovableDriveOutputDevice(OutputDevice):
super().__init__(device_id)
self.setName(device_name)
self.setShortDescription(catalog.i18nc("@action:button", "Save to Removable Drive"))
self.setShortDescription(catalog.i18nc("@action:button Preceded by 'Ready to'.", "Save to Removable Drive"))
self.setDescription(catalog.i18nc("@item:inlistbox", "Save to Removable Drive {0}").format(device_name))
self.setIconName("save_sd")
self.setPriority(1)

View File

@ -19,13 +19,12 @@ from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal, pyqtProperty
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
class USBPrinterOutputDevice(PrinterOutputDevice):
def __init__(self, serial_port):
super().__init__(serial_port)
self.setName(catalog.i18nc("@item:inmenu", "USB printing"))
self.setShortDescription(catalog.i18nc("@action:button", "Print via USB"))
self.setShortDescription(catalog.i18nc("@action:button Preceded by 'Ready to'.", "Print via USB"))
self.setDescription(catalog.i18nc("@info:tooltip", "Print via USB"))
self.setIconName("print")
self.setConnectionText(catalog.i18nc("@info:status", "Connected via USB"))

View File

@ -5,6 +5,7 @@ See: http://en.wikipedia.org/wiki/Intel_HEX
This is a python 3 conversion of the code created by David Braam for the Cura project.
"""
import io
from UM.Logger import Logger
def readHex(filename):
"""
@ -41,6 +42,6 @@ def readHex(filename):
elif rec_type == 2: #Extended Segment Address Record
extra_addr = int(line[9:13], 16) * 16
else:
print(rec_type, rec_len, addr, check_sum, line)
Logger.log("d", "%s, %s, %s, %s, %s", rec_type, rec_len, addr, check_sum, line)
f.close()
return data

View File

@ -8,6 +8,7 @@ The ISP AVR programmer can load firmware into AVR chips. Which are commonly used
"""
from . import chipDB
from UM.Logger import Logger
class IspBase():
"""
@ -22,11 +23,11 @@ class IspBase():
raise IspError("Chip with signature: " + str(self.getSignature()) + "not found")
self.chipErase()
print("Flashing %i bytes" % len(flash_data))
Logger.log("d", "Flashing %i bytes", len(flash_data))
self.writeFlash(flash_data)
print("Verifying %i bytes" % len(flash_data))
Logger.log("d", "Verifying %i bytes", len(flash_data))
self.verifyFlash(flash_data)
print("Completed")
Logger.log("d", "Completed")
def getSignature(self):
"""

View File

@ -3,7 +3,6 @@ STK500v2 protocol implementation for programming AVR chips.
The STK500v2 protocol is used by the ArduinoMega2560 and a few other Arduino platforms to load firmware.
This is a python 3 conversion of the code created by David Braam for the Cura project.
"""
import os
import struct
import sys
import time
@ -11,6 +10,7 @@ import time
from serial import Serial
from serial import SerialException
from serial import SerialTimeoutException
from UM.Logger import Logger
from . import ispBase, intelHex
@ -27,7 +27,7 @@ class Stk500v2(ispBase.IspBase):
self.close()
try:
self.serial = Serial(str(port), speed, timeout=1, writeTimeout=10000)
except SerialException as e:
except SerialException:
raise ispBase.IspError("Failed to open serial port")
except:
raise ispBase.IspError("Unexpected error while connecting to serial port:" + port + ":" + str(sys.exc_info()[0]))
@ -84,14 +84,14 @@ class Stk500v2(ispBase.IspBase):
#Set load addr to 0, in case we have more then 64k flash we need to enable the address extension
page_size = self.chip["pageSize"] * 2
flash_size = page_size * self.chip["pageCount"]
print("Writing flash")
Logger.log("d", "Writing flash")
if flash_size > 0xFFFF:
self.sendMessage([0x06, 0x80, 0x00, 0x00, 0x00])
else:
self.sendMessage([0x06, 0x00, 0x00, 0x00, 0x00])
load_count = (len(flash_data) + page_size - 1) / page_size
for i in range(0, int(load_count)):
recv = self.sendMessage([0x13, page_size >> 8, page_size & 0xFF, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flash_data[(i * page_size):(i * page_size + page_size)])
self.sendMessage([0x13, page_size >> 8, page_size & 0xFF, 0xc1, 0x0a, 0x40, 0x4c, 0x20, 0x00, 0x00] + flash_data[(i * page_size):(i * page_size + page_size)])
if self.progress_callback is not None:
if self._has_checksum:
self.progress_callback(i + 1, load_count)
@ -151,7 +151,6 @@ class Stk500v2(ispBase.IspBase):
raise ispBase.IspError("Timeout")
b = struct.unpack(">B", s)[0]
checksum ^= b
#print(hex(b))
if state == "Start":
if b == 0x1B:
state = "GetSeq"
@ -183,11 +182,11 @@ class Stk500v2(ispBase.IspBase):
def portList():
ret = []
import _winreg
key=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"HARDWARE\\DEVICEMAP\\SERIALCOMM")
key=_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,"HARDWARE\\DEVICEMAP\\SERIALCOMM") #@UndefinedVariable
i=0
while True:
try:
values = _winreg.EnumValue(key, i)
values = _winreg.EnumValue(key, i) #@UndefinedVariable
except:
return ret
if "USBSER" in values[0]:
@ -206,7 +205,7 @@ def main():
""" Entry point to call the stk500v2 programmer from the commandline. """
import threading
if sys.argv[1] == "AUTO":
print(portList())
Logger.log("d", "portList(): ", repr(portList()))
for port in portList():
threading.Thread(target=runProgrammer, args=(port,sys.argv[2])).start()
time.sleep(5)

View File

@ -5,6 +5,7 @@ import configparser #To read config files.
import io #To write config files to strings as if they were files.
import UM.VersionUpgrade
from UM.Logger import Logger
## Creates a new profile instance by parsing a serialised profile in version 1
# of the file format.

View File

@ -165,7 +165,7 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
machine_container_map = {}
machine_nozzle_map = {}
all_containers = registry.findInstanceContainers(GUID = self.getMetaDataEntry("GUID"))
all_containers = registry.findInstanceContainers(GUID = self.getMetaDataEntry("GUID"), base_file = self._id)
for container in all_containers:
definition_id = container.getDefinition().id
if definition_id == "fdmprinter":
@ -209,7 +209,17 @@ class XmlMaterialProfile(UM.Settings.InstanceContainer):
if not variant_containers:
continue
builder.start("hotend", { "id": variant_containers[0].getName() })
builder.start("hotend", {"id": variant_containers[0].getName()})
# Compatible is a special case, as it's added as a meta data entry (instead of an instance).
compatible = hotend.getMetaDataEntry("compatible")
if compatible is not None:
builder.start("setting", {"key": "hardware compatible"})
if compatible:
builder.data("yes")
else:
builder.data("no")
builder.end("setting")
for instance in hotend.findInstances():
if container.getInstance(instance.definition.key) and container.getProperty(instance.definition.key, "value") == instance.value:

View File

@ -0,0 +1,40 @@
{
"id": "bfb",
"name": "BFB",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "BFB",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"speed_topbottom": { "default_value": 40 },
"speed_print": { "default_value": 40 },
"machine_extruder_count": { "default_value": 1 },
"prime_tower_size": { "default_value": 7.745966692414834 },
"machine_name": { "default_value": "BFB_Test" },
"machine_heated_bed": { "default_value": false },
"machine_nozzle_size": { "default_value": 0.5 },
"speed_layer_0": { "default_value": 25 },
"machine_width": { "default_value": 275 },
"machine_gcode_flavor": { "default_value": "BFB" },
"machine_depth": { "default_value": 265 },
"speed_infill": { "default_value": 30 },
"material_diameter": { "default_value": 1.7 },
"machine_center_is_zero": { "default_value": true },
"machine_height": { "default_value": 240 },
"layer_height": { "default_value": 0.25 },
"material_print_temperature": { "default_value": 200 },
"retraction_amount": { "default_value": 0.05 },
"speed_wall_0": { "default_value": 25 },
"speed_travel": { "default_value": 50 },
"infill_sparse_density": { "default_value": 10 },
"layer_height_0": { "default_value": 0.5 },
"speed_wall_x": { "default_value": 20 }
}
}

View File

@ -0,0 +1,35 @@
{
"id": "deltabot",
"name": "DeltaBot",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Danny Lu",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"speed_travel": { "default_value": 150 },
"prime_tower_size": { "default_value": 8.660254037844387 },
"infill_sparse_density": { "default_value": 10 },
"speed_wall_x": { "default_value": 30 },
"speed_wall_0": { "default_value": 30 },
"speed_topbottom": { "default_value": 30 },
"layer_height": { "default_value": 0.2 },
"machine_nozzle_size": { "default_value": 0.5 },
"speed_print": { "default_value": 30 },
"speed_infill": { "default_value": 30 },
"machine_extruder_count": { "default_value": 1 },
"machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": true },
"machine_height": { "default_value": 150 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 150 },
"machine_width": { "default_value": 150 },
"machine_name": { "default_value": "DeltaBot style" }
}
}

View File

@ -169,7 +169,7 @@
},
"machine_extruder_count":
{
"label": "Number extruders",
"label": "Number of Extruders",
"description": "Number of extruder trains. An extruder train is the combination of a feeder, bowden tube, and nozzle.",
"default_value": 1,
"minimum_value": "1",
@ -283,6 +283,18 @@
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"nozzle_disallowed_areas":
{
"label": "Nozzle Disallowed Areas",
"description": "A list of polygons with areas the nozzle is not allowed to enter.",
"type": "polygons",
"default_value":
[
],
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"machine_head_polygon":
{
"label": "Machine head polygon",
@ -756,6 +768,18 @@
}
}
},
"wall_0_wipe_dist":
{
"label": "Outer Wall Wipe Distance",
"description": "Distance of a travel move inserted after the outer wall, to hide the Z seam better.",
"unit": "mm",
"type": "float",
"default_value": 0.2,
"value": "machine_nozzle_size / 2",
"minimum_value": "0",
"maximum_value_warning": "machine_nozzle_size",
"settable_per_mesh": true
},
"top_bottom_thickness":
{
"label": "Top/Bottom Thickness",
@ -897,6 +921,17 @@
}
}
},
"fill_perimeter_gaps": {
"label": "Fill Gaps Between Walls",
"description": "Fills the gaps between walls where no walls fit.",
"type": "enum",
"options": {
"nowhere": "Nowhere",
"everywhere": "Everywhere"
},
"default_value": "everywhere",
"settable_per_mesh": true
},
"xy_offset":
{
"label": "Horizontal Expansion",
@ -979,6 +1014,7 @@
"cubic": "Cubic",
"tetrahedral": "Tetrahedral",
"concentric": "Concentric",
"concentric_3d": "Concentric 3D",
"zigzag": "Zig Zag"
},
"default_value": "grid",
@ -1135,7 +1171,22 @@
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"maximum_value_warning": "260",
"enabled": "not (material_flow_dependent_temperature)",
"enabled": "not (material_flow_dependent_temperature) and machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": true
},
"material_print_temperature_layer_0":
{
"label": "Printing Temperature Initial Layer",
"description": "The temperature used for printing the first layer. Set at 0 to disable special handling of the initial layer.",
"unit": "°C",
"type": "float",
"default_value": 215,
"value": "material_print_temperature + 5",
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"maximum_value_warning": "260",
"enabled": "machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1176,7 +1227,23 @@
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"maximum_value_warning": "260",
"enabled": "machine_heated_bed",
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"material_bed_temperature_layer_0":
{
"label": "Build Plate Temperature Initial Layer",
"description": "The temperature used for the heated build plate at the first layer.",
"unit": "°C",
"type": "float",
"resolve": "max(extruderValues('material_bed_temperature_layer_0'))",
"default_value": 60,
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"maximum_value_warning": "260",
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
@ -1191,6 +1258,7 @@
"minimum_value": "0.0001",
"minimum_value_warning": "0.4",
"maximum_value_warning": "3.5",
"enabled": "machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1204,6 +1272,7 @@
"minimum_value": "5",
"minimum_value_warning": "50",
"maximum_value_warning": "150",
"enabled": "machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": true
},
"retraction_enable":
@ -1215,6 +1284,14 @@
"settable_per_mesh": false,
"settable_per_extruder": true
},
"retract_at_layer_change":{
"label": "Retract at Layer Change",
"description": "Retract the filament when the nozzle is moving to the next layer.",
"type": "bool",
"default_value": false,
"settable_per_mesh": false,
"settable_per_extruder": true
},
"retraction_amount":
{
"label": "Retraction Distance",
@ -1224,7 +1301,7 @@
"default_value": 6.5,
"minimum_value_warning": "-0.0001",
"maximum_value_warning": "10.0",
"enabled": "retraction_enable",
"enabled": "retraction_enable and machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1239,7 +1316,7 @@
"minimum_value_warning": "1",
"maximum_value": "machine_max_feedrate_e",
"maximum_value_warning": "70",
"enabled": "retraction_enable",
"enabled": "retraction_enable and machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": true,
"children":
@ -1255,7 +1332,7 @@
"maximum_value": "machine_max_feedrate_e",
"minimum_value_warning": "1",
"maximum_value_warning": "70",
"enabled": "retraction_enable",
"enabled": "retraction_enable and machine_gcode_flavor != \"UltiGCode\"",
"value": "retraction_speed",
"settable_per_mesh": false,
"settable_per_extruder": true
@ -1271,7 +1348,7 @@
"maximum_value": "machine_max_feedrate_e",
"minimum_value_warning": "1",
"maximum_value_warning": "70",
"enabled": "retraction_enable",
"enabled": "retraction_enable and machine_gcode_flavor != \"UltiGCode\"",
"value": "retraction_speed",
"settable_per_mesh": false,
"settable_per_extruder": true
@ -1341,6 +1418,7 @@
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"maximum_value_warning": "260",
"enabled": "machine_extruder_count > 1 and machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -2179,7 +2257,7 @@
"retraction_combing":
{
"label": "Combing Mode",
"description": "Combing keeps the nozzle within already printed areas when traveling. This results in slightly longer travel moves but reduces the need for retractions. If combing is off, the material will retract and the nozzle moves in a straight line to the next point. It is also possible to avoid combing over top/bottom skin areas by combing within the infill only. It is also possible to avoid combing over top/bottom skin areas by combing within the infill only.",
"description": "Combing keeps the nozzle within already printed areas when traveling. This results in slightly longer travel moves but reduces the need for retractions. If combing is off, the material will retract and the nozzle moves in a straight line to the next point. It is also possible to avoid combing over top/bottom skin areas by combing within the infill only.",
"type": "enum",
"options":
{
@ -2217,6 +2295,42 @@
"settable_per_mesh": false,
"settable_per_extruder": true
},
"start_layers_at_same_position":
{
"label": "Start Layers Near Same Point",
"description": "Start printing the objects in each layer near the same point, so that we don't start a new layer with printing the piece which the previous layer ended with. This makes for better overhangs and small parts, but increases printing time.",
"type": "bool",
"default_value": false,
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": true
},
"layer_start_x":
{
"label": "Layer Start X",
"description": "The X coordinate of the position near where to start printing objects each layer.",
"unit": "mm",
"type": "float",
"default_value": 0.0,
"minimum_value": "0",
"enabled": "start_layers_at_same_position",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": true
},
"layer_start_y":
{
"label": "Layer Start Y",
"description": "The Y coordinate of the position near where to start printing objects each layer.",
"unit": "mm",
"type": "float",
"default_value": 0.0,
"minimum_value": "0",
"enabled": "start_layers_at_same_position",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": true
},
"retraction_hop_enabled": {
"label": "Z Hop when Retracted",
"description": "Whenever a retraction is done, the build plate is lowered to create clearance between the nozzle and the print. It prevents the nozzle from hitting the print during travel moves, reducing the chance to knock the print from the build plate.",
@ -2290,6 +2404,20 @@
"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",
@ -2335,7 +2463,7 @@
"cool_fan_full_at_height":
{
"label": "Regular Fan Speed at Height",
"description": "The height at which the fans spin on regular fan speed. At the layers below the fan speed gradually increases from zero to regular fan speed.",
"description": "The height at which the fans spin on regular fan speed. At the layers below the fan speed gradually increases from Initial Fan Speed to Regular Fan Speed.",
"unit": "mm",
"type": "float",
"default_value": 0.5,
@ -2498,6 +2626,7 @@
"grid": "Grid",
"triangles": "Triangles",
"concentric": "Concentric",
"concentric_3d": "Concentric 3D",
"zigzag": "Zig Zag"
},
"default_value": "zigzag",
@ -2767,7 +2896,7 @@
"type": "float",
"default_value": 0.4,
"minimum_value": "0",
"minimum_value_warning": "support_interface_line_width",
"minimum_value_warning": "support_interface_line_width - 0.0001",
"value": "0 if support_interface_density == 0 else (support_interface_line_width * 100) / support_interface_density * (2 if support_interface_pattern == 'grid' else (3 if support_interface_pattern == 'triangles' else 1))",
"limit_to_extruder": "support_interface_extruder_nr",
"enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
@ -2787,6 +2916,7 @@
"grid": "Grid",
"triangles": "Triangles",
"concentric": "Concentric",
"concentric_3d": "Concentric 3D",
"zigzag": "Zig Zag"
},
"default_value": "concentric",
@ -2892,7 +3022,8 @@
{
"skirt": "Skirt",
"brim": "Brim",
"raft": "Raft"
"raft": "Raft",
"none": "None"
},
"default_value": "brim",
"resolve": "'raft' if 'raft' in extruderValues('adhesion_type') else ('brim' if 'brim' in extruderValues('adhesion_type') else 'skirt')",
@ -2905,7 +3036,7 @@
"description": "The extruder train to use for printing the skirt/brim/raft. This is used in multi-extrusion.",
"type": "extruder",
"default_value": "0",
"enabled": "machine_extruder_count > 1",
"enabled": "machine_extruder_count > 1 and resolveOrValue('adhesion_type') != 'none'",
"settable_per_mesh": false,
"settable_per_extruder": false
},
@ -3635,13 +3766,24 @@
"carve_multiple_volumes":
{
"label": "Remove Mesh Intersection",
"description": "Remove areas where multiple objecs are overlapping with each other. This is may be used if merged dual material objects overlap with each other.",
"description": "Remove areas where multiple objects are overlapping with each other. This may be used if merged dual material objects overlap with each other.",
"type": "bool",
"default_value": true,
"value": "machine_extruder_count > 1",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": true
},
"alternate_carve_order":
{
"label": "Alternate Mesh Removal",
"description": "With every layer switch from which model intersecting volumes are removed, so that the overlapping volumes become interwoven.",
"type": "bool",
"default_value": true,
"enabled": "carve_multiple_volumes",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": true
}
}
},
@ -3664,6 +3806,7 @@
"one_at_a_time": "One at a Time"
},
"default_value": "all_at_once",
"enabled": "machine_extruder_count == 1",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
@ -3902,6 +4045,14 @@
"limit_to_extruder": "support_infill_extruder_nr",
"settable_per_mesh": true
},
"infill_hollow":
{
"label": "Hollow Out Objects",
"description": "Remove all infill and make the inside of the object eligible for support.",
"type": "bool",
"default_value": false,
"settable_per_mesh": true
},
"magic_fuzzy_skin_enabled":
{
"label": "Fuzzy Skin",
@ -4309,6 +4460,49 @@
"settable_per_meshgroup": false
}
}
},
"command_line_settings": {
"label": "Command Line Settings",
"description": "Settings which are only used if CuraEngine isn't called from the Cura frontend.",
"type": "category",
"enabled": false,
"children": {
"center_object": {
"description": "Whether to center the object on the middle of the build platform (0,0), instead of using the coordinate system in which the object was saved.",
"type": "bool",
"label": "Center object",
"default_value": false,
"enabled": false
},
"mesh_position_x": {
"description": "Offset applied to the object in the x direction.",
"type": "float",
"label": "Mesh position x",
"default_value": 0,
"enabled": false
},
"mesh_position_y": {
"description": "Offset applied to the object in the y direction.",
"type": "float",
"label": "Mesh position y",
"default_value": 0,
"enabled": false
},
"mesh_position_z": {
"description": "Offset applied to the object in the z direction. With this you can perform what was used to be called 'Object Sink'.",
"type": "float",
"label": "Mesh position z",
"default_value": 0,
"enabled": false
},
"mesh_rotation_matrix": {
"label": "Mesh Rotation Matrix",
"description": "Transformation matrix to be applied to the model when loading it from file.",
"type": "str",
"default_value": "[[1,0,0], [0,1,0], [0,0,1]]",
"enabled": false
}
}
}
}
}

View File

@ -54,7 +54,7 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G28 ; Home extruder\nM107 ; Turn off fan\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\n{IF_BED}M190 S{BED}\n{IF_EXT0}M104 T0 S{TEMP0}\n{IF_EXT0}M109 T0 S{TEMP0}\n{IF_EXT1}M104 T1 S{TEMP1}\n{IF_EXT1}M109 T1 S{TEMP1}\nG32 S3 ; auto level\nG92 E0 ; Reset extruder position"
"default_value": "G28 ; Home extruder\nM107 ; Turn off fan\nG90 ; Absolute positioning\nM82 ; Extruder in absolute mode\nM190 S{material_bed_temperature}\nM104 T0 S{material_print_temperature}\nM109 T0 S{material_print_temperature}\nM104 T1 S{material_print_temperature}\nM109 T1 S{material_print_temperature}\nG32 S3 ; auto level\nG92 E0 ; Reset extruder position"
},
"machine_end_gcode": {
"default_value": "M104 S0 ; turn off extruders\nM140 S0 ; heated bed heater off\nG91 ; relative positioning\nG1 E-2 F5000; retract 2mm\nG28 Z; move bed down\nG90 ; absolute positioning\nM84 ; disable motors"

View File

@ -0,0 +1,52 @@
{
"id": "julia",
"name": "Julia",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Fracktal",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"machine_start_gcode": {
"default_value": " ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_sparse_density}\n ;metric values\n M107\n G28\n G29\n G90 ;absolute positioning\n G92 E0; reset extruder distance\n G1 Z5 F300 ;move nozzle up 5mm for safe homing\n G1 X0 Y0 Z0 F5000; move nozzle to home\n M300 S600P200\n M300 S800 P200\n M190 S{material_bed_temperature} ;Uncomment to add your own bed temperature line\n M109 S{material_print_temperature} ;Uncomment to add your own temperature line\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G1 Z15.0 F{speed_travel} ;move the platform down 15mm\n G92 E0 ;zero the extruded length\n G1 F200 E3 ;extrude 3mm of feed stock\n G92 E0 ;zero the extruded length again\n G1 F{speed_travel}\n ;Put printing message on LCD screen\n M117 Printing...\n"
},
"machine_end_gcode": {
"default_value": " M104 S0 ;extruder heater off\n M140 S0 ;heated bed heater off (if you have it)\n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning\n"
},
"material_bed_temperature": { "default_value": 100 },
"layer_height": { "default_value": 0.2 },
"support_angle": { "default_value": 30 },
"infill_overlap": { "default_value": 30 },
"layer_height_0": { "default_value": 0.2 },
"speed_print": { "default_value": 80 },
"speed_wall_0": { "default_value": 30 },
"speed_travel": { "default_value": 150 },
"brim_line_count": { "default_value": 15 },
"skin_overlap": { "default_value": 30 },
"prime_tower_size": { "default_value": 8.660254037844387 },
"material_diameter": { "default_value": 1.75 },
"bottom_thickness": { "default_value": 0.8 },
"retraction_amount": { "default_value": 3 },
"speed_topbottom": { "default_value": 80 },
"material_print_temperature": { "default_value": 230 },
"support_pattern": { "default_value": "grid" },
"speed_infill": { "default_value": 80 },
"infill_sparse_density": { "default_value": 10 },
"top_thickness": { "default_value": 0.8 },
"machine_extruder_count": { "default_value": 1 },
"retraction_combing": { "default_value": "off" },
"machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 260 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 250 },
"machine_width": { "default_value": 210 },
"machine_name": { "default_value": "Julia V2" }
}
}

View File

@ -0,0 +1,38 @@
{
"id": "kupido",
"name": "Kupido",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Kupido",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"machine_name": { "default_value": "Kupido" },
"machine_start_gcode": {
"default_value": " ;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_sparse_density}\n ;M190 S{material_bed_temperature} ;Uncomment to add your own bed temperature line\n ;M109 S{material_print_temperature} ;Uncomment to add your own temperature line\n G21 ;metric values\n G90 ;absolute positioning\n M82 ;set extruder to absolute mode\n M107 ;start with the fan off\n G28 X0 Y0 ;move X Y to endstops\n G28 Z0 ;move Z to endstops\n G1 Z20.0 F40 ;move the platform down 20mm\n G1 Y0 X170 F{speed_travel}\n G92 E0 ;zero the extruded length\n G1 F200 E10 ;extrude 3mm of feed stock\n G92 E0 ;zero the extruded length again\n G4 P7000\n G1 F{speed_travel}\n ;Put printing message on LCD screen\n M117 Printing...\n"
},
"machine_end_gcode": {
"default_value": " M104 S0 ;extruder heater off\n M140 S0 ;heated bed heater off (if you have it)\n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning\n"
},
"prime_tower_size": { "default_value": 8.660254037844387 },
"retraction_speed": { "default_value": 60 },
"material_bed_temperature": { "default_value": 60 },
"speed_wall_x": { "default_value": 40 },
"skirt_line_count": { "default_value": 2 },
"retraction_min_travel": { "default_value": 2 },
"speed_wall_0": { "default_value": 30 },
"material_print_temperature": { "default_value": 220 },
"brim_line_count": { "default_value": 15 },
"retraction_amount": { "default_value": 3.6 },
"speed_topbottom": { "default_value": 20 },
"layer_height": { "default_value": 0.2 },
"speed_print": { "default_value": 30 },
"speed_infill": { "default_value": 30 }
}
}

View File

@ -0,0 +1,31 @@
{
"id": "makerbotreplicator",
"name": "MakerBotReplicator",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "MakerBot",
"category": "Other",
"file_formats": "application/x3g",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"prime_tower_size": { "default_value": 10.0 },
"infill_sparse_density": { "default_value": 10 },
"speed_travel": { "default_value": 150 },
"material_diameter": { "default_value": 1.75 },
"layer_height": { "default_value": 0.15 },
"material_print_temperature": { "default_value": 220 },
"machine_extruder_count": { "default_value": 1 },
"machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 150 },
"machine_gcode_flavor": { "default_value": "MakerBot" },
"machine_depth": { "default_value": 145 },
"machine_width": { "default_value": 225 },
"machine_name": { "default_value": "MakerBot Replicator" }
}
}

View File

@ -0,0 +1,41 @@
{
"id": "ord",
"name": "RoVa3D",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "ORD Solutions",
"category": "Other",
"file_formats": "text/x-gcode",
"machine_extruder_trains":
{
"0": "ord_extruder_0",
"1": "ord_extruder_1",
"2": "ord_extruder_2",
"3": "ord_extruder_3",
"4": "ord_extruder_4"
},
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"material_bed_temperature": { "default_value": 60 },
"prime_tower_size": { "default_value": 7.0710678118654755 },
"infill_sparse_density": { "default_value": 15 },
"speed_travel": { "default_value": 150 },
"material_diameter": { "default_value": 1.75 },
"layer_height": { "default_value": 0.3 },
"machine_nozzle_size": { "default_value": 0.35 },
"material_print_temperature": { "default_value": 240 },
"machine_extruder_count": { "default_value": 5 },
"machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 200 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 250 },
"machine_width": { "default_value": 215 },
"machine_name": { "default_value": "RoVa3D" }
}
}

View File

@ -0,0 +1,41 @@
{
"id": "punchtec_connect_xl",
"name": "Punchtec Connect XL",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Punchtec",
"category": "Other",
"file_formats": "text/x-gcode",
"machine_extruder_trains":
{
"0": "punchtec_connect_xl_extruder_0",
"1": "punchtec_connect_xl_extruder_1"
},
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"machine_head_polygon": { "default_value": [[ 0, 0], [ 0, 0], [ 0, 0], [ 0, 0]] },
"speed_travel": { "default_value": 150 },
"prime_tower_size": { "default_value": 8.660254037844387 },
"speed_wall_x": { "default_value": 40 },
"speed_wall_0": { "default_value": 40 },
"material_diameter": { "default_value": 1.75 },
"speed_topbottom": { "default_value": 40 },
"layer_height": { "default_value": 0.2 },
"material_print_temperature": { "default_value": 195 },
"speed_print": { "default_value": 40 },
"speed_infill": { "default_value": 40 },
"machine_extruder_count": { "default_value": 2 },
"machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 200 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 304 },
"machine_width": { "default_value": 304 },
"machine_name": { "default_value": "Punchtec Connect XL" }
}
}

View File

@ -0,0 +1,53 @@
{
"id": "rigid3d",
"name": "Rigid3D",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Rigid3D",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"machine_start_gcode": {
"default_value": " ; -- START GCODE --\n G21\n G28 ; Home extruder\n G29 ; Autolevel bed\n M107 ; Turn off fan\n G90 ; Absolute positioning\n M82 ; Extruder in absolute mode\n G92 E0 ; Reset extruder position\n ; -- end of START GCODE --\n\n"
},
"machine_end_gcode": {
"default_value": " ; -- END GCODE --\n G1 X0 Y230 ; Get extruder out of way.\n M107 ; Turn off fan\n G91 ; Relative positioning\n G0 Z20 ; Lift extruder up\n T0\n G1 E-1 ; Reduce filament pressure\n M104 T0 S0 ; Turn ectruder heater off\n G90 ; Absolute positioning\n G92 E0 ; Reset extruder position\n M140 S0 ; Disable heated bed\n M84 ; Turn steppers off\n ; -- end of END GCODE --\n"
},
"machine_head_polygon": { "default_value": [[ 22, 67], [ 22, 51], [ 36, 51], [ 36, 67]] },
"skirt_gap": { "default_value": 5.0 },
"cool_min_layer_time": { "default_value": 10 },
"prime_tower_size": { "default_value": 7.745966692414834 },
"speed_wall_x": { "default_value": 40 },
"speed_travel": { "default_value": 100 },
"bottom_thickness": { "default_value": 0.75 },
"material_diameter": { "default_value": 1.75 },
"layer_height_0": { "default_value": 0.25 },
"support_angle": { "default_value": 45 },
"material_bed_temperature": { "default_value": 100 },
"top_thickness": { "default_value": 0.75 },
"material_print_temperature": { "default_value": 235 },
"retraction_speed": { "default_value": 60.0 },
"wall_thickness": { "default_value": 0.8 },
"retraction_min_travel": { "default_value": 2 },
"speed_wall_0": { "default_value": 30 },
"retraction_amount": { "default_value": 1 },
"speed_topbottom": { "default_value": 30 },
"layer_height": { "default_value": 0.25 },
"speed_print": { "default_value": 40 },
"speed_infill": { "default_value": 40 },
"machine_extruder_count": { "default_value": 1 },
"machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 210 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 250 },
"machine_width": { "default_value": 250 },
"machine_name": { "default_value": "Rigid3D" }
}
}

View File

@ -0,0 +1,50 @@
{
"id": "rigid3d_3rdgen",
"name": "Rigid3D 3rdGen",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Rigid3D",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"machine_start_gcode": {
"default_value": " ; -- START GCODE --\n G21\n G28 ; Home extruder\n G29 ; Autolevel bed\n M107 ; Turn off fan\n G90 ; Absolute positioning\n M82 ; Extruder in absolute mode\n G92 E0 ; Reset extruder position\n ; -- end of START GCODE --\n\n"
},
"machine_end_gcode": {
"default_value": " ; -- END GCODE --\n G1 X0 Y230 ; Get extruder out of way.\n M107 ; Turn off fan\n G91 ; Relative positioning\n G0 Z20 ; Lift extruder up\n T0\n G1 E-1 ; Reduce filament pressure\n M104 T0 S0 ; Turn extruder heater off\n G90 ; Absolute positioning\n G92 E0 ; Reset extruder position\n M140 S0 ; Disable heated bed\n M84 ; Turn steppers off\n ; -- end of END GCODE --\n"
},
"machine_head_polygon": { "default_value": [[ 18, 0], [ 18, 65], [ 32, 65], [ 32, 0]] },
"cool_min_layer_time": { "default_value": 10 },
"prime_tower_size": { "default_value": 7.745966692414834 },
"skirt_gap": { "default_value": 5.0 },
"speed_travel": { "default_value": 120 },
"bottom_thickness": { "default_value": 0.75 },
"material_diameter": { "default_value": 1.75 },
"layer_height_0": { "default_value": 0.25 },
"support_angle": { "default_value": 45 },
"material_bed_temperature": { "default_value": 100 },
"retraction_min_travel": { "default_value": 2 },
"speed_wall_0": { "default_value": 30 },
"retraction_speed": { "default_value": 60.0 },
"wall_thickness": { "default_value": 0.8 },
"material_print_temperature": { "default_value": 235 },
"retraction_amount": { "default_value": 1 },
"speed_topbottom": { "default_value": 25 },
"layer_height": { "default_value": 0.25 },
"top_thickness": { "default_value": 0.75 },
"machine_extruder_count": { "default_value": 1 },
"machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 240 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 290 },
"machine_width": { "default_value": 275 },
"machine_name": { "default_value": "Rigid3D 3rd Geneartion" }
}
}

View File

@ -0,0 +1,47 @@
{
"id": "rigid3d_hobby",
"name": "Rigid3D Hobby",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Rigid3D",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"machine_head_polygon": { "default_value": [[ 16, 30], [ 16, 45], [ 16, 45], [ 16, 30]] },
"prime_tower_size": { "default_value": 8.660254037844387 },
"speed_travel": { "default_value": 40 },
"skirt_gap": { "default_value": 5.0 },
"cool_min_layer_time": { "default_value": 15 },
"support_pattern": { "default_value": "grid" },
"material_diameter": { "default_value": 1.75 },
"layer_height_0": { "default_value": 0.25 },
"speed_wall_x": { "default_value": 30 },
"skirt_line_count": { "default_value": 2 },
"support_angle": { "default_value": 45 },
"speed_topbottom": { "default_value": 20 },
"material_print_temperature": { "default_value": 205 },
"retraction_speed": { "default_value": 80 },
"wall_thickness": { "default_value": 0.8 },
"retraction_min_travel": { "default_value": 2 },
"speed_wall_0": { "default_value": 20 },
"retraction_amount": { "default_value": 2 },
"speed_layer_0": { "default_value": 15 },
"layer_height": { "default_value": 0.2 },
"speed_print": { "default_value": 30 },
"speed_infill": { "default_value": 30 },
"machine_extruder_count": { "default_value": 1 },
"machine_heated_bed": { "default_value": false },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 150 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 150 },
"machine_width": { "default_value": 150 },
"machine_name": { "default_value": "Rigid3D Hobby" }
}
}

View File

@ -0,0 +1,53 @@
{
"id": "rigid3d_zero",
"name": "Rigid3D Zero",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Rigid3D",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"machine_start_gcode": {
"default_value": " ; -- START GCODE --\n G21\n G28 ; Home extruder\n G29 ; Autolevel bed\n M107 ; Turn off fan\n G90 ; Absolute positioning\n M82 ; Extruder in absolute mode\n G92 E0 ; Reset extruder position\n ; -- end of START GCODE --\n\n"
},
"machine_end_gcode": {
"default_value": " ; -- END GCODE --\n G1 X0 Y230 ; Get extruder out of way.\n M107 ; Turn off fan\n G91 ; Relative positioning\n G0 Z20 ; Lift extruder up\n T0\n G1 E-1 ; Reduce filament pressure\n M104 T0 S0 ; Turn ectruder heater off\n G90 ; Absolute positioning\n G92 E0 ; Reset extruder position\n M140 S0 ; Disable heated bed\n M84 ; Turn steppers off\n ; -- end of END GCODE --\n"
},
"machine_head_polygon": { "default_value": [[ 40, 15], [ 40, 60], [ 30, 60], [ 30, 15]] },
"support_pattern": { "default_value": "grid" },
"cool_min_layer_time": { "default_value": 10 },
"speed_travel": { "default_value": 80 },
"support_angle": { "default_value": 45 },
"retraction_min_travel": { "default_value": 2 },
"speed_wall_0": { "default_value": 20 },
"speed_layer_0": { "default_value": 15 },
"speed_infill": { "default_value": 30 },
"speed_topbottom": { "default_value": 30 },
"prime_tower_size": { "default_value": 7.745966692414834 },
"skirt_line_count": { "default_value": 2 },
"speed_wall_x": { "default_value": 30 },
"material_diameter": { "default_value": 1.75 },
"bottom_thickness": { "default_value": 0.75 },
"layer_height_0": { "default_value": 0.25 },
"top_thickness": { "default_value": 0.75 },
"wall_thickness": { "default_value": 0.8 },
"material_print_temperature": { "default_value": 195 },
"retraction_amount": { "default_value": 1.5 },
"skirt_gap": { "default_value": 5.0 },
"layer_height": { "default_value": 0.25 },
"speed_print": { "default_value": 30 },
"machine_extruder_count": { "default_value": 1 },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 190 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 250 },
"machine_width": { "default_value": 250 },
"machine_name": { "default_value": "Rigid3D Zero" }
}
}

View File

@ -39,10 +39,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": ";Sliced at: {day} {date} {time}\n;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_sparse_density}\n;Print time: {print_time}\n;Filament used: {filament_amount}m {filament_weight}g\n;Filament cost: {filament_cost}\n;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line\n;M109 S{print_temperature} ;Uncomment to add your own temperature line\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nM205 X8 ;X/Y Jerk settings\nG1 Z15.0 F{travel_speed} ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E7 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F{travel_speed}\n;Put printing message on LCD screen\nM117 Rigibot Printing..."
"default_value": ";Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_sparse_density}\n;M190 S{material_bed_temperature} ;Uncomment to add your own bed temperature line\n;M109 S{material_print_temperature} ;Uncomment to add your own temperature line\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nM205 X8 ;X/Y Jerk settings\nG1 Z15.0 F{travel_speed} ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E7 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F{speed_travel}\n;Put printing message on LCD screen\nM117 Rigibot Printing..."
},
"machine_end_gcode": {
"default_value": ";End GCode\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+10 E-1 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nG1 Y230 F3000 ;move Y so the head is out of the way and Plate is moved forward\nM84 ;steppers off\nG90 ;absolute positioning\n;{profile_string}"
"default_value": ";End GCode\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+10 E-1 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nG1 Y230 F3000 ;move Y so the head is out of the way and Plate is moved forward\nM84 ;steppers off\nG90 ;absolute positioning"
},
"layer_height": {
"default_value": 0.2

View File

@ -42,10 +42,10 @@
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": ";Sliced at: {day} {date} {time}\n;Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_sparse_density}\n;Print time: {print_time}\n;Filament used: {filament_amount}m {filament_weight}g\n;Filament cost: {filament_cost}\n;M190 S{print_bed_temperature} ;Uncomment to add your own bed temperature line\n;M109 S{print_temperature} ;Uncomment to add your own temperature line\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nM205 X8 ;X/Y Jerk settings\nG1 Z15.0 F{travel_speed} ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E7 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F{travel_speed}\n;Put printing message on LCD screen\nM117 Rigibot Printing..."
"default_value": ";Basic settings: Layer height: {layer_height} Walls: {wall_thickness} Fill: {infill_sparse_density}\n;Print time: {print_time}\n;M190 S{material_bed_temperature} ;Uncomment to add your own bed temperature line\n;M109 S{material_print_temperature} ;Uncomment to add your own temperature line\nG21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nM205 X8 ;X/Y Jerk settings\nG1 Z15.0 F{speed_travel} ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E7 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F{speed_travel}\n;Put printing message on LCD screen\nM117 Rigibot Printing..."
},
"machine_end_gcode": {
"default_value": ";End GCode\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+10 E-1 X-20 Y-20 F{travel_speed} ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nG1 Y230 F3000 ;move Y so the head is out of the way and Plate is moved forward\nM84 ;steppers off\nG90 ;absolute positioning\n;{profile_string}"
"default_value": ";End GCode\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+10 E-1 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nG1 Y230 F3000 ;move Y so the head is out of the way and Plate is moved forward\nM84 ;steppers off\nG90 ;absolute positioning"
},
"layer_height": {
"default_value": 0.2

View File

@ -0,0 +1,61 @@
{
"id": "robo_3d_r1",
"name": "Robo 3D R1",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Robo 3D",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"machine_start_gcode": {
"default_value": " G92 E0 ;\n M565 Z-1 ;\n G1 Z5 F5000 ;\n G29 ;\n"
},
"machine_end_gcode": {
"default_value": " M104 S0 ;extruder heater off\n M140 S0 ;heated bed heater off (if you have it)\n G91 ;relative positioning\n G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n G1 Z+0.5 E-5 X-20 Y-20 F{speed_travel} ;move Z up a bit and retract filament even more\n G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n M84 ;steppers off\n G90 ;absolute positioning\n"
},
"cool_min_layer_time": { "default_value": 7 },
"speed_topbottom": { "default_value": 40 },
"retraction_speed": { "default_value": 50 },
"layer_0_z_overlap": { "default_value": 0.2 },
"cool_min_speed": { "default_value": 19 },
"material_bed_temperature": { "default_value": 60 },
"support_angle": { "default_value": 50 },
"speed_layer_0": { "default_value": 30 },
"line_width": { "default_value": 0.4 },
"speed_infill": { "default_value": 60 },
"prime_tower_size": { "default_value": 8.660254037844387 },
"support_enable": { "default_value": true },
"cool_fan_full_at_height": { "default_value": 0.1 },
"material_diameter": { "default_value": 1.75 },
"bottom_thickness": { "default_value": 1.2 },
"raft_airgap": { "default_value": 0.2 },
"layer_height_0": { "default_value": 0.15 },
"top_thickness": { "default_value": 1.2 },
"speed_wall_0": { "default_value": 40 },
"retraction_min_travel": { "default_value": 5 },
"material_flow": { "default_value": 100 },
"infill_sparse_density": { "default_value": 10 },
"wall_thickness": { "default_value": 1.2 },
"material_print_temperature": { "default_value": 190 },
"retraction_amount": { "default_value": 3 },
"layer_height": { "default_value": 0.2 },
"speed_print": { "default_value": 40 },
"machine_extruder_count": { "default_value": 1 },
"retraction_combing": { "default_value": "off" },
"machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 210 },
"adhesion_type": { "default_value": "raft" },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 245 },
"machine_width": { "default_value": 225 },
"support_z_distance": { "default_value": 0.22 },
"machine_name": { "default_value": "ROBO 3D R1" }
}
}

View File

@ -86,12 +86,6 @@
"machine_nozzle_expansion_angle": {
"default_value": 45
},
"material_print_temperature": {
"enabled": "not (material_flow_dependent_temperature) and machine_gcode_flavor != \"UltiGCode\""
},
"material_bed_temperature": {
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\""
},
"machine_max_feedrate_x": {
"default_value": 300
},
@ -106,24 +100,6 @@
},
"machine_acceleration": {
"default_value": 3000
},
"material_diameter": {
"enabled": "machine_gcode_flavor != \"UltiGCode\""
},
"material_flow": {
"enabled": "machine_gcode_flavor != \"UltiGCode\""
},
"retraction_amount": {
"enabled": "retraction_enable and machine_gcode_flavor != \"UltiGCode\""
},
"retraction_speed": {
"enabled": "retraction_enable and machine_gcode_flavor != \"UltiGCode\""
},
"retraction_retract_speed": {
"enabled": "retraction_enable and machine_gcode_flavor != \"UltiGCode\""
},
"retraction_prime_speed": {
"enabled": "retraction_enable and machine_gcode_flavor != \"UltiGCode\""
}
}
}

View File

@ -34,7 +34,7 @@
"overrides": {
"machine_name": { "default_value": "Ultimaker 3" },
"machine_width": { "default_value": 215 },
"machine_width": { "default_value": 233 },
"machine_depth": { "default_value": 215 },
"machine_height": { "default_value": 200 },
"machine_heated_bed": { "default_value": true },
@ -44,10 +44,10 @@
{
"default_value":
[
[ -40, 10 ],
[ -40, -30 ],
[ 60, 10 ],
[ 60, -30 ]
[ -29, 6.1 ],
[ -29, -33.9 ],
[ 71, 6.1 ],
[ 71, -33.9 ]
]
},
"machine_gcode_flavor": { "default_value": "Griffin" },
@ -57,15 +57,12 @@
"machine_acceleration": { "default_value": 3000 },
"gantry_height": { "default_value": 60 },
"machine_disallowed_areas": { "default_value": [
[[-91.5, -115], [-115, -115], [-115, -104.6], [-91.5, -104.6]],
[[-99.5, -104.6], [-115, -104.6], [-115, 104.6], [-99.5, 104.6]],
[[-94.5, 104.6], [-115, 104.6], [-115, 105.5], [-94.5, 105.5]],
[[-91.4, 105.5], [-115, 105.5], [-115, 115], [-91.4, 115]],
[[77.3, -115], [77.3, -98.6], [115, -98.6], [115, -115]],
[[97.2, -98.6], [97.2, -54.5], [113, -54.5], [113, -98.6]],
[[100.5, -54.5], [100.5, 99.3], [115, 99.3], [115, -54.5]],
[[77, 99.3], [77, 115], [115, 115], [115, 99.3]]
[[92.8, -53.4], [92.8, -97.5], [116.5, -97.5], [116.5, -53.4]],
[[73.8, 107.5], [73.8, 100.5], [116.5, 100.5], [116.5, 107.5]],
[[74.6, 107.5], [74.6, 100.5], [116.5, 100.5], [116.5, 107.5]],
[[74.9, -97.5], [74.9, -107.5], [116.5, -107.5], [116.5, -97.5]],
[[-116.5, -103.5], [-116.5, -107.5], [-100.9, -107.5], [-100.9, -103.5]],
[[-116.5, 105.8], [-96.9, 105.8], [-96.9, 107.5], [-116.5, 107.5]]
]},
"machine_extruder_count": { "default_value": 2 },
"extruder_prime_pos_abs": { "default_value": true },
@ -74,10 +71,6 @@
"prime_tower_position_x": { "default_value": 175 },
"prime_tower_position_y": { "default_value": 179 },
"extruder_prime_pos_x": { "enabled": false },
"extruder_prime_pos_y": { "enabled": false },
"print_sequence": {"enabled": false},
"acceleration_enabled": { "value": "True" },
"acceleration_layer_0": { "value": "acceleration_topbottom" },
"acceleration_prime_tower": { "value": "math.ceil(acceleration_print * 2000 / 4000)" },
@ -106,6 +99,8 @@
"jerk_wall": { "value": "math.ceil(jerk_print * 10 / 25)" },
"jerk_wall_0": { "value": "math.ceil(jerk_wall * 5 / 10)" },
"layer_height_0": { "value": "round(machine_nozzle_size / 1.5, 2)" },
"layer_start_x": { "value": "sum(extruderValues('machine_extruder_start_pos_x')) / len(extruderValues('machine_extruder_start_pos_x'))" },
"layer_start_y": { "value": "sum(extruderValues('machine_extruder_start_pos_y')) / len(extruderValues('machine_extruder_start_pos_y'))" },
"line_width": { "value": "machine_nozzle_size * 0.875" },
"machine_min_cool_heat_time_window": { "value": "15" },
"material_print_temperature": { "value": "200" },

View File

@ -14,7 +14,7 @@
"platform_texture": "Ultimaker3Extendedbackplate.png",
"platform_offset": [0, 0, 0],
"has_machine_quality": true,
"has_machine_materials": true,
"has_machine_materials": true,
"has_variant_materials": true,
"has_materials": true,
"has_variants": true,

View File

@ -72,9 +72,6 @@
"machine_extruder_count": {
"default_value": 2
},
"print_sequence": {
"enabled": false
},
"prime_tower_position_x": {
"default_value": 185
},

View File

@ -0,0 +1,30 @@
{
"id": "zone3d_printer",
"name": "Zone3d Printer",
"version": 2,
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"author": "Ultimaker",
"manufacturer": "Unknown",
"category": "Other",
"file_formats": "text/x-gcode",
"platform_offset": [ 0, 0, 0]
},
"overrides": {
"material_diameter": { "default_value": 1.75 },
"prime_tower_size": { "default_value": 10.350983390135314 },
"material_print_temperature": { "default_value": 260 },
"layer_height": { "default_value": 0.14 },
"speed_travel": { "default_value": 150 },
"machine_extruder_count": { "default_value": 1 },
"machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 210 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 220 },
"machine_width": { "default_value": 240 },
"machine_name": { "default_value": "Zone3D Printer" }
}
}

View File

@ -0,0 +1,19 @@
{
"id": "ord_extruder_0",
"version": 2,
"name": "0",
"inherits": "fdmextruder",
"metadata": {
"machine": "ord",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "4"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 }
}
}

View File

@ -0,0 +1,19 @@
{
"id": "ord_extruder_1",
"version": 2,
"name": "1",
"inherits": "fdmextruder",
"metadata": {
"machine": "ord",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "4"
},
"machine_nozzle_offset_x": { "default_value": 62.95 },
"machine_nozzle_offset_y": { "default_value": 2.05 }
}
}

View File

@ -0,0 +1,19 @@
{
"id": "ord_extruder_2",
"version": 2,
"name": "2",
"inherits": "fdmextruder",
"metadata": {
"machine": "ord",
"position": "2"
},
"overrides": {
"extruder_nr": {
"default_value": 2,
"maximum_value": "4"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 27.7 }
}
}

View File

@ -0,0 +1,19 @@
{
"id": "ord_extruder_3",
"version": 2,
"name": "3",
"inherits": "fdmextruder",
"metadata": {
"machine": "ord",
"position": "3"
},
"overrides": {
"extruder_nr": {
"default_value": 3,
"maximum_value": "4"
},
"machine_nozzle_offset_x": { "default_value": 63.18 },
"machine_nozzle_offset_y": { "default_value": 28.65 }
}
}

View File

@ -0,0 +1,19 @@
{
"id": "ord_extruder_4",
"version": 2,
"name": "4",
"inherits": "fdmextruder",
"metadata": {
"machine": "ord",
"position": "4"
},
"overrides": {
"extruder_nr": {
"default_value": 4,
"maximum_value": "4"
},
"machine_nozzle_offset_x": { "default_value": 31.6 },
"machine_nozzle_offset_y": { "default_value": 28.2 }
}
}

View File

@ -0,0 +1,19 @@
{
"id": "punchtec_connect_xl_extruder_0",
"version": 2,
"name": "0",
"inherits": "fdmextruder",
"metadata": {
"machine": "punchtec_connect_xl",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 }
}
}

View File

@ -0,0 +1,19 @@
{
"id": "punchtec_connect_xl_extruder_1",
"version": 2,
"name": "1",
"inherits": "fdmextruder",
"metadata": {
"machine": "punchtec_connect_xl",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 }
}
}

View File

@ -13,8 +13,8 @@
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": -11.0 },
"machine_nozzle_offset_y": { "default_value": 3.9 },
"machine_nozzle_offset_x": { "default_value": 0 },
"machine_nozzle_offset_y": { "default_value": 0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "default_value": 213 },
@ -23,8 +23,8 @@
"machine_extruder_end_pos_x": { "default_value": 213 },
"machine_extruder_end_pos_y": { "default_value": 207 },
"machine_nozzle_head_distance": { "default_value": 2.7 },
"extruder_prime_pos_x": { "default_value": 170, "enabled": false },
"extruder_prime_pos_y": { "default_value": 6, "enabled": false },
"extruder_prime_pos_z": { "default_value": 2, "enabled": false }
"extruder_prime_pos_x": { "default_value": 170 },
"extruder_prime_pos_y": { "default_value": 6 },
"extruder_prime_pos_z": { "default_value": 2 }
}
}

View File

@ -13,8 +13,8 @@
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 7.0 },
"machine_nozzle_offset_y": { "default_value": 3.9 },
"machine_nozzle_offset_x": { "default_value": 18 },
"machine_nozzle_offset_y": { "default_value": 0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "default_value": 213 },
@ -23,8 +23,8 @@
"machine_extruder_end_pos_x": { "default_value": 213 },
"machine_extruder_end_pos_y": { "default_value": 189 },
"machine_nozzle_head_distance": { "default_value": 4.2 },
"extruder_prime_pos_x": { "default_value": 182, "enabled": false },
"extruder_prime_pos_y": { "default_value": 6, "enabled": false },
"extruder_prime_pos_z": { "default_value": 2, "enabled": false }
"extruder_prime_pos_x": { "default_value": 182 },
"extruder_prime_pos_y": { "default_value": 6 },
"extruder_prime_pos_z": { "default_value": 2 }
}
}

View File

@ -13,8 +13,8 @@
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": -11.0 },
"machine_nozzle_offset_y": { "default_value": 3.9 },
"machine_nozzle_offset_x": { "default_value": 0 },
"machine_nozzle_offset_y": { "default_value": 0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "default_value": 213 },
@ -23,8 +23,8 @@
"machine_extruder_end_pos_x": { "default_value": 213 },
"machine_extruder_end_pos_y": { "default_value": 207 },
"machine_nozzle_head_distance": { "default_value": 2.7 },
"extruder_prime_pos_x": { "default_value": 170, "enabled": false },
"extruder_prime_pos_y": { "default_value": 6, "enabled": false },
"extruder_prime_pos_z": { "default_value": 2, "enabled": false }
"extruder_prime_pos_x": { "default_value": 170 },
"extruder_prime_pos_y": { "default_value": 6 },
"extruder_prime_pos_z": { "default_value": 2 }
}
}

View File

@ -13,8 +13,8 @@
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 7.0 },
"machine_nozzle_offset_y": { "default_value": 3.9 },
"machine_nozzle_offset_x": { "default_value": 18 },
"machine_nozzle_offset_y": { "default_value": 0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "default_value": 213 },
@ -23,8 +23,8 @@
"machine_extruder_end_pos_x": { "default_value": 213 },
"machine_extruder_end_pos_y": { "default_value": 189 },
"machine_nozzle_head_distance": { "default_value": 4.2 },
"extruder_prime_pos_x": { "default_value": 182, "enabled": false },
"extruder_prime_pos_y": { "default_value": 6, "enabled": false },
"extruder_prime_pos_z": { "default_value": 2, "enabled": false }
"extruder_prime_pos_x": { "default_value": 182 },
"extruder_prime_pos_y": { "default_value": 6 },
"extruder_prime_pos_z": { "default_value": 2 }
}
}

View File

@ -160,13 +160,13 @@ msgstr "Salvato su unità rimovibile {0} come {1}"
#: /home/ruben/Projects/Cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:103
msgctxt "@action:button"
msgid "Eject"
msgstr "Espelli"
msgstr "Rimuovi"
#: /home/ruben/Projects/Cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:103
#, python-brace-format
msgctxt "@action"
msgid "Eject removable device {0}"
msgstr "Espelli il dispositivo rimovibile {0}"
msgstr "Rimuovi il dispositivo rimovibile {0}"
#: /home/ruben/Projects/Cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:108
#, python-brace-format
@ -2008,7 +2008,7 @@ msgstr "Sel&eziona tutti i modelli"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:248
msgctxt "@action:inmenu menubar:edit"
msgid "&Clear Build Plate"
msgstr "&Cancella piano di stampa"
msgstr "&Cancellare piano di stampa"
#: /home/ruben/Projects/Cura/resources/qml/Actions.qml:258
msgctxt "@action:inmenu menubar:file"

View File

@ -2257,12 +2257,12 @@ msgstr "Regola il posizionamento delle strutture di supporto. Il posizionamento
#: fdmprinter.def.json
msgctxt "support_type option buildplate"
msgid "Touching Buildplate"
msgstr "Sostegno solo delle pareti esterne"
msgstr "Contatto con il Piano di Stampa"
#: fdmprinter.def.json
msgctxt "support_type option everywhere"
msgid "Everywhere"
msgstr "In tutti i possibili punti"
msgstr "In Tutti i Possibili Punti"
#: fdmprinter.def.json
msgctxt "support_angle label"

View File

@ -121,7 +121,7 @@ Item
Action
{
id: updateProfileAction;
enabled: Cura.MachineManager.isActiveStackValid && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
enabled: !Cura.MachineManager.stacksHaveErrors && Cura.MachineManager.hasUserSettings && !Cura.MachineManager.isReadOnly(Cura.MachineManager.activeQualityId)
text: catalog.i18nc("@action:inmenu menubar:profile","&Update profile with current settings");
onTriggered: Cura.ContainerManager.updateQualityChanges();
}
@ -130,14 +130,18 @@ Item
{
id: resetProfileAction;
enabled: Cura.MachineManager.hasUserSettings
text: catalog.i18nc("@action:inmenu menubar:profile","&Discard current settings");
onTriggered: Cura.ContainerManager.clearUserContainers();
text: catalog.i18nc("@action:inmenu menubar:profile","&Discard current changes");
onTriggered:
{
forceActiveFocus();
Cura.ContainerManager.clearUserContainers();
}
}
Action
{
id: addProfileAction;
enabled: Cura.MachineManager.isActiveStackValid && Cura.MachineManager.hasUserSettings
enabled: !Cura.MachineManager.stacksHaveErrors && Cura.MachineManager.hasUserSettings
text: catalog.i18nc("@action:inmenu menubar:profile","&Create profile from current settings...");
}
@ -228,7 +232,7 @@ Item
Action
{
id: multiplyObjectAction;
text: catalog.i18nc("@action:inmenu","&Duplicate Model");
text: catalog.i18nc("@action:inmenu","&Multiply Model...");
iconName: "edit-duplicate"
}

View File

@ -246,15 +246,35 @@ UM.MainWindow
{
if(drop.urls.length > 0)
{
// Import models
for(var i in drop.urls)
{
UM.MeshFileHandler.readLocalFile(drop.urls[i]);
if (i == drop.urls.length - 1)
{
var meshName = backgroundItem.getMeshName(drop.urls[i].toString())
backgroundItem.hasMesh(decodeURIComponent(meshName))
// There is no endsWith in this version of JS...
if ((drop.urls[i].length <= 12) || (drop.urls[i].substring(drop.urls[i].length-12) !== ".curaprofile")) {
// Drop an object
UM.MeshFileHandler.readLocalFile(drop.urls[i]);
if (i == drop.urls.length - 1)
{
var meshName = backgroundItem.getMeshName(drop.urls[i].toString());
backgroundItem.hasMesh(decodeURIComponent(meshName));
}
}
}
// Import profiles
var import_result = Cura.ContainerManager.importProfiles(drop.urls);
if (import_result.message !== "") {
messageDialog.text = import_result.message
if(import_result.status == "ok")
{
messageDialog.icon = StandardIcon.Information
}
else
{
messageDialog.icon = StandardIcon.Critical
}
messageDialog.open()
}
}
}
}
@ -402,6 +422,20 @@ UM.MainWindow
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenterOffset: - UM.Theme.getSize("sidebar").width / 2
visible: base.monitoringPrint
onVisibleChanged:
{
if(Cura.MachineManager.printerOutputDevices.length == 0 )
{
return;
}
if(visible)
{
Cura.MachineManager.printerOutputDevices[0].startCamera()
} else
{
Cura.MachineManager.printerOutputDevices[0].stopCamera()
}
}
source:
{
if(!base.monitoringPrint)
@ -539,7 +573,7 @@ UM.MainWindow
target: Cura.MachineManager
onBlurSettings:
{
contentItem.focus = true
contentItem.forceActiveFocus()
}
}
@ -575,6 +609,11 @@ UM.MainWindow
}
}
MultiplyObjectOptions
{
id: multiplyObjectOptions
}
Connections
{
target: Cura.Actions.multiplyObject
@ -582,7 +621,9 @@ UM.MainWindow
{
if(objectContextMenu.objectId != 0)
{
Printer.multiplyObject(objectContextMenu.objectId, 1);
multiplyObjectOptions.objectId = objectContextMenu.objectId;
multiplyObjectOptions.visible = true;
multiplyObjectOptions.reset();
objectContextMenu.objectId = 0;
}
}

View File

@ -153,6 +153,7 @@ Menu
else
{
result.definition = "fdmprinter";
result.compatible = true; //NB: Only checks for compatibility in global version of material, but we don't have machine-specific materials anyway.
}
return result;
}

View File

@ -0,0 +1,66 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.1
import UM 1.1 as UM
UM.Dialog
{
id: base
//: Dialog title
title: catalog.i18nc("@title:window", "Multiply Model")
minimumWidth: 400 * Screen.devicePixelRatio
minimumHeight: 80 * Screen.devicePixelRatio
width: minimumWidth
height: minimumHeight
property var objectId: 0;
onAccepted: Printer.multiplyObject(base.objectId, parseInt(copiesField.text))
property variant catalog: UM.I18nCatalog { name: "cura" }
signal reset()
onReset: {
copiesField.text = "1";
copiesField.selectAll();
copiesField.focus = true;
}
Row
{
spacing: UM.Theme.getSize("default_margin").width
Label {
text: "Number of copies:"
anchors.verticalCenter: copiesField.verticalCenter
}
TextField {
id: copiesField
validator: RegExpValidator { regExp: /^\d{0,2}/ }
maximumLength: 2
}
}
rightButtons:
[
Button
{
text: catalog.i18nc("@action:button","OK")
onClicked: base.accept()
enabled: base.objectId != 0 && parseInt(copiesField.text) > 0
},
Button
{
text: catalog.i18nc("@action:button","Cancel")
onClicked: base.reject()
}
]
}

View File

@ -251,6 +251,8 @@ UM.ManagementPage
{
id: renameDialog;
object: base.currentItem && base.currentItem.name ? base.currentItem.name : "";
property var machine_name_validator: Cura.MachineNameValidator { }
validName: renameDialog.newName.match(renameDialog.machine_name_validator.machineNameRegex) != null;
onAccepted:
{
Cura.MachineManager.renameMachine(base.currentItem.id, newName.trim());

View File

@ -22,7 +22,7 @@ TabView
Tab
{
title: "Information"
title: catalog.i18nc("@title","Information")
anchors
{
leftMargin: UM.Theme.getSize("default_margin").width

View File

@ -29,7 +29,8 @@ UM.ManagementPage
}
else
{
result.definition = "fdmprinter"
result.definition = "fdmprinter";
result.compatible = true; //NB: Only checks for compatibility in global version of material, but we don't have machine-specific materials anyway.
}
return result
}

View File

@ -62,7 +62,7 @@ UM.ManagementPage
Button
{
text: catalog.i18nc("@label", "Create")
enabled: base.canCreateProfile()
enabled: base.canCreateProfile() && !Cura.MachineManager.stacksHaveErrors
visible: base.canCreateProfile()
iconName: "list-add";
@ -170,7 +170,7 @@ UM.ManagementPage
Button
{
text: catalog.i18nc("@action:button", "Discard current settings");
text: catalog.i18nc("@action:button", "Discard current changes");
enabled: Cura.MachineManager.hasUserSettings
onClicked: Cura.ContainerManager.clearUserContainers();
}
@ -310,7 +310,7 @@ UM.ManagementPage
folder: CuraApplication.getDefaultPath("dialog_profile_path")
onAccepted:
{
var result = base.model.importProfile(fileUrl)
var result = Cura.ContainerManager.importProfile(fileUrl);
messageDialog.text = result.message
if(result.status == "ok")
{
@ -339,7 +339,7 @@ UM.ManagementPage
onAccepted:
{
var containers = Cura.ContainerManager.findInstanceContainers({"type": "quality_changes", "name": base.currentItem.name})
var result = base.model.exportProfile(containers, fileUrl, selectedNameFilter)
var result = Cura.ContainerManager.exportProfile(containers, fileUrl, selectedNameFilter)
if(result && result.status == "error")
{

View File

@ -116,7 +116,8 @@ UM.PreferencesPage
id: definitionsModel
containerId: Cura.MachineManager.activeDefinitionId
showAll: true
exclude: ["machine_settings"]
exclude: ["machine_settings", "command_line_settings"]
showAncestors: true
expanded: ["*"]
visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
}

View File

@ -29,11 +29,11 @@ SettingItem
// 4: variant
// 5: machine
var value;
if ((propertyProvider.properties.resolve != "None") && (stackLevel != 0) && (stackLevel != 1)) {
if ((base.resolve != "None") && (stackLevel != 0) && (stackLevel != 1)) {
// We have a resolve function. Indicates that the setting is not settable per extruder and that
// we have to choose between the resolved value (default) and the global value
// (if user has explicitly set this).
value = propertyProvider.properties.resolve;
value = base.resolve;
} else {
value = propertyProvider.properties.value;
}

View File

@ -96,11 +96,11 @@ SettingItem
{
// FIXME this needs to go away once 'resolve' is combined with 'value' in our data model.
var value;
if ((propertyProvider.properties.resolve != "None") && (base.stackLevel != 0) && (base.stackLevel != 1)) {
if ((base.resolve != "None") && (base.stackLevel != 0) && (base.stackLevel != 1)) {
// We have a resolve function. Indicates that the setting is not settable per extruder and that
// we have to choose between the resolved value (default) and the global value
// (if user has explicitly set this).
value = propertyProvider.properties.resolve;
value = base.resolve;
} else {
value = propertyProvider.properties.value;
}

View File

@ -21,7 +21,11 @@ SettingItem
id: extruders_model
onModelChanged: control.color = extruders_model.getItem(control.currentIndex).color
}
property string color: extruders_model.getItem(control.currentIndex).color
property string color:
{
var model_color = extruders_model.getItem(control.currentIndex).color;
return (model_color) ? model_color : "";
}
textRole: "name"

View File

@ -27,7 +27,8 @@ Item {
// Create properties to put property provider stuff in (bindings break in qt 5.5.1 otherwise)
property var state: propertyProvider.properties.state
property var resolve: propertyProvider.properties.resolve
// There is no resolve property if there is only one stack.
property var resolve: Cura.MachineManager.activeStackId != Cura.MachineManager.activeMachineId ? propertyProvider.properties.resolve : "None"
property var stackLevels: propertyProvider.stackLevels
property var stackLevel: stackLevels[0]

View File

@ -114,11 +114,11 @@ SettingItem
// 3: material -> user changed material in materialspage
// 4: variant
// 5: machine
if ((propertyProvider.properties.resolve != "None" && propertyProvider.properties.resolve) && (stackLevel != 0) && (stackLevel != 1)) {
if ((base.resolve != "None" && base.resolve) && (stackLevel != 0) && (stackLevel != 1)) {
// We have a resolve function. Indicates that the setting is not settable per extruder and that
// we have to choose between the resolved value (default) and the global value
// (if user has explicitly set this).
return propertyProvider.properties.resolve;
return base.resolve;
} else {
return propertyProvider.properties.value;
}

View File

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

View File

@ -222,6 +222,7 @@ Column
width: materialSelection.visible ? (parent.width - UM.Theme.getSize("default_margin").width) / 2 : parent.width
anchors.left: parent.left
style: UM.Theme.styles.sidebar_header_button
activeFocusOnPress: true;
menu: NozzleMenu { extruderIndex: base.currentExtruderIndex }
}
@ -252,6 +253,7 @@ Column
width: variantSelection.visible ? (parent.width - UM.Theme.getSize("default_margin").width) / 2 : parent.width
anchors.right: parent.right
style: UM.Theme.styles.sidebar_header_button
activeFocusOnPress: true;
menu: MaterialMenu { extruderIndex: base.currentExtruderIndex }
}
@ -301,6 +303,7 @@ Column
height: UM.Theme.getSize("setting_control").height
tooltip: Cura.MachineManager.activeQualityName
style: UM.Theme.styles.sidebar_header_button
activeFocusOnPress: true;
property var valueWarning: ! Cura.MachineManager.isActiveQualitySupported
menu: ProfileMenu { }
@ -319,7 +322,11 @@ Column
color: hovered ? UM.Theme.getColor("setting_control_button_hover") : UM.Theme.getColor("setting_control_button");
iconSource: UM.Theme.getIcon("star");
onClicked: Cura.Actions.manageProfiles.trigger()
onClicked:
{
forceActiveFocus();
Cura.Actions.manageProfiles.trigger()
}
onEntered:
{
var content = catalog.i18nc("@tooltip","Some setting values are different from the values stored in the profile.\n\nClick to open the profile manager.")

View File

@ -126,7 +126,7 @@ Item
{
return UM.Theme.getColor("setting_control_disabled_text")
}
return UM.Theme.getColor("text")
return UM.Theme.getColor("setting_control_disabled_text")
}
}
@ -327,7 +327,7 @@ Item
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: supportHelperLabel.right
anchors.leftMargin: UM.Theme.getSize("default_margin").width
width: parent.width / 100 * 45
width: parent.width / 100 * 65
style: UM.Theme.styles.combobox
enabled: base.settingsEnabled