def _updateWithPreferences(self): self._solid_layers = int( Preferences.getInstance().getValue("view/top_layer_count")) self._only_show_top_layers = bool( Preferences.getInstance().getValue("view/only_show_top_layers")) self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool( Preferences.getInstance().getValue( "view/force_layer_view_compatibility_mode")) self.setSimulationViewType( int( float(Preferences.getInstance().getValue( "layerview/layer_view_type")))) for extruder_nr, extruder_opacity in enumerate( Preferences.getInstance().getValue( "layerview/extruder_opacities").split("|")): try: opacity = float(extruder_opacity) except ValueError: opacity = 1.0 self.setExtruderOpacity(extruder_nr, opacity) self.setShowTravelMoves( bool(Preferences.getInstance().getValue( "layerview/show_travel_moves"))) self.setShowHelpers( bool(Preferences.getInstance().getValue("layerview/show_helpers"))) self.setShowSkin( bool(Preferences.getInstance().getValue("layerview/show_skin"))) self.setShowInfill( bool(Preferences.getInstance().getValue("layerview/show_infill"))) self._startUpdateTopLayers() self.preferencesChanged.emit()
def getSimulationPass(self): if not self._layer_pass: # Currently the RenderPass constructor requires a size > 0 # This should be fixed in RenderPass's constructor. self._layer_pass = SimulationPass(1, 1) self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode")) self._layer_pass.setSimulationView(self) return self._layer_pass
def getSimulationPass(self): if not self._layer_pass: # Currently the RenderPass constructor requires a size > 0 # This should be fixed in RenderPass's constructor. self._layer_pass = SimulationPass(1, 1) self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode")) self._layer_pass.setSimulationView(self) return self._layer_pass
def createShaderProgram(self, file_name): shader = ShaderProgram.ShaderProgram() # The version_string must match the keys in shader files. if OpenGLContext.isLegacyOpenGL(): version_string = "" # Nothing is added to "fragment" and "vertex" else: version_string = "41core" shader.load(file_name, version=version_string) return shader
def createShaderProgram(self, file_name: str) -> ShaderProgram: shader = ShaderProgram() # The version_string must match the keys in shader files. if OpenGLContext.isLegacyOpenGL(): version_string = "" # Nothing is added to "fragment" and "vertex" else: version_string = "41core" try: shader.load(file_name, version = version_string) except InvalidShaderProgramError: # If the loading failed, it could be that there is no specific shader for this version. # Try again without a version nr to get the generic one. if version_string != "": shader.load(file_name, version = "") return shader
def createShaderProgram(self, file_name: str) -> ShaderProgram: shader = ShaderProgram() # The version_string must match the keys in shader files. if OpenGLContext.isLegacyOpenGL(): version_string = "" # Nothing is added to "fragment" and "vertex" else: version_string = "41core" try: shader.load(file_name, version=version_string) except InvalidShaderProgramError: # If the loading failed, it could be that there is no specific shader for this version. # Try again without a version nr to get the generic one. if version_string != "": shader.load(file_name, version="") return shader
def _onPreferencesChanged(self, preference): if preference not in { "view/top_layer_count", "view/only_show_top_layers", "view/force_layer_view_compatibility_mode" }: return self._solid_layers = int( Preferences.getInstance().getValue("view/top_layer_count")) self._only_show_top_layers = bool( Preferences.getInstance().getValue("view/only_show_top_layers")) self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool( Preferences.getInstance().getValue( "view/force_layer_view_compatibility_mode")) self._startUpdateTopLayers() self.preferencesChanged.emit()
def _updateWithPreferences(self): self._solid_layers = int( Preferences.getInstance().getValue("view/top_layer_count")) self._only_show_top_layers = bool( Preferences.getInstance().getValue("view/only_show_top_layers")) self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool( Preferences.getInstance().getValue( "view/force_layer_view_compatibility_mode")) self.setLayerViewType( int( float(Preferences.getInstance().getValue( "layerview/layer_view_type")))) self.setExtruderOpacity( 0, float(Preferences.getInstance().getValue( "layerview/extruder0_opacity"))) self.setExtruderOpacity( 1, float(Preferences.getInstance().getValue( "layerview/extruder1_opacity"))) self.setExtruderOpacity( 2, float(Preferences.getInstance().getValue( "layerview/extruder2_opacity"))) self.setExtruderOpacity( 3, float(Preferences.getInstance().getValue( "layerview/extruder3_opacity"))) self.setShowTravelMoves( bool(Preferences.getInstance().getValue( "layerview/show_travel_moves"))) self.setShowHelpers( bool(Preferences.getInstance().getValue("layerview/show_helpers"))) self.setShowSkin( bool(Preferences.getInstance().getValue("layerview/show_skin"))) self.setShowInfill( bool(Preferences.getInstance().getValue("layerview/show_infill"))) self._startUpdateTopLayers() self.preferencesChanged.emit()
def _updateWithPreferences(self): self._solid_layers = int(Preferences.getInstance().getValue("view/top_layer_count")) self._only_show_top_layers = bool(Preferences.getInstance().getValue("view/only_show_top_layers")) self._compatibility_mode = OpenGLContext.isLegacyOpenGL() or bool( Preferences.getInstance().getValue("view/force_layer_view_compatibility_mode")) self.setLayerViewType(int(float(Preferences.getInstance().getValue("layerview/layer_view_type")))); for extruder_nr, extruder_opacity in enumerate(Preferences.getInstance().getValue("layerview/extruder_opacities").split("|")): try: opacity = float(extruder_opacity) except ValueError: opacity = 1.0 self.setExtruderOpacity(extruder_nr, opacity) self.setShowTravelMoves(bool(Preferences.getInstance().getValue("layerview/show_travel_moves"))) self.setShowHelpers(bool(Preferences.getInstance().getValue("layerview/show_helpers"))) self.setShowSkin(bool(Preferences.getInstance().getValue("layerview/show_skin"))) self.setShowInfill(bool(Preferences.getInstance().getValue("layerview/show_infill"))) self._startUpdateTopLayers() self.preferencesChanged.emit()
def createShaderProgram(self, file_name: str) -> Optional[ShaderProgram]: """Create a ShaderProgram Object. This should return an implementation-specifc ShaderProgram subclass. """ shader = ShaderProgram() # The version_string must match the keys in shader files. if OpenGLContext.isLegacyOpenGL(): version_string = "" # Nothing is added to "fragment" and "vertex" else: version_string = "41core" try: shader.load(file_name, version=version_string) except InvalidShaderProgramError: # If the loading failed, it could be that there is no specific shader for this version. # Try again without a version nr to get the generic one. if version_string != "": try: shader.load(file_name, version="") except InvalidShaderProgramError as e: Logger.logException("e", str(e)) return None return shader
def run(self): start_time = time() if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView": self._progress = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, -1) self._progress.show() Job.yieldThread() if self._abort_requested: if self._progress: self._progress.hide() return Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) new_node = SceneNode() ## Remove old layer data (if any) for node in DepthFirstIterator(self._scene.getRoot()): if node.callDecoration("getLayerData"): node.getParent().removeChild(node) break if self._abort_requested: if self._progress: self._progress.hide() return # 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 using a raft, the raft layers are sent as layers < 0. Instead of allowing layers < 0, we # instead simply offset all other layers so the lowest layer is always 0. min_layer_number = 0 for layer in self._layers: if layer.id < min_layer_number: min_layer_number = layer.id current_layer = 0 for layer in self._layers: abs_layer_number = layer.id + abs(min_layer_number) layer_data.addLayer(abs_layer_number) this_layer = layer_data.getLayer(abs_layer_number) layer_data.setLayerHeight(abs_layer_number, layer.height) 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. else: # Point3D points = points.reshape((-1,3)) 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. # In the future, line_thicknesses should be given by CuraEngine as well. # Currently the infill layer thickness also translates to line width line_thicknesses = numpy.zeros(line_widths.shape, dtype="f4") line_thicknesses[:] = layer.thickness / 1000 # from micrometer to millimeter # 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. new_points = numpy.empty((len(points), 3), 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] else: # Point3D new_points[:, 0] = points[:, 0] new_points[:, 1] = points[:, 2] new_points[:, 2] = -points[:, 1] this_poly = LayerPolygon.LayerPolygon(extruder, line_types, new_points, line_widths, line_thicknesses) this_poly.buildCache() this_layer.polygons.append(this_poly) Job.yieldThread() Job.yieldThread() 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: self._progress.hide() return if self._progress: self._progress.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 = list(manager.getMachineExtruders(global_container_stack.getId())) if extruders: material_color_map = numpy.zeros((len(extruders), 4), dtype=numpy.float32) for extruder in extruders: material = extruder.findContainer({"type": "material"}) position = int(extruder.getMetaDataEntry("position", default="0")) # Get the position color_code = material.getMetaDataEntry("color_code", default="#e0e000") 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) material = global_container_stack.findContainer({"type": "material"}) color_code = "#e0e000" if material: if material.getMetaDataEntry("color_code") is not None: color_code = material.getMetaDataEntry("color_code") color = colorCodeToRGBA(color_code) material_color_map[0, :] = color # We have to scale the colors for compatibility mode if OpenGLContext.isLegacyOpenGL() or bool(Preferences.getInstance().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: self._progress.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: self._progress.setProgress(100) view = Application.getInstance().getController().getActiveView() if view.getPluginId() == "LayerView": view.resetLayerData() if self._progress: self._progress.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 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 = CuraSceneNode(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 layer.repeatedMessageCount("path_segment") > 0: if layer.id < min_layer_number: min_layer_number = layer.id if layer.id < 0: negative_layers += 1 current_layer = 0 for layer in self._layers: # 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 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. else: # Point3D points = points.reshape((-1,3)) 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. new_points = numpy.empty((len(points), 3), 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] else: # Point3D new_points[:, 0] = points[:, 0] new_points[:, 1] = points[:, 2] new_points[:, 2] = -points[:, 1] 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() 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")) 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 _evaluateCompatibilityMode(self) -> bool: return OpenGLContext.isLegacyOpenGL() or bool( Application.getInstance().getPreferences().getValue( "view/force_layer_view_compatibility_mode"))
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 = CuraSceneNode(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 layer.repeatedMessageCount("path_segment") > 0: if layer.id < min_layer_number: min_layer_number = layer.id if layer.id < 0: negative_layers += 1 current_layer = 0 for layer in self._layers: # 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 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. else: # Point3D points = points.reshape((-1, 3)) 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. new_points = numpy.empty((len(points), 3), 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] else: # Point3D new_points[:, 0] = points[:, 0] new_points[:, 1] = points[:, 2] new_points[:, 2] = -points[:, 1] 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() 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")) 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 test_isLegacyOpenGl(major_version, minor_version, result): OpenGLContext.major_version = major_version OpenGLContext.minor_version = minor_version assert OpenGLContext.isLegacyOpenGL() == result
def _evaluateCompatibilityMode(self): return OpenGLContext.isLegacyOpenGL() or bool(Application.getInstance().getPreferences().getValue("view/force_layer_view_compatibility_mode"))
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 = CuraSceneNode(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 using a raft, the raft layers are sent as layers < 0. Instead of allowing layers < 0, we # instead 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 = 0 negative_layers = 0 for layer in self._layers: if layer.id < min_layer_number: min_layer_number = layer.id if layer.id < 0: negative_layers += 1 current_layer = 0 for layer in self._layers: # Negative layers are offset by the minimum layer number, but the positive layers are just # offset by the number of negative layers so there is no layer gap between raft and model abs_layer_number = layer.id + abs( min_layer_number ) if layer.id < 0 else layer.id + 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. else: # Point3D points = points.reshape((-1, 3)) 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. global_container_stack = Application.getInstance( ).getGlobalContainerStack() half_outer_wall_thickness = global_container_stack.getProperty( "wall_line_width_0", "value") / 2 # Adjust layer data to show Raft line type, if it is enabled if global_container_stack.getProperty("blackbelt_raft", "value"): raft_thickness = global_container_stack.getProperty( "blackbelt_raft_thickness", "value") extrusion_started = False for index, segment_type in enumerate(line_types): if points[index + 1][ 1] <= half_outer_wall_thickness + raft_thickness: if segment_type in [ LayerPolygon.LayerPolygon.Inset0Type, LayerPolygon.LayerPolygon.InsetXType ]: line_types[ index] = LayerPolygon.LayerPolygon.SkirtType extrusion_started = True elif extrusion_started: break # Adjust layer data to show Belt Wall feed rate, if it is enabled if global_container_stack.getProperty( "blackbelt_belt_wall_enabled", "value"): belt_wall_feedrate = global_container_stack.getProperty( "blackbelt_belt_wall_speed", "value") belt_wall_indices = [] for index, point in enumerate(points): if point[1] <= half_outer_wall_thickness: if last_point_hit_wall and line_feedrates[ index - 1] > belt_wall_feedrate: belt_wall_indices.append(index) last_point_hit_wall = True else: last_point_hit_wall = False dimensionality = points.shape[1] edited_points = points.flatten() line_types = line_types.flatten() line_widths = line_widths.flatten() line_thicknesses = line_thicknesses.flatten() line_feedrates = line_feedrates.flatten() for index in reversed(belt_wall_indices): edited_points = numpy.insert( edited_points, dimensionality * (index), numpy.append(points[index - 1], points[index])) line_types = numpy.insert(line_types, index, [line_types[index - 1]] * 2) line_widths = numpy.insert( line_widths, index, [line_widths[index - 1]] * 2) line_thicknesses = numpy.insert( line_thicknesses, index, [line_thicknesses[index - 1]] * 2) line_feedrates = numpy.insert(line_feedrates, index - 1, [belt_wall_feedrate] * 2) # Fix shape of adjusted data if polygon.point_type == 0: points = edited_points.reshape( (-1, 2) ) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly. else: points = edited_points.reshape((-1, 3)) line_types = line_types.reshape((-1, 1)) line_widths = line_widths.reshape((-1, 1)) line_thicknesses = line_thicknesses.reshape((-1, 1)) line_feedrates = line_feedrates.reshape((-1, 1)) # 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. new_points = numpy.empty((len(points), 3), 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] else: # Point3D new_points[:, 0] = points[:, 0] new_points[:, 1] = points[:, 2] new_points[:, 2] = -points[:, 1] 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() 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 = list( manager.getMachineExtruders(global_container_stack.getId())) 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(Preferences.getInstance( ).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)) transform = self._scene.getRoot().callDecoration("getTransformMatrix") if transform and transform != Matrix(): transform_matrix = new_node.getLocalTransformation().preMultiply( transform.getInverse()) new_node.setTransformation(transform_matrix) front_offset = self._scene.getRoot().callDecoration( "getSceneFrontOffset") if global_container_stack.getProperty("blackbelt_raft", "value"): front_offset = front_offset - global_container_stack.getProperty("blackbelt_raft_margin", "value") \ - global_container_stack.getProperty("blackbelt_raft_thickness", "value") new_node.translate(Vector(0, 0, front_offset), SceneNode.TransformSpace.World) 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 isLegacyOpenGL(self): return OpenGLContext.isLegacyOpenGL()
def isLegacyOpenGL(self): return OpenGLContext.isLegacyOpenGL()
def run(self): start_time = time() if Application.getInstance().getController().getActiveView().getPluginId() == "LayerView": self._progress = Message(catalog.i18nc("@info:status", "Processing Layers"), 0, False, -1) self._progress.show() Job.yieldThread() if self._abort_requested: if self._progress: self._progress.hide() return Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged) new_node = SceneNode() ## Remove old layer data (if any) for node in DepthFirstIterator(self._scene.getRoot()): if node.callDecoration("getLayerData"): node.getParent().removeChild(node) break if self._abort_requested: if self._progress: self._progress.hide() return # 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 using a raft, the raft layers are sent as layers < 0. Instead of allowing layers < 0, we # instead simply offset all other layers so the lowest layer is always 0. min_layer_number = 0 for layer in self._layers: if layer.id < min_layer_number: min_layer_number = layer.id current_layer = 0 for layer in self._layers: abs_layer_number = layer.id + abs(min_layer_number) layer_data.addLayer(abs_layer_number) this_layer = layer_data.getLayer(abs_layer_number) layer_data.setLayerHeight(abs_layer_number, layer.height) 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. else: # Point3D points = points.reshape((-1,3)) 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. # In the future, line_thicknesses should be given by CuraEngine as well. # Currently the infill layer thickness also translates to line width line_thicknesses = numpy.zeros(line_widths.shape, dtype="f4") line_thicknesses[:] = layer.thickness / 1000 # from micrometer to millimeter # 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. new_points = numpy.empty((len(points), 3), 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] else: # Point3D new_points[:, 0] = points[:, 0] new_points[:, 1] = points[:, 2] new_points[:, 2] = -points[:, 1] this_poly = LayerPolygon.LayerPolygon(extruder, line_types, new_points, line_widths, line_thicknesses) this_poly.buildCache() this_layer.polygons.append(this_poly) Job.yieldThread() Job.yieldThread() 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: self._progress.hide() return if self._progress: self._progress.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 = list(manager.getMachineExtruders(global_container_stack.getId())) 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 KeyError: 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(Preferences.getInstance().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: self._progress.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: self._progress.setProgress(100) view = Application.getInstance().getController().getActiveView() if view.getPluginId() == "LayerView": view.resetLayerData() if self._progress: self._progress.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)