def _onActiveExtruderChanged(self) -> None: new_active_stack = ExtruderManager.getInstance().getActiveExtruderStack() if not new_active_stack: self._active_container_stack = None return if new_active_stack != self._active_container_stack: # Check if changed if self._active_container_stack: # Disconnect signal from old container (if any) self._active_container_stack.propertyChanged.disconnect(self._onPropertyChanged) self._active_container_stack.containersChanged.disconnect(self._onContainersChanged) self._active_container_stack = new_active_stack if self._active_container_stack is not None: self._active_container_stack.propertyChanged.connect(self._onPropertyChanged) self._active_container_stack.containersChanged.connect(self._onContainersChanged) self._update() # Ensure that the settings_with_inheritance_warning list is populated.
def __init__(self, width, height): super().__init__("simulationview", width, height) self._layer_shader = None self._layer_shadow_shader = None self._current_shader = None # This shader will be the shadow or the normal depending if the user wants to see the paths or the layers self._tool_handle_shader = None self._nozzle_shader = None self._old_current_layer = 0 self._old_current_path = 0 self._switching_layers = True # It tracks when the user is moving the layers' slider self._gl = OpenGL.getInstance().getBindingsObject() self._scene = Application.getInstance().getController().getScene() self._extruder_manager = ExtruderManager.getInstance() self._layer_view = None self._compatibility_mode = None
def getOverridesForExtruder(self, key: str, extruder_index: str) -> List[str]: if self._global_container_stack is None: return [] result = [] # type: List[str] extruder_stack = ExtruderManager.getInstance().getExtruderStack(extruder_index) if not extruder_stack: Logger.log("w", "Unable to find extruder for current machine with index %s", extruder_index) return result definitions = self._global_container_stack.definition.findDefinitions(key = key) if not definitions: Logger.log("w", "Could not find definition for key [%s] (2)", key) return result for key in definitions[0].getAllKeys(): if self._settingIsOverwritingInheritance(key, extruder_stack): result.append(key) return result
def _handlePerObjectSettings(self, node: SteSlicerSceneNode, message: Arcus.PythonMessage): stack = node.callDecoration("getStack") # Check if the node has a stack attached to it and the stack has any settings in the top container. if not stack: return # Check all settings for relations, so we can also calculate the correct values for dependent settings. top_of_stack = stack.getTop() # Cache for efficiency. changed_setting_keys = top_of_stack.getAllKeys() # Add all relations to changed settings as well. for key in top_of_stack.getAllKeys(): instance = top_of_stack.getInstance(key) self._addRelations(changed_setting_keys, instance.definition.relations) Job.yieldThread() # Ensure that the engine is aware what the build extruder is. changed_setting_keys.add("extruder_nr") # Get values for all changed settings for key in changed_setting_keys: setting = message.addRepeatedMessage("settings") setting.name = key extruder = int( round(float(stack.getProperty(key, "limit_to_extruder")))) # Check if limited to a specific extruder, but not overridden by per-object settings. if extruder >= 0 and key not in changed_setting_keys: limited_stack = ExtruderManager.getInstance( ).getActiveExtruderStacks()[extruder] else: limited_stack = stack setting.value = str(limited_stack.getProperty( key, "value")).encode("utf-8") Job.yieldThread()
def __init__(self): super().__init__() self._stack = PerObjectContainerStack( container_id="per_object_stack_" + str(id(self))) self._stack.setDirty(False) # This stack does not need to be saved. user_container = InstanceContainer( container_id=self._generateUniqueName()) user_container.setMetaDataEntry("type", "user") self._stack.userChanges = user_container self._extruder_stack = ExtruderManager.getInstance().getExtruderStack( 0).getId() self._is_non_printing_mesh = False self._is_non_thumbnail_visible_mesh = False self._stack.propertyChanged.connect(self._onSettingChanged) Application.getInstance().getContainerRegistry().addContainer( self._stack) Application.getInstance().globalContainerStackChanged.connect( self._updateNextStack) self.activeExtruderChanged.connect(self._updateNextStack) self._updateNextStack()
def _getSettingProperty(self, setting_key: str, prop: str = "value") -> Any: if self._global_stack is None or self._node is None: return None per_mesh_stack = self._node.callDecoration("getStack") if per_mesh_stack: return per_mesh_stack.getProperty(setting_key, prop) extruder_index = self._global_stack.getProperty( setting_key, "limit_to_extruder") if extruder_index == "-1": # No limit_to_extruder extruder_stack_id = self._node.callDecoration("getActiveExtruder") if not extruder_stack_id: # Decoration doesn't exist extruder_stack_id = ExtruderManager.getInstance( ).extruderIds["0"] extruder_stack = ContainerRegistry.getInstance( ).findContainerStacks(id=extruder_stack_id)[0] return extruder_stack.getProperty(setting_key, prop) else: # Limit_to_extruder is set. The global stack handles this then return self._global_stack.getProperty(setting_key, prop)
def setActiveExtruder(self, extruder_stack_id): self._extruder_stack = extruder_stack_id self._updateNextStack() ExtruderManager.getInstance().resetSelectedObjectExtruders() self.activeExtruderChanged.emit()
def run(self): Logger.log( "d", "Processing new layer for build plate %s..." % self._build_plate_number) start_time = time() view = Application.getInstance().getController().getActiveView() if view.getPluginId() == "SimulationView": view.resetLayerData() self._progress_message.show() Job.yieldThread() if self._abort_requested: if self._progress_message: self._progress_message.hide() return Application.getInstance().getController().activeViewChanged.connect( self._onActiveViewChanged) # The no_setting_override is here because adding the SettingOverrideDecorator will trigger a reslice new_node = SteSlicerSceneNode(no_setting_override=True) new_node.addDecorator(BuildPlateDecorator(self._build_plate_number)) # Force garbage collection. # For some reason, Python has a tendency to keep the layer data # in memory longer than needed. Forcing the GC to run here makes # sure any old layer data is really cleaned up before adding new. gc.collect() mesh = MeshData() layer_data = LayerDataBuilder.LayerDataBuilder() layer_count = len(self._layers) # Find the minimum layer number # When disabling the remove empty first layers setting, the minimum layer number will be a positive # value. In that case the first empty layers will be discarded and start processing layers from the # first layer with data. # When using a raft, the raft layers are sent as layers < 0. Instead of allowing layers < 0, we # simply offset all other layers so the lowest layer is always 0. It could happens that the first # raft layer has value -8 but there are just 4 raft (negative) layers. min_layer_number = sys.maxsize negative_layers = 0 for layer in self._layers: if isinstance(layer, Arcus.PythonMessage): if layer.repeatedMessageCount("path_segment") > 0: if layer.id < min_layer_number: min_layer_number = layer.id if layer.id < 0: negative_layers += 1 else: if layer.id < min_layer_number: min_layer_number = layer.id if layer.id < 0: negative_layers += 1 current_layer = 0 additional_first_layers = 0 for layer in self._layers: if isinstance(layer, Layer): layer_data.addLayer(current_layer, layer) additional_first_layers += 1 else: # If the layer is below the minimum, it means that there is no data, so that we don't create a layer # data. However, if there are empty layers in between, we compute them. if layer.id < min_layer_number: continue # Layers are offset by the minimum layer number. In case the raft (negative layers) is being used, # then the absolute layer number is adjusted by removing the empty layers that can be in between raft # and the model abs_layer_number = layer.id - min_layer_number abs_layer_number += additional_first_layers if layer.id >= 0 and negative_layers != 0: abs_layer_number += (min_layer_number + negative_layers) layer_data.addLayer(abs_layer_number) this_layer = layer_data.getLayer(abs_layer_number) layer_data.setLayerHeight(abs_layer_number, layer.height) layer_data.setLayerThickness(abs_layer_number, layer.thickness) for p in range(layer.repeatedMessageCount("path_segment")): polygon = layer.getRepeatedMessage("path_segment", p) extruder = polygon.extruder line_types = numpy.fromstring( polygon.line_type, dtype="u1") # Convert bytearray to numpy array line_types = line_types.reshape((-1, 1)) points = numpy.fromstring( polygon.points, dtype="f4") # Convert bytearray to numpy array if polygon.point_type == 0: # Point2D points = points.reshape( (-1, 2) ) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly. elif polygon.point_type == 1: # Point3D points = points.reshape((-1, 3)) else: # Point6D points = points.reshape((-1, 6)) line_widths = numpy.fromstring( polygon.line_width, dtype="f4") # Convert bytearray to numpy array line_widths = line_widths.reshape( (-1, 1) ) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly. line_thicknesses = numpy.fromstring( polygon.line_thickness, dtype="f4") # Convert bytearray to numpy array line_thicknesses = line_thicknesses.reshape( (-1, 1) ) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly. line_feedrates = numpy.fromstring( polygon.line_feedrate, dtype="f4") # Convert bytearray to numpy array line_feedrates = line_feedrates.reshape( (-1, 1) ) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly. # Create a new 3D-array, copy the 2D points over and insert the right height. # This uses manual array creation + copy rather than numpy.insert since this is # faster. if polygon.point_type in [0, 1]: new_points = numpy.empty((len(points), 3), numpy.float32) else: new_points = numpy.empty((len(points), 6), numpy.float32) if polygon.point_type == 0: # Point2D new_points[:, 0] = points[:, 0] new_points[:, 1] = layer.height / 1000 # layer height value is in backend representation new_points[:, 2] = -points[:, 1] elif polygon.point_type == 1: # Point3D new_points[:, 0] = points[:, 0] new_points[:, 1] = points[:, 2] new_points[:, 2] = -points[:, 1] else: new_points[:, 0] = points[:, 0] new_points[:, 1] = points[:, 2] new_points[:, 2] = -points[:, 1] new_points[:, 3] = points[:, 3] new_points[:, 4] = points[:, 5] new_points[:, 5] = -points[:, 4] this_poly = LayerPolygon.LayerPolygon( extruder, line_types, new_points, line_widths, line_thicknesses, line_feedrates) this_poly.buildCache() this_layer.polygons.append(this_poly) Job.yieldThread() Job.yieldThread() contains_arcus_layers = False current_layer += 1 progress = (current_layer / layer_count) * 99 # TODO: Rebuild the layer data mesh once the layer has been processed. # This needs some work in LayerData so we can add the new layers instead of recreating the entire mesh. if self._abort_requested: if self._progress_message: self._progress_message.hide() return if self._progress_message: self._progress_message.setProgress(progress) # We are done processing all the layers we got from the engine, now create a mesh out of the data # Find out colors per extruder global_container_stack = Application.getInstance( ).getGlobalContainerStack() manager = ExtruderManager.getInstance() extruders = manager.getActiveExtruderStacks() if extruders: material_color_map = numpy.zeros((len(extruders), 4), dtype=numpy.float32) for extruder in extruders: position = int( extruder.getMetaDataEntry("position", default="0")) # Get the position try: default_color = ExtrudersModel.defaultColors[position] except IndexError: default_color = "#e0e000" color_code = extruder.material.getMetaDataEntry( "color_code", default=default_color) color = colorCodeToRGBA(color_code) material_color_map[position, :] = color else: # Single extruder via global stack. material_color_map = numpy.zeros((1, 4), dtype=numpy.float32) color_code = global_container_stack.material.getMetaDataEntry( "color_code", default="#e0e000") color = colorCodeToRGBA(color_code) material_color_map[0, :] = color # We have to scale the colors for compatibility mode if OpenGLContext.isLegacyOpenGL() or bool( Application.getInstance().getPreferences().getValue( "view/force_layer_view_compatibility_mode")): line_type_brightness = 0.5 # for compatibility mode else: line_type_brightness = 1.0 layer_mesh = layer_data.build(material_color_map, line_type_brightness) if self._abort_requested: if self._progress_message: self._progress_message.hide() return # Add LayerDataDecorator to scene node to indicate that the node has layer data decorator = LayerDataDecorator.LayerDataDecorator() decorator.setLayerData(layer_mesh) new_node.addDecorator(decorator) new_node.setMeshData(mesh) # Set build volume as parent, the build volume can move as a result of raft settings. # It makes sense to set the build volume as parent: the print is actually printed on it. new_node_parent = Application.getInstance().getBuildVolume() new_node.setParent( new_node_parent) # Note: After this we can no longer abort! settings = Application.getInstance().getGlobalContainerStack() if not settings.getProperty("machine_center_is_zero", "value"): new_node.setPosition( Vector(-settings.getProperty("machine_width", "value") / 2, 0.0, settings.getProperty("machine_depth", "value") / 2)) if self._progress_message: self._progress_message.setProgress(100) if self._progress_message: self._progress_message.hide() # Clear the unparsed layers. This saves us a bunch of memory if the Job does not get destroyed. self._layers = None Logger.log("d", "Processing layers took %s seconds", time() - start_time)
def setVisible(self, visible): if not self._node: return if not self._stack: self._node.addDecorator(SettingOverrideDecorator()) self._stack = self._node.callDecoration("getStack") settings = self._stack.getTop() all_instances = settings.findInstances() visibility_changed = False # Flag to check if at the end the signal needs to be emitted # Remove all instances that are not in visibility list for instance in all_instances: # exceptionally skip setting if instance.definition.key in self._skip_reset_setting_set: continue if instance.definition.key not in visible: settings.removeInstance(instance.definition.key) visibility_changed = True # Add all instances that are not added, but are in visibility list for item in visible: if not settings.getInstance( item): # Setting was not added already. definition = self._stack.getSettingDefinition(item) if definition: new_instance = SettingInstance(definition, settings) stack_nr = -1 stack = None # Check from what stack we should copy the raw property of the setting from. if self._stack.getProperty("machine_extruder_count", "value") > 1: if definition.limit_to_extruder != "-1": # A limit to extruder function was set and it's a multi extrusion machine. Check what stack we do need to use. stack_nr = str( int( round( float( self._stack.getProperty( item, "limit_to_extruder"))))) # Check if the found stack_number is in the extruder list of extruders. if stack_nr not in ExtruderManager.getInstance( ).extruderIds and self._stack.getProperty( "extruder_nr", "value") is not None: stack_nr = -1 # Use the found stack number to get the right stack to copy the value from. if stack_nr in ExtruderManager.getInstance( ).extruderIds: stack = ContainerRegistry.getInstance( ).findContainerStacks( id=ExtruderManager.getInstance( ).extruderIds[stack_nr])[0] else: stack = self._stack # Use the raw property to set the value (so the inheritance doesn't break) if stack is not None: new_instance.setProperty( "value", stack.getRawProperty(item, "value")) else: new_instance.setProperty("value", None) new_instance.resetState( ) # Ensure that the state is not seen as a user state. settings.addInstance(new_instance) visibility_changed = True else: Logger.log( "w", "Unable to add instance (%s) to per-object visibility because we couldn't find the matching definition", item) if visibility_changed: self.visibilityChanged.emit()
def _onProcessCliFinished(self, job: ProcessCliJob): self._message_handlers["cliparser.proto.LayerOptimized"] = self._onOptimizedLayerMessage self._message_handlers["cliparser.proto.Progress"] = self._onProgressMessage self._message_handlers["cliparser.proto.GCodeLayer"] = self._onGCodeLayerMessage self._message_handlers["cliparser.proto.GCodePrefix"] = self._onGCodePrefixMessage self._message_handlers["cliparser.proto.PrintTimeMaterialEstimates"] = self._onPrintTimeMaterialEstimates self._message_handlers["cliparser.proto.SlicingFinished"] = self._onSlicingFinishedMessage if self._error_message: self._error_message.hide() # Note that cancelled slice jobs can still call this method. if self._process_cli_job is job: self._process_cli_job = None if job.isCancelled() or job.getError() or job.getResult() == StartJobResult.Error: self.backendStateChange.emit(BackendState.Error) self.backendError.emit(job) return if job.getResult() == StartJobResult.MaterialIncompatible: if self._application.platformActivity: self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current material as it is incompatible with the selected machine or configuration."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) self.backendError.emit(job) else: self.backendStateChange.emit(BackendState.NotStarted) return if job.getResult() == StartJobResult.SettingError: if self._application.platformActivity: if not self._global_container_stack: Logger.log("w", "Global container stack not assigned to CuraEngineBackend!") return extruders = ExtruderManager.getInstance().getActiveExtruderStacks() error_keys = [] #type: List[str] for extruder in extruders: error_keys.extend(extruder.getErrorKeys()) if not extruders: error_keys = self._global_container_stack.getErrorKeys() error_labels = set() for key in error_keys: for stack in [self._global_container_stack] + extruders: #Search all container stacks for the definition of this setting. Some are only in an extruder stack. definitions = cast(DefinitionContainerInterface, stack.getBottom()).findDefinitions(key = key) if definitions: break #Found it! No need to continue search. else: #No stack has a definition for this setting. Logger.log("w", "When checking settings for errors, unable to find definition for key: {key}".format(key = key)) continue error_labels.add(definitions[0].label) self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice with the current settings. The following settings have errors: {0}").format(", ".join(error_labels)), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) self.backendError.emit(job) else: self.backendStateChange.emit(BackendState.NotStarted) return elif job.getResult() == StartJobResult.ObjectSettingError: errors = {} for node in DepthFirstIterator(self._application.getController().getScene().getRoot()): #type: ignore #Ignore type error because iter() should get called automatically by Python syntax. stack = node.callDecoration("getStack") if not stack: continue for key in stack.getErrorKeys(): if not self._global_container_stack: Logger.log("e", "CuraEngineBackend does not have global_container_stack assigned.") continue definition = cast(DefinitionContainerInterface, self._global_container_stack.getBottom()).findDefinitions(key = key) if not definition: Logger.log("e", "When checking settings for errors, unable to find definition for key {key} in per-object stack.".format(key = key)) continue errors[key] = definition[0].label self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice due to some per-model settings. The following settings have errors on one or more models: {error_labels}").format(error_labels = ", ".join(errors.values())), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) self.backendError.emit(job) return if job.getResult() == StartJobResult.BuildPlateError: if self._application.platformActivity: self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice because the prime tower or prime position(s) are invalid."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) self.backendError.emit(job) else: self.backendStateChange.emit(BackendState.NotStarted) if job.getResult() == StartJobResult.ObjectsWithDisabledExtruder: self._error_message = Message(catalog.i18nc("@info:status", "Unable to slice because there are objects associated with disabled Extruder %s." % job.getMessage()), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) self.backendError.emit(job) return if job.getResult() == StartJobResult.NothingToSlice: if self._application.platformActivity: 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."), title = catalog.i18nc("@info:title", "Unable to slice")) self._error_message.show() self.backendStateChange.emit(BackendState.Error) self.backendError.emit(job) else: self.backendStateChange.emit(BackendState.NotStarted) self._invokeSlice() return # Preparation completed, send it to the backend. self._socket.sendMessage(job.getSliceMessage()) # Notify the user that it's now up to the backend to do it's job self.backendStateChange.emit(BackendState.Processing) self.processingProgress.emit(0.3) if self._slice_start_time: Logger.log("d", "Sending slice message took %s seconds", time() - self._slice_start_time )
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._theme: self._theme = Application.getInstance().getTheme() if not self._enabled_shader: self._enabled_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "overhang.shader")) self._enabled_shader.setUniformValue( "u_overhangColor", Color(*self._theme.getColor("model_overhang").getRgb())) if not self._disabled_shader: self._disabled_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "striped.shader")) self._disabled_shader.setUniformValue( "u_diffuseColor1", Color(*self._theme.getColor("model_unslicable").getRgb())) self._disabled_shader.setUniformValue( "u_diffuseColor2", Color(*self._theme.getColor("model_unslicable_alt").getRgb())) self._disabled_shader.setUniformValue("u_width", 50.0) if not self._non_printing_shader: self._non_printing_shader = OpenGL.getInstance( ).createShaderProgram( Resources.getPath(Resources.Shaders, "transparent_object.shader")) self._non_printing_shader.setUniformValue( "u_diffuseColor", Color(*self._theme.getColor("model_non_printing").getRgb())) self._non_printing_shader.setUniformValue("u_opacity", 0.6) if not self._support_mesh_shader: self._support_mesh_shader = OpenGL.getInstance( ).createShaderProgram( Resources.getPath(Resources.Shaders, "striped.shader")) self._support_mesh_shader.setUniformValue("u_vertical_stripes", True) self._support_mesh_shader.setUniformValue("u_width", 5.0) global_container_stack = Application.getInstance( ).getGlobalContainerStack() if global_container_stack: support_extruder_nr = global_container_stack.getExtruderPositionValueWithDefault( "support_extruder_nr") support_angle_stack = Application.getInstance().getExtruderManager( ).getExtruderStack(support_extruder_nr) if support_angle_stack is not None and Application.getInstance( ).getPreferences().getValue("view/show_overhang"): angle = support_angle_stack.getProperty( "support_angle", "value") # Make sure the overhang angle is valid before passing it to the shader # Note: if the overhang angle is set to its default value, it does not need to get validated (validationState = None) if angle is not None and global_container_stack.getProperty( "support_angle", "validationState") in [None, ValidatorState.Valid]: self._enabled_shader.setUniformValue( "u_overhangAngle", math.cos(math.radians(90 - angle))) else: self._enabled_shader.setUniformValue( "u_overhangAngle", math.cos(math.radians(0)) ) #Overhang angle of 0 causes no area at all to be marked as overhang. else: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(0))) for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): if node.getMeshData() and node.isVisible( ) and not node.callDecoration("getLayerData"): uniforms = {} shade_factor = 1.0 per_mesh_stack = node.callDecoration("getStack") extruder_index = node.callDecoration( "getActiveExtruderPosition") if extruder_index is None: extruder_index = "0" extruder_index = int(extruder_index) # Use the support extruder instead of the active extruder if this is a support_mesh if per_mesh_stack: if per_mesh_stack.getProperty("support_mesh", "value"): extruder_index = int( global_container_stack. getExtruderPositionValueWithDefault( "support_extruder_nr")) try: material_color = self._extruders_model.getItem( extruder_index)["color"] except KeyError: material_color = self._extruders_model.defaultColors[0] if extruder_index != ExtruderManager.getInstance( ).activeExtruderIndex: # Shade objects that are printed with the non-active extruder 25% darker shade_factor = 0.6 try: # Colors are passed as rgb hex strings (eg "#ffffff"), and the shader needs # an rgba list of floats (eg [1.0, 1.0, 1.0, 1.0]) uniforms["diffuse_color"] = [ shade_factor * int(material_color[1:3], 16) / 255, shade_factor * int(material_color[3:5], 16) / 255, shade_factor * int(material_color[5:7], 16) / 255, 1.0 ] except ValueError: pass if node.callDecoration("isNonPrintingMesh"): if per_mesh_stack and (per_mesh_stack.getProperty( "infill_mesh", "value") or per_mesh_stack.getProperty( "cutting_mesh", "value")): renderer.queueNode( node, shader=self._non_printing_shader, uniforms=uniforms, transparent=True) else: renderer.queueNode( node, shader=self._non_printing_shader, transparent=True) elif getattr(node, "_outside_buildarea", False): renderer.queueNode(node, shader=self._disabled_shader) elif per_mesh_stack and per_mesh_stack.getProperty( "support_mesh", "value"): # Render support meshes with a vertical stripe that is darker shade_factor = 0.6 uniforms["diffuse_color_2"] = [ uniforms["diffuse_color"][0] * shade_factor, uniforms["diffuse_color"][1] * shade_factor, uniforms["diffuse_color"][2] * shade_factor, 1.0 ] renderer.queueNode(node, shader=self._support_mesh_shader, uniforms=uniforms) else: renderer.queueNode(node, shader=self._enabled_shader, uniforms=uniforms) if node.callDecoration("isGroup") and Selection.isSelected( node): renderer.queueNode(scene.getRoot(), mesh=node.getBoundingBoxMesh(), mode=RenderBatch.RenderMode.LineLoop)
def _convertSavitarNodeToUMNode(self, savitar_node): self._object_count += 1 node_name = "Object %s" % self._object_count active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate um_node = SteSlicerSceneNode() # This adds a SettingOverrideDecorator um_node.addDecorator(BuildPlateDecorator(active_build_plate)) um_node.setName(node_name) transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation()) um_node.setTransformation(transformation) mesh_builder = MeshBuilder() data = numpy.fromstring(savitar_node.getMeshData().getFlatVerticesAsBytes(), dtype=numpy.float32) vertices = numpy.resize(data, (int(data.size / 3), 3)) mesh_builder.setVertices(vertices) mesh_builder.calculateNormals(fast=True) mesh_data = mesh_builder.build() if len(mesh_data.getVertices()): um_node.setMeshData(mesh_data) for child in savitar_node.getChildren(): child_node = self._convertSavitarNodeToUMNode(child) if child_node: um_node.addChild(child_node) if um_node.getMeshData() is None and len(um_node.getChildren()) == 0: return None settings = savitar_node.getSettings() # Add the setting override decorator, so we can add settings to this node. if settings: global_container_stack = Application.getInstance().getGlobalContainerStack() # Ensure the correct next container for the SettingOverride decorator is set. if global_container_stack: default_stack = ExtruderManager.getInstance().getExtruderStack(0) if default_stack: um_node.callDecoration("setActiveExtruder", default_stack.getId()) # Get the definition & set it definition_id = getMachineDefinitionIDForQualitySearch(global_container_stack.definition) um_node.callDecoration("getStack").getTop().setDefinition(definition_id) setting_container = um_node.callDecoration("getStack").getTop() for key in settings: setting_value = settings[key] # Extruder_nr is a special case. if key == "extruder_nr": extruder_stack = ExtruderManager.getInstance().getExtruderStack(int(setting_value)) if extruder_stack: um_node.callDecoration("setActiveExtruder", extruder_stack.getId()) else: Logger.log("w", "Unable to find extruder in position %s", setting_value) continue setting_container.setProperty(key, "value", setting_value) if len(um_node.getChildren()) > 0 and um_node.getMeshData() is None: group_decorator = GroupDecorator() um_node.addDecorator(group_decorator) um_node.setSelectable(True) if um_node.getMeshData(): # Assuming that all nodes with mesh data are printable objects # affects (auto) slicing sliceable_decorator = SliceableObjectDecorator() um_node.addDecorator(sliceable_decorator) return um_node