def _pixelSelection(self, event): pixel_id = self._renderer.getIdAtCoordinate(event.x, event.y) if not pixel_id: Selection.clear() return for node in BreadthFirstIterator(self._scene.getRoot()): if id(node) == pixel_id: if self._ctrl_is_active: if Selection.isSelected(node): if node.getParent(): if node.getParent().callDecoration("isGroup"): Selection.remove(node.getParent()) else: Selection.remove(node) else: Selection.add(node) if node.getParent(): if node.getParent().callDecoration("isGroup"): Selection.add(node.getParent()) else: Selection.add(node) else: if not Selection.isSelected(node) or Selection.getCount() > 1: Selection.clear() if node.getParent(): if node.getParent().callDecoration("isGroup"): Selection.add(node.getParent()) else: Selection.add(node)
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() renderer.setRenderSelection(False) if not self._material: self._material = renderer.createMaterial(Resources.getPath(Resources.Shaders, "basic.vert"), Resources.getPath(Resources.Shaders, "vertexcolor.frag")) self._material.setUniformValue("u_color", [1.0, 0.0, 0.0, 1.0]) self._selection_material = renderer.createMaterial(Resources.getPath(Resources.Shaders, "basic.vert"), Resources.getPath(Resources.Shaders, "color.frag")) self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128)) for node in DepthFirstIterator(scene.getRoot()): # We do not want to render ConvexHullNode as it conflicts with the bottom layers. # However, it is somewhat relevant when the node is selected, so do render it then. if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()): continue if not node.render(renderer): if node.getMeshData() and node.isVisible(): if Selection.isSelected(node): renderer.queueNode(node, material = self._selection_material, transparent = True) layer_data = node.callDecoration("getLayerData") if not layer_data: continue # Render all layers below a certain number as line mesh instead of vertices. if self._current_layer_num - self._solid_layers > -1: start = 0 end = 0 element_counts = layer_data.getElementCounts() for layer, counts in element_counts.items(): if layer + self._solid_layers > self._current_layer_num: break end += counts # This uses glDrawRangeElements internally to only draw a certain range of lines. renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end) # We currently recreate the current "solid" layers every time a if not self._current_layer_mesh: self._current_layer_mesh = MeshData() for i in range(self._solid_layers): layer = self._current_layer_num - i if layer < 0: continue layer_mesh = layer_data.getLayer(layer).createMesh() if not layer_mesh or layer_mesh.getVertices() is None: continue self._current_layer_mesh.addVertices(layer_mesh.getVertices()) # Scale layer color by a brightness factor based on the current layer number # This will result in a range of 0.5 - 1.0 to multiply colors by. brightness = (2.0 - (i / self._solid_layers)) / 2.0 self._current_layer_mesh.addColors(layer_mesh.getColors() * brightness) renderer.queueNode(node, mesh = self._current_layer_mesh, material = self._material)
def _pixelSelection(self, event): # Find a node id by looking at a pixel value at the requested location if self._selection_pass: item_id = self._selection_pass.getIdAtPosition(event.x, event.y) else: Logger.log("w", "Selection pass is None. getRenderPass('selection') returned None") return False if not item_id and not self._shift_is_active: if Selection.hasSelection(): Selection.clear() return True return False # Nothing was selected before and the user didn't click on an object. # Find the scene-node which matches the node-id for node in BreadthFirstIterator(self._scene.getRoot()): if id(node) != item_id: continue if self._isNodeInGroup(node): is_selected = Selection.isSelected(self._findTopGroupNode(node)) else: is_selected = Selection.isSelected(node) if self._shift_is_active: if is_selected: # Deselect the SceneNode and its siblings in a group if node.getParent(): if self._ctrl_is_active or not self._isNodeInGroup(node): Selection.remove(node) else: Selection.remove(self._findTopGroupNode(node)) return True else: # Select the SceneNode and its siblings in a group if node.getParent(): if self._ctrl_is_active or not self._isNodeInGroup(node): Selection.add(node) else: Selection.add(self._findTopGroupNode(node)) return True else: if not is_selected or Selection.getCount() > 1: # Select only the SceneNode and its siblings in a group Selection.clear() if node.getParent(): if self._ctrl_is_active or not self._isNodeInGroup(node): Selection.add(node) else: Selection.add(self._findTopGroupNode(node)) return True elif self._isNodeInGroup(node) and self._ctrl_is_active: Selection.clear() Selection.add(node) return True return False
def updateList(self, trigger_node): for root_child in self._scene.getRoot().getChildren(): if root_child.callDecoration( "isGroup"): # Check if its a group node #if root_child.hasChildren(): #Check if it has children (only show it if it has) parent_key = id(root_child) for node in DepthFirstIterator(root_child): if root_child in self._collapsed_nodes: self._collapsed_nodes.append(node) data = { "name": node.getName(), "visibility": node.isVisible(), "key": (id(node)), "selected": Selection.isSelected(node), "collapsed": node in self._collapsed_nodes, "parent_key": parent_key, "is_group": bool(node.callDecoration("isGroup")) } index = self.find("key", (id(node))) parent_index = self.find("key", data["parent_key"]) num_children = 0 for parent_node in Application.getInstance().getController( ).getScene().getRoot().getAllChildren(): if id(parent_node) == data["parent_key"]: num_children = len(parent_node.getChildren()) if parent_index != -1: corrected_index = parent_index + num_children else: corrected_index = 0 if index is not None and index >= 0: self.removeItem(index) self.insertItem(index, data) else: self.insertItem(corrected_index, data) #self.appendItem(data) elif type(root_child) is SceneNode or type( root_child) is PointCloudNode: data = { "name": root_child.getName(), "visibility": root_child.isVisible(), "key": (id(root_child)), "selected": Selection.isSelected(root_child), "collapsed": root_child in self._collapsed_nodes, "parent_key": 0, "is_group": bool(root_child.callDecoration("isGroup")) } # Check if data exists, if yes, remove old and re-add. index = self.find("key", (id(root_child))) if index is not None and index >= 0: self.removeItem(index) self.insertItem(index, data) else: self.appendItem(data) '''for node in DepthFirstIterator(group_node):
def updateList(self, trigger_node): self.clear() for root_child in self._scene.getRoot().getChildren(): if root_child.callDecoration( "isGroup"): # Check if its a group node parent_key = id(root_child) for node in DepthFirstIterator(root_child): if root_child in self._collapsed_nodes: self._collapsed_nodes.append(node) data = { "name": node.getName(), "visibility": node.isVisible(), "key": (id(node)), "selected": Selection.isSelected(node), "collapsed": node in self._collapsed_nodes, "parent_key": parent_key, "is_group": bool(node.callDecoration("isGroup")), "is_dummy": False } self.appendItem(data) data = { "name": "Dummy " + root_child.getName(), "visibility": True, "key": 0, "selected": Selection.isSelected(node), "collapsed": root_child in self._collapsed_nodes, "parent_key": parent_key, "is_group": False, "is_dummy": True } self.appendItem(data) elif type(root_child) is SceneNode or type( root_child) is PointCloudNode: # Item is not a group node. data = { "name": root_child.getName(), "visibility": root_child.isVisible(), "key": (id(root_child)), "selected": Selection.isSelected(root_child), "collapsed": root_child in self._collapsed_nodes, "parent_key": 0, "is_group": bool(root_child.callDecoration("isGroup")), "is_dummy": False } # Check if data exists, if yes, remove old and re-add. index = self.find("key", (id(root_child))) if index is not None and index >= 0: self.removeItem(index) self.insertItem(index, data) else: self.appendItem(data)
def test_UndoRedoWithSelection(): node = SceneNode() parent_node = SceneNode() Selection.add(node) operation = AddSceneNodeOperation(node, parent_node) operation.undo() assert not Selection.isSelected(node) operation.redo() assert Selection.isSelected(node)
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._selection_shader: self._selection_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "color.shader")) self._selection_shader.setUniformValue("u_color", Color(32, 32, 32, 128)) for node in DepthFirstIterator(scene.getRoot()): # We do not want to render ConvexHullNode as it conflicts with the bottom layers. # However, it is somewhat relevant when the node is selected, so do render it then. if type(node) is ConvexHullNode and not Selection.isSelected( node.getWatchedNode()): continue if not node.render(renderer): if node.getMeshData() and node.isVisible(): if Selection.isSelected(node): renderer.queueNode(node, transparent=True, shader=self._selection_shader) layer_data = node.callDecoration("getLayerData") if not layer_data: continue # Render all layers below a certain number as line mesh instead of vertices. if self._current_layer_num - self._solid_layers > -1: start = 0 end = 0 element_counts = layer_data.getElementCounts() for layer, counts in element_counts.items(): if layer + self._solid_layers > self._current_layer_num: break end += counts # This uses glDrawRangeElements internally to only draw a certain range of lines. renderer.queueNode(node, mesh=layer_data, mode=RenderBatch.RenderMode.Lines, range=(start, end)) if self._current_layer_mesh: renderer.queueNode(node, mesh=self._current_layer_mesh) if self._current_layer_jumps: renderer.queueNode(node, mesh=self._current_layer_jumps)
def updateList(self, trigger_node): self.clear() for root_child in self._scene.getRoot().getChildren(): if root_child.callDecoration("isGroup"): # Check if its a group node parent_key = id(root_child) for node in DepthFirstIterator(root_child): if root_child in self._collapsed_nodes: self._collapsed_nodes.append(node) data = {"name":node.getName(), "visibility": node.isVisible(), "key": (id(node)), "selected": Selection.isSelected(node), "collapsed": node in self._collapsed_nodes, "parent_key": parent_key, "is_group":bool(node.callDecoration("isGroup")), "is_dummy" : False } self.appendItem(data) data = { "name":"Dummy", "visibility": True, "key": 0, "selected": Selection.isSelected(node), "collapsed": root_child in self._collapsed_nodes, "parent_key": parent_key, "is_group":False, "is_dummy" : True } self.appendItem(data) elif type(root_child) is SceneNode or type(root_child) is PointCloudNode: # Item is not a group node. data = {"name":root_child.getName(), "visibility": root_child.isVisible(), "key": (id(root_child)), "selected": Selection.isSelected(root_child), "collapsed": root_child in self._collapsed_nodes, "parent_key": 0, "is_group":bool(root_child.callDecoration("isGroup")), "is_dummy" : False } # Check if data exists, if yes, remove old and re-add. index = self.find("key",(id(root_child))) if index is not None and index >= 0: self.removeItem(index) self.insertItem(index,data) else: self.appendItem(data)
def _onSelectedFaceChanged(self, current_surface=None): """ Gets face id and triangles from current face selection """ if getPrintableNodes() and Selection.isSelected(getPrintableNodes( )[0]): # Fixes bug for when scene is unselected if not self.getEnabled() or not self._select: return if self._bc_list is None: return bc_node = self._bc_list.getActiveNode() if bc_node is None: return try: selected_face, axis = self._getSelectedTriangles( current_surface, bc_node.surface_type) except Exception as exc: Logger.logException("e", "Unable to select face") selected_face = None if selected_face is not None: bc_node.selection = Selection.getSelectedFace() bc_node.setMeshDataFromPywimTriangles(selected_face, axis) self.selectedFaceChanged.emit(bc_node)
def changeSelection(self, index): modifiers = QApplication.keyboardModifiers() ctrl_is_active = modifiers & Qt.ControlModifier shift_is_active = modifiers & Qt.ShiftModifier if ctrl_is_active: item = self._objects_model.getItem(index) node = item["node"] if Selection.isSelected(node): Selection.remove(node) else: Selection.add(node) elif shift_is_active: polarity = 1 if index + 1 > self._last_selected_index else -1 for i in range(self._last_selected_index, index + polarity, polarity): item = self._objects_model.getItem(i) node = item["node"] Selection.add(node) else: # Single select item = self._objects_model.getItem(index) node = item["node"] build_plate_number = node.callDecoration("getBuildPlateNumber") if build_plate_number is not None and build_plate_number != -1: self.setActiveBuildPlate(build_plate_number) Selection.clear() Selection.add(node) self._last_selected_index = index
def setSelected(self, key): for index in range(0,len(self.items)): if self.items[index]["key"] == key: for node in Application.getInstance().getController().getScene().getRoot().getAllChildren(): if id(node) == key: if node not in Selection.getAllSelectedObjects(): #node already selected Selection.add(node) if self.items[index]["depth"] == 1: #Its a group node for child_node in node.getChildren(): if child_node not in Selection.getAllSelectedObjects(): #Set all children to parent state (if they arent already) Selection.add(child_node) else: Selection.remove(node) if self.items[index]["depth"] == 1: #Its a group for child_node in node.getChildren(): if child_node in Selection.getAllSelectedObjects(): Selection.remove(child_node) all_children_selected = True #Check all group nodes to see if all their children are selected (if so, they also need to be selected!) for index in range(0,len(self.items)): if self.items[index]["depth"] == 1: for node in Application.getInstance().getController().getScene().getRoot().getAllChildren(): if node.hasChildren(): if id(node) == self.items[index]["key"] and id(node) != key: for index, child_node in enumerate(node.getChildren()): if not Selection.isSelected(child_node): all_children_selected = False #At least one of its children is not selected, dont change state break if all_children_selected: Selection.add(node) else: Selection.remove(node) #Force update self.updateList(Application.getInstance().getController().getScene().getRoot())
def _isInSelectedGroup(self, node): group_node = node.getParent() while group_node.callDecoration("isGroup"): if Selection.isSelected(group_node): return True group_node = group_node.getParent() return False
def _update(self, *args): nodes = [] filter_current_build_plate = Preferences.getInstance().getValue( "view/filter_current_build_plate") active_build_plate_number = self._build_plate_number for node in DepthFirstIterator(Application.getInstance().getController( ).getScene().getRoot()): if not issubclass(type(node), SceneNode) or ( not node.getMeshData() and not node.callDecoration("getLayerData")): continue if not node.callDecoration("isSliceable"): continue node_build_plate_number = node.callDecoration( "getBuildPlateNumber") if filter_current_build_plate and node_build_plate_number != active_build_plate_number: continue nodes.append({ "name": node.getName(), "isSelected": Selection.isSelected(node), "isOutsideBuildArea": node.isOutsideBuildArea(), "buildPlateNumber": node_build_plate_number, "node": node }) nodes = sorted(nodes, key=lambda n: n["name"]) self.setItems(nodes) self.itemsChanged.emit()
def _replaceSceneNode(self, existing_node, trimeshes): name = existing_node.getName() file_name = existing_node.getMeshData().getFileName() transformation = existing_node.getWorldTransformation() parent = existing_node.getParent() extruder_id = existing_node.callDecoration("getActiveExtruder") build_plate = existing_node.callDecoration("getBuildPlateNumber") selected = Selection.isSelected(existing_node) op = GroupedOperation() op.addOperation(RemoveSceneNodeOperation(existing_node)) for i, tri_node in enumerate(trimeshes): mesh_data = self._toMeshData(tri_node) new_node = CuraSceneNode() new_node.setSelectable(True) new_node.setMeshData(mesh_data) new_node.setName(name if i == 0 else "%s %d" % (name, i)) new_node.callDecoration("setActiveExtruder", extruder_id) new_node.addDecorator(BuildPlateDecorator(build_plate)) new_node.addDecorator(SliceableObjectDecorator()) op.addOperation(AddSceneNodeOperation(new_node, parent)) op.addOperation( SetTransformMatrixOperation(new_node, transformation)) if selected: Selection.add(new_node) op.push()
def beginRendering(self) -> None: scene = self.getController().getScene() renderer = self.getRenderer() if renderer is None: return if not self._ghost_shader: self._ghost_shader = OpenGL.getInstance().createShaderProgram( Resources.getPath(Resources.Shaders, "color.shader")) theme = CuraApplication.getInstance().getTheme() if theme is not None: self._ghost_shader.setUniformValue( "u_color", Color(*theme.getColor("layerview_ghost").getRgb())) for node in DepthFirstIterator(scene.getRoot()): # We do not want to render ConvexHullNode as it conflicts with the bottom layers. # However, it is somewhat relevant when the node is selected, so do render it then. if type(node) is ConvexHullNode and not Selection.isSelected( cast(ConvexHullNode, node).getWatchedNode()): continue if not node.render(renderer): if (node.getMeshData()) and node.isVisible(): renderer.queueNode(node, transparent=True, shader=self._ghost_shader)
def _boundingBoxSelection(self, event): """Handle mouse and keyboard events for bounding box selection :param event: type(Event) passed from self.event() """ root = self._scene.getRoot() ray = self._scene.getActiveCamera().getRay(event.x, event.y) intersections = [] for node in BreadthFirstIterator(root): if node.isEnabled() and not node.isLocked(): intersection = node.getBoundingBox().intersectsRay(ray) if intersection: intersections.append((node, intersection[0], intersection[1])) if intersections: intersections.sort(key=lambda k: k[1]) node = intersections[0][0] if not Selection.isSelected(node): if not self._shift_is_active: Selection.clear() Selection.add(node) else: Selection.clear()
def changeSelection(self, index): modifiers = QApplication.keyboardModifiers() ctrl_is_active = modifiers & Qt.ControlModifier shift_is_active = modifiers & Qt.ShiftModifier if ctrl_is_active: item = self._objects_model.getItem(index) node = item["node"] if Selection.isSelected(node): Selection.remove(node) else: Selection.add(node) elif shift_is_active: polarity = 1 if index + 1 > self._last_selected_index else -1 for i in range(self._last_selected_index, index + polarity, polarity): item = self._objects_model.getItem(i) node = item["node"] Selection.add(node) else: # Single select item = self._objects_model.getItem(index) node = item["node"] build_plate_number = node.callDecoration("getBuildPlateNumber") if build_plate_number is not None and build_plate_number != -1: self.setActiveBuildPlate(build_plate_number) Selection.clear() Selection.add(node) self._last_selected_index = index
def _update(self, *args): nodes = [] filter_current_build_plate = Application.getInstance().getPreferences( ).getValue("view/filter_current_build_plate") active_build_plate_number = self._build_plate_number group_nr = 1 name_count_dict = defaultdict(int) for node in DepthFirstIterator(Application.getInstance().getController( ).getScene().getRoot()): if not isinstance(node, SceneNode): continue if (not node.getMeshData() and not node.callDecoration("getLayerData") ) and not node.callDecoration("isGroup"): continue if node.getParent() and node.getParent().callDecoration("isGroup"): continue # Grouped nodes don't need resetting as their parent (the group) is resetted) if not node.callDecoration( "isSliceable") and not node.callDecoration("isGroup"): continue node_build_plate_number = node.callDecoration( "getBuildPlateNumber") if filter_current_build_plate and node_build_plate_number != active_build_plate_number: continue if not node.callDecoration("isGroup"): name = node.getName() else: name = catalog.i18nc( "@label", "Group #{group_nr}").format(group_nr=str(group_nr)) group_nr += 1 if hasattr(node, "isOutsideBuildArea"): is_outside_build_area = node.isOutsideBuildArea() else: is_outside_build_area = False #check if we already have an instance of the object based on name name_count_dict[name] += 1 name_count = name_count_dict[name] if name_count > 1: name = "{0}({1})".format(name, name_count - 1) node.setName(name) nodes.append({ "name": name, "isSelected": Selection.isSelected(node), "isOutsideBuildArea": is_outside_build_area, "buildPlateNumber": node_build_plate_number, "node": node }) nodes = sorted(nodes, key=lambda n: n["name"]) self.setItems(nodes) self.itemsChanged.emit()
def _isInSelectedGroup(self, node): group_node = node.getParent() while group_node.callDecoration("isGroup"): if Selection.isSelected(group_node): return True group_node = group_node.getParent() return False
def _pixelSelection(self, event): # Find a node id by looking at a pixel value at the requested location item_id = self._selection_pass.getIdAtPosition(event.x, event.y) if not item_id: Selection.clear() return # Find the scene-node which matches the node-id for node in BreadthFirstIterator(self._scene.getRoot()): if id(node) == item_id: if self._isNodeInGroup(node): is_selected = Selection.isSelected( self._findTopGroupNode(node)) else: is_selected = Selection.isSelected(node) if self._ctrl_is_active: if is_selected: # Deselect the scenenode and its sibblings in a group if node.getParent(): if self._alt_is_active or not self._isNodeInGroup( node): Selection.remove(node) else: Selection.remove(self._findTopGroupNode(node)) else: # Select the scenenode and its sibblings in a group if node.getParent(): if self._alt_is_active or not self._isNodeInGroup( node): Selection.add(node) else: Selection.add(self._findTopGroupNode(node)) else: if not is_selected or Selection.getCount() > 1: # Select only the scenenode and its sibblings in a group Selection.clear() if node.getParent(): if self._alt_is_active or not self._isNodeInGroup( node): Selection.add(node) else: Selection.add(self._findTopGroupNode(node)) elif self._isNodeInGroup(node) and self._alt_is_active: Selection.clear() Selection.add(node)
def _onChangeTimerFinished(self): root = self._controller.getScene().getRoot() for node in BreadthFirstIterator(root): if node is root or type(node) is not SceneNode: continue bbox = node.getBoundingBox() if not bbox or not bbox.isValid(): continue # Mark the node as outside the build volume if the bounding box test fails. if self._build_volume.getBoundingBox().intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: node._outside_buildarea = True else: node._outside_buildarea = False # Move the node upwards if the bottom is below the build platform. move_vector = Vector() if not Float.fuzzyCompare(bbox.bottom, 0.0): move_vector.setY(-bbox.bottom) # If there is no convex hull for the node, start calculating it and continue. if not hasattr(node, "_convex_hull"): if not hasattr(node, "_convex_hull_job"): job = ConvexHullJob.ConvexHullJob(node) job.start() node._convex_hull_job = job elif Selection.isSelected(node): pass else: # Check for collisions between convex hulls for other_node in BreadthFirstIterator(root): # Ignore root, ourselves and anything that is not a normal SceneNode. if other_node is root or type(other_node) is not SceneNode or other_node is node: continue # Ignore nodes that do not have the right properties set. if not hasattr(other_node, "_convex_hull") or not other_node.getBoundingBox(): continue # Check to see if the bounding boxes intersect. If not, we can ignore the node as there is no way the hull intersects. if node.getBoundingBox().intersectsBox(other_node.getBoundingBox()) == AxisAlignedBox.IntersectionResult.NoIntersection: continue # Get the overlap distance for both convex hulls. If this returns None, there is no intersection. overlap = node._convex_hull.intersectsPolygon(other_node._convex_hull) if overlap is None: continue move_vector.setX(overlap[0] * 1.1) move_vector.setZ(overlap[1] * 1.1) if move_vector != Vector(): op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector) op.push() if node.getBoundingBox().intersectsBox(self._build_volume.getBoundingBox()) == AxisAlignedBox.IntersectionResult.FullIntersection: op = ScaleToBoundsOperation(node, self._build_volume.getBoundingBox()) op.push()
def _replaceSceneNode(self, existing_node, trimeshes) -> None: name = existing_node.getName() file_name = existing_node.getMeshData().getFileName() transformation = existing_node.getWorldTransformation() parent = existing_node.getParent() extruder_id = existing_node.callDecoration("getActiveExtruder") build_plate = existing_node.callDecoration("getBuildPlateNumber") selected = Selection.isSelected(existing_node) children = existing_node.getChildren() new_nodes = [] op = GroupedOperation() op.addOperation(RemoveSceneNodeOperation(existing_node)) for i, tri_node in enumerate(trimeshes): mesh_data = self._toMeshData(tri_node, file_name) new_node = CuraSceneNode() new_node.setSelectable(True) new_node.setMeshData(mesh_data) new_node.setName(name if i==0 else "%s %d" % (name, i)) new_node.callDecoration("setActiveExtruder", extruder_id) new_node.addDecorator(BuildPlateDecorator(build_plate)) new_node.addDecorator(SliceableObjectDecorator()) op.addOperation(AddSceneNodeOperation(new_node, parent)) op.addOperation(SetTransformMatrixOperation(new_node, transformation)) new_nodes.append(new_node) if selected: Selection.add(new_node) for child in children: mesh_data = child.getMeshData() if not mesh_data: continue child_bounding_box = mesh_data.getTransformed(child.getWorldTransformation()).getExtents() if not child_bounding_box: continue new_parent = None for potential_parent in new_nodes: parent_mesh_data = potential_parent.getMeshData() if not parent_mesh_data: continue parent_bounding_box = parent_mesh_data.getTransformed(potential_parent.getWorldTransformation()).getExtents() if not parent_bounding_box: continue intersection = child_bounding_box.intersectsBox(parent_bounding_box) if intersection != AxisAlignedBox.IntersectionResult.NoIntersection: new_parent = potential_parent break if not new_parent: new_parent = new_nodes[0] op.addOperation(SetParentOperationSimplified(child, new_parent)) op.push()
def undo(self): self._node.setParent(None) self._node_dup.setParent(None) self._selected = Selection.isSelected(self._node) if self._selected: Selection.remove( self._node) # Also remove the node from the selection. self._print_mode_manager.deleteDuplicatedNode(self._node_dup)
def redo(self): self._node.setParent(None) # Hack to ensure that the _onchanged is triggered correctly. # We can't do it the right way as most remove changes don't need to trigger # a reslice (eg; removing hull nodes don't need to trigger reslice). Application.getInstance().getBackend().forceSlice() if Selection.isSelected(self._node): Selection.remove(self._node)
def _pixelSelection(self, event): # Find a node id by looking at a pixel value at the requested location item_id = self._selection_pass.getIdAtPosition(event.x, event.y) if not item_id and not self._shift_is_active: Selection.clear() return # Find the scene-node which matches the node-id for node in BreadthFirstIterator(self._scene.getRoot()): if id(node) == item_id: if self._isNodeInGroup(node): is_selected = Selection.isSelected(self._findTopGroupNode(node)) else: is_selected = Selection.isSelected(node) if self._shift_is_active: if is_selected: # Deselect the scenenode and its sibblings in a group if node.getParent(): if self._ctrl_is_active or not self._isNodeInGroup(node): Selection.remove(node) else: Selection.remove(self._findTopGroupNode(node)) else: # Select the scenenode and its sibblings in a group if node.getParent(): if self._ctrl_is_active or not self._isNodeInGroup(node): Selection.add(node) else: Selection.add(self._findTopGroupNode(node)) else: if not is_selected or Selection.getCount() > 1: # Select only the scenenode and its sibblings in a group Selection.clear() if node.getParent(): if self._ctrl_is_active or not self._isNodeInGroup(node): Selection.add(node) else: Selection.add(self._findTopGroupNode(node)) elif self._isNodeInGroup(node) and self._ctrl_is_active: Selection.clear() Selection.add(node)
def _pixelSelection(self, event): pixel_id = self._renderer.getIdAtCoordinate(event.x, event.y) if not pixel_id: Selection.clear() return for node in BreadthFirstIterator(self._scene.getRoot()): if id(node) == pixel_id: if self._ctrl_is_active: if Selection.isSelected(node): if node.getParent(): group_node = node.getParent() if not group_node.callDecoration("isGroup"): Selection.remove(node) else: while group_node.getParent().callDecoration( "isGroup"): group_node = group_node.getParent() Selection.remove(group_node) else: if node.getParent(): group_node = node.getParent() if not group_node.callDecoration("isGroup"): Selection.add(node) else: while group_node.getParent().callDecoration( "isGroup"): group_node = group_node.getParent() Selection.add(group_node) else: if not Selection.isSelected( node) or Selection.getCount() > 1: Selection.clear() if node.getParent(): group_node = node.getParent() if not group_node.callDecoration("isGroup"): Selection.add(node) else: while group_node.getParent().callDecoration( "isGroup"): group_node = group_node.getParent() Selection.add(group_node)
def undo(self) -> None: """Reverses the operation of adding a scene node. This removes the scene node again. """ self._node.setParent(None) self._selected = Selection.isSelected(self._node) if self._selected: Selection.remove( self._node) # Also remove the node from the selection.
def _pixelSelection(self, event): pixel_id = self._renderer.getIdAtCoordinate(event.x, event.y) if not pixel_id: Selection.clear() return for node in BreadthFirstIterator(self._scene.getRoot()): if id(node) == pixel_id: if not Selection.isSelected(node): Selection.clear() Selection.add(node)
def _removeEraserMesh(self, node: CuraSceneNode): parent = node.getParent() if parent == self._controller.getScene().getRoot(): parent = None op = RemoveSceneNodeOperation(node) op.push() if parent and not Selection.isSelected(parent): Selection.add(parent) CuraApplication.getInstance().getController().getScene().sceneChanged.emit(node)
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._selection_shader: self._selection_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader")) self._selection_shader.setUniformValue("u_color", Color(32, 32, 32, 128)) for node in DepthFirstIterator(scene.getRoot()): # We do not want to render ConvexHullNode as it conflicts with the bottom layers. # However, it is somewhat relevant when the node is selected, so do render it then. if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()): continue if not node.render(renderer): if node.getMeshData() and node.isVisible(): if Selection.isSelected(node): renderer.queueNode(node, transparent = True, shader = self._selection_shader) layer_data = node.callDecoration("getLayerData") if not layer_data: continue # Render all layers below a certain number as line mesh instead of vertices. if self._current_layer_num - self._solid_layers > -1: start = 0 end = 0 element_counts = layer_data.getElementCounts() for layer, counts in element_counts.items(): if layer + self._solid_layers > self._current_layer_num: break end += counts # This uses glDrawRangeElements internally to only draw a certain range of lines. renderer.queueNode(node, mesh = layer_data, mode = RenderBatch.RenderMode.Lines, range = (start, end)) if self._current_layer_mesh: renderer.queueNode(node, mesh = self._current_layer_mesh) if self._current_layer_jumps: renderer.queueNode(node, mesh = self._current_layer_jumps)
def _update(self, *args): nodes = [] filter_current_build_plate = Application.getInstance().getPreferences().getValue("view/filter_current_build_plate") active_build_plate_number = self._build_plate_number group_nr = 1 name_count_dict = defaultdict(int) for node in DepthFirstIterator(Application.getInstance().getController().getScene().getRoot()): if not isinstance(node, SceneNode): continue if (not node.getMeshData() and not node.callDecoration("getLayerData")) and not node.callDecoration("isGroup"): continue if node.getParent() and node.getParent().callDecoration("isGroup"): continue # Grouped nodes don't need resetting as their parent (the group) is resetted) if not node.callDecoration("isSliceable") and not node.callDecoration("isGroup"): continue node_build_plate_number = node.callDecoration("getBuildPlateNumber") if filter_current_build_plate and node_build_plate_number != active_build_plate_number: continue if not node.callDecoration("isGroup"): name = node.getName() else: name = catalog.i18nc("@label", "Group #{group_nr}").format(group_nr = str(group_nr)) group_nr += 1 if hasattr(node, "isOutsideBuildArea"): is_outside_build_area = node.isOutsideBuildArea() else: is_outside_build_area = False #check if we already have an instance of the object based on name name_count_dict[name] += 1 name_count = name_count_dict[name] if name_count > 1: name = "{0}({1})".format(name, name_count-1) node.setName(name) nodes.append({ "name": name, "isSelected": Selection.isSelected(node), "isOutsideBuildArea": is_outside_build_area, "buildPlateNumber": node_build_plate_number, "node": node }) nodes = sorted(nodes, key=lambda n: n["name"]) self.setItems(nodes) self.itemsChanged.emit()
def _removeSplittingPlane(self, node: SteSlicerSceneNode): parent = node.getParent() if parent == self._controller.getScene().getRoot(): parent = None op = RemoveSceneNodeOperation(node) op.push() if parent and not Selection.isSelected(parent): Selection.add(parent) SteSlicerApplication.getInstance().getController().getScene( ).sceneChanged.emit(node)
def _pixelSelection(self, event): item_id = self._selection_pass.getIdAtPosition(event.x, event.y) if not item_id: Selection.clear() return for node in BreadthFirstIterator(self._scene.getRoot()): if id(node) == item_id: if self._ctrl_is_active: if Selection.isSelected(node): if node.getParent(): group_node = node.getParent() if not group_node.callDecoration("isGroup"): Selection.remove(node) else: while group_node.getParent().callDecoration("isGroup"): group_node = group_node.getParent() Selection.remove(group_node) else: if node.getParent(): group_node = node.getParent() if not group_node.callDecoration("isGroup"): Selection.add(node) else: while group_node.getParent().callDecoration("isGroup"): group_node = group_node.getParent() Selection.add(group_node) else: if not Selection.isSelected(node) or Selection.getCount() > 1: Selection.clear() if node.getParent(): group_node = node.getParent() if not group_node.callDecoration("isGroup"): Selection.add(node) else: while group_node.getParent().callDecoration("isGroup"): group_node = group_node.getParent() Selection.add(group_node)
def undo(self): self._node.setParent(None) self._node_dup.setParent(None) self._selected = Selection.isSelected(self._node) if self._selected: Selection.remove( self._node) # Also remove the node from the selection. self._print_mode_manager.deleteDuplicatedNode(self._node_dup) for child in self._node_dup.getAllChildren(): if type(child) == DuplicatedNode: self._print_mode_manager.deleteDuplicatedNode(child)
def _getNodeColor(self, node): while True: r = random.randint(0, 255) g = random.randint(0, 255) b = random.randint(0, 255) a = 255 if Selection.isSelected(node) or self._isInSelectedGroup(node) else 0 color = Color(r, g, b, a) if color not in self._selection_map: break self._selection_map[color] = id(node) return color
def _getNodeColor(self, node): while True: r = random.randint(0, 255) g = random.randint(0, 255) b = random.randint(0, 255) a = 255 if Selection.isSelected(node) else 0 color = Color(r, g, b, a) if color not in self._selection_map: break self._selection_map[color] = id(node) return color
def redo(self): old_parent = self._parent self._node.setParent(None) if old_parent and old_parent.callDecoration("isGroup"): old_parent.callDecoration("recomputeConvexHull") # Hack to ensure that the _onchanged is triggered correctly. # We can't do it the right way as most remove changes don't need to trigger # a reslice (eg; removing hull nodes don't need to trigger reslice). try: Application.getInstance().getBackend().needsSlicing() except: pass if Selection.isSelected(self._node): # Also remove the selection. Selection.remove(self._node)
def _isInSelectedGroup(self, node: "SceneNode") -> bool: """ Get whether the given node is in a group that is selected. :param node: The node to check. :return: ``True`` if the node is in a selected group, or ``False`` if it's not. """ group_node = node.getParent() if group_node is None: # Separate node that's not in the scene. return False # Can never get selected. while group_node.callDecoration("isGroup"): if Selection.isSelected(group_node): return True group_node = group_node.getParent() if group_node is None: return False return False
def redo(self) -> None: old_parent = self._parent self._node.setParent(None) if old_parent and old_parent.callDecoration("isGroup"): old_parent.callDecoration("recomputeConvexHull") # Hack to ensure that the _onchanged is triggered correctly. # We can't do it the right way as most remove changes don't need to trigger # a reslice (eg; removing hull nodes don't need to trigger a reslice). try: Application.getInstance().getBackend().needsSlicing( ) # type: ignore except AttributeError: # Todo: This should be removed, Uranium doesn't care or know about slicing! pass if Selection.isSelected(self._node): # Also remove the selection. Selection.remove(self._node)
def _getSelectedObjectsWithoutSelectedAncestors(self) -> List[SceneNode]: if not isinstance(self._selected_objects_without_selected_ancestors, list): nodes = Selection.getAllSelectedObjects() self._selected_objects_without_selected_ancestors = [] for node in nodes: has_selected_ancestor = False ancestor = node.getParent() while ancestor: if Selection.isSelected(ancestor): has_selected_ancestor = True break ancestor = ancestor.getParent() if not has_selected_ancestor: self._selected_objects_without_selected_ancestors.append(node) return self._selected_objects_without_selected_ancestors
def _getSelectedObjectsWithoutSelectedAncestors(self) -> List[SceneNode]: if not isinstance(self._selected_objects_without_selected_ancestors, list): nodes = Selection.getAllSelectedObjects() self._selected_objects_without_selected_ancestors = [] for node in nodes: has_selected_ancestor = False ancestor = node.getParent() while ancestor: if Selection.isSelected(ancestor): has_selected_ancestor = True break ancestor = ancestor.getParent() if not has_selected_ancestor: self._selected_objects_without_selected_ancestors.append(node) return self._selected_objects_without_selected_ancestors
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._ghost_shader: self._ghost_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "color.shader")) self._ghost_shader.setUniformValue("u_color", Color(*Application.getInstance().getTheme().getColor("layerview_ghost").getRgb())) for node in DepthFirstIterator(scene.getRoot()): # We do not want to render ConvexHullNode as it conflicts with the bottom layers. # However, it is somewhat relevant when the node is selected, so do render it then. if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()): continue if not node.render(renderer): if (node.getMeshData()) and node.isVisible(): renderer.queueNode(node, transparent = True, shader = self._ghost_shader)
def setSelected(self, key): for index in range(0, len(self.items)): if self.items[index]["key"] == key: for node in Application.getInstance().getController().getScene( ).getRoot().getAllChildren(): if id(node) == key: if node not in Selection.getAllSelectedObjects( ): #node already selected Selection.add(node) if node.callDecoration( "isGroup"): #Its a group node for child_node in node.getChildren(): if child_node not in Selection.getAllSelectedObjects( ): #Set all children to parent state (if they arent already) Selection.add(child_node) else: Selection.remove(node) if node.callDecoration("isGroup"): #Its a group for child_node in node.getChildren(): if child_node in Selection.getAllSelectedObjects( ): Selection.remove(child_node) all_children_selected = True #Check all group nodes to see if all their children are selected (if so, they also need to be selected!) for index in range(0, len(self.items)): if self.items[index]["is_group"]: for node in Application.getInstance().getController().getScene( ).getRoot().getAllChildren(): if node.hasChildren(): if id(node) == self.items[index]["key"] and id( node) != key: for index, child_node in enumerate( node.getChildren()): if not Selection.isSelected(child_node): all_children_selected = False #At least one of its children is not selected, dont change state break if all_children_selected: Selection.add(node) else: Selection.remove(node) #Force update self.updateList( Application.getInstance().getController().getScene().getRoot())
def _update(self, *args): nodes = [] filter_current_build_plate = Preferences.getInstance().getValue( "view/filter_current_build_plate") active_build_plate_number = self._build_plate_number group_nr = 1 for node in DepthFirstIterator(Application.getInstance().getController( ).getScene().getRoot()): if not isinstance(node, SceneNode): continue if (not node.getMeshData() and not node.callDecoration("getLayerData") ) and not node.callDecoration("isGroup"): continue if node.getParent() and node.getParent().callDecoration("isGroup"): continue # Grouped nodes don't need resetting as their parent (the group) is resetted) if not node.callDecoration( "isSliceable") and not node.callDecoration("isGroup"): continue node_build_plate_number = node.callDecoration( "getBuildPlateNumber") if filter_current_build_plate and node_build_plate_number != active_build_plate_number: continue if not node.callDecoration("isGroup"): name = node.getName() else: name = catalog.i18nc( "@label", "Group #{group_nr}").format(group_nr=str(group_nr)) group_nr += 1 nodes.append({ "name": name, "isSelected": Selection.isSelected(node), "isOutsideBuildArea": node.isOutsideBuildArea(), "buildPlateNumber": node_build_plate_number, "node": node }) nodes = sorted(nodes, key=lambda n: n["name"]) self.setItems(nodes) self.itemsChanged.emit()
def _boundingBoxSelection(self, event): root = self._scene.getRoot() ray = self._scene.getActiveCamera().getRay(event.x, event.y) intersections = [] for node in BreadthFirstIterator(root): if node.getSelectionMask() == self._selectionMask and not node.isLocked(): intersection = node.getBoundingBox().intersectsRay(ray) if intersection: intersections.append((node, intersection[0], intersection[1])) if intersections: intersections.sort(key=lambda k: k[1]) node = intersections[0][0] if not Selection.isSelected(node): Selection.clear() Selection.add(node) else: Selection.clear()
def _boundingBoxSelection(self, event): root = self._scene.getRoot() ray = self._scene.getActiveCamera().getRay(event.x, event.y) intersections = [] for node in BreadthFirstIterator(root): if node.isEnabled() and not node.isLocked(): intersection = node.getBoundingBox().intersectsRay(ray) if intersection: intersections.append((node, intersection[0], intersection[1])) if intersections: intersections.sort(key=lambda k: k[1]) node = intersections[0][0] if not Selection.isSelected(node): if not self._ctrl_is_active: Selection.clear() Selection.add(node) else: Selection.clear()
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() renderer.setRenderSelection(False) if not self._material: self._material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "vertexcolor.frag")) self._material.setUniformValue("u_color", [1.0, 0.0, 0.0, 1.0]) self._selection_material = renderer.createMaterial(Resources.getPath(Resources.ShadersLocation, "basic.vert"), Resources.getPath(Resources.ShadersLocation, "color.frag")) self._selection_material.setUniformValue("u_color", Color(35, 35, 35, 128)) for node in DepthFirstIterator(scene.getRoot()): if not node.render(renderer): if node.getMeshData() and node.isVisible(): if Selection.isSelected(node): renderer.queueNode(node, material = self._selection_material, transparent = True) try: layer_data = node.getMeshData().layerData except AttributeError: continue start = 0 end = 0 element_counts = layer_data.getElementCounts() for layer, counts in element_counts.items(): end += sum(counts) ## Hack to ensure the end is correct. Not quite sure what causes this end += 2 * len(counts) if layer >= self._current_layer_num: break renderer.queueNode(node, mesh = layer_data, material = self._material, mode = Renderer.RenderLines, start = start, end = end)
def updateList(self, trigger_node): #self.clear() for group_node in self._scene.getRoot().getChildren(): for node in DepthFirstIterator(group_node): if node.getMeshData() is not None or node.hasChildren() and type(node) is not Camera: parent_key = 0 if group_node is not node: parent_key = id(group_node) index = self.find("key",(id(node))) data = {"name":node.getName(), "visibility": node.isVisible(), "key": (id(node)), "selected": Selection.isSelected(node),"depth": node.getDepth(),"collapsed": node in self._collapsed_nodes,"parent_key": parent_key, "has_children":node.hasChildren()} if index is not None and index >= 0: self.removeItem(index) self.insertItem(index,data) else: self.appendItem(data)
def updateList(self, trigger_node): for root_child in self._scene.getRoot().getChildren(): if root_child.callDecoration("isGroup"): # Check if its a group node #if root_child.hasChildren(): #Check if it has children (only show it if it has) parent_key = id(root_child) for node in DepthFirstIterator(root_child): if root_child in self._collapsed_nodes: self._collapsed_nodes.append(node) data = {"name":node.getName(), "visibility": node.isVisible(), "key": (id(node)), "selected": Selection.isSelected(node),"collapsed": node in self._collapsed_nodes,"parent_key": parent_key, "is_group":bool(node.callDecoration("isGroup"))} index = self.find("key",(id(node))) parent_index = self.find("key", data["parent_key"]) num_children = 0 for parent_node in Application.getInstance().getController().getScene().getRoot().getAllChildren(): if id(parent_node) == data["parent_key"]: num_children = len(parent_node.getChildren()) if parent_index != -1: corrected_index = parent_index + num_children else: corrected_index = 0 if index is not None and index >= 0: self.removeItem(index) self.insertItem(index,data) else: self.insertItem(corrected_index, data) #self.appendItem(data) elif type(root_child) is SceneNode or type(root_child) is PointCloudNode: data = {"name":root_child.getName(), "visibility": root_child.isVisible(), "key": (id(root_child)), "selected": Selection.isSelected(root_child),"collapsed": root_child in self._collapsed_nodes,"parent_key": 0, "is_group":bool(root_child.callDecoration("isGroup"))} # Check if data exists, if yes, remove old and re-add. index = self.find("key",(id(root_child))) if index is not None and index >= 0: self.removeItem(index) self.insertItem(index,data) else: self.appendItem(data) '''for node in DepthFirstIterator(group_node):
def redo(self): self._node.setParent(None) if Selection.isSelected(self._node): Selection.remove(self._node)
def renderQueuedNodes(self): self._gl.glEnable(self._gl.GL_DEPTH_TEST) self._gl.glDepthFunc(self._gl.GL_LESS) self._gl.glDepthMask(self._gl.GL_TRUE) self._gl.glDisable(self._gl.GL_CULL_FACE) self._gl.glLineWidth(self.getPixelMultiplier()) self._scene.acquireLock() self._camera = self._scene.getActiveCamera() if not self._camera: Logger.log("e", "No active camera set, can not render") self._scene.releaseLock() return # Render the selection image selectable_nodes = [] for node in DepthFirstIterator(self._scene.getRoot()): if node.isSelectable() and node.getMeshData(): selectable_nodes.append(node) if selectable_nodes: #TODO: Use a limited area around the mouse rather than a full viewport for rendering if self._selection_buffer.width() < self._viewport_width or self._selection_buffer.height() < self._viewport_height: self._selection_buffer = self.createFrameBuffer(self._viewport_width, self._viewport_height) self._selection_buffer.bind() self._gl.glClearColor(0.0, 0.0, 0.0, 0.0) self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT) self._gl.glDisable(self._gl.GL_BLEND) self._selection_map.clear() for node in selectable_nodes: if type(node) is PointCloudNode: #Pointcloud node sets vertex color (to be used for point precise selection) self._renderItem({ "node": node, "material": self._handle_material, "mode": self._gl.GL_POINTS }) else : color = self._getObjectColor(node) self._selection_map[color] = id(node) self._selection_material.setUniformValue("u_color", color) self._renderItem({ "node": node, "material": self._selection_material, "mode": self._gl.GL_TRIANGLES }) tool = self._controller.getActiveTool() if tool: tool_handle = tool.getHandle() if tool_handle and tool_handle.getSelectionMesh() and tool_handle.getParent(): self._selection_map.update(tool_handle.getSelectionMap()) self._gl.glDisable(self._gl.GL_DEPTH_TEST) self._renderItem({ "node": tool_handle, "mesh": tool_handle.getSelectionMesh(), "material": self._handle_material, "mode": self._gl.GL_TRIANGLES }) self._gl.glEnable(self._gl.GL_DEPTH_TEST) self._selection_buffer.release() self._selection_image = self._selection_buffer.toImage() # Workaround for a MacOSX Intel HD Graphics 6000 Bug # Apparently, performing a glReadPixels call on a bound framebuffer breaks releasing the # depth buffer, which means the rest of the depth tested geometry never renders. To work- # around this we perform a clear here. Note that for some reason we also need to set # glClearColor since it is apparently not stored properly. self._gl.glClearColor(self._background_color.redF(), self._background_color.greenF(), self._background_color.blueF(), self._background_color.alphaF()) self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT) self._gl.glEnable(self._gl.GL_STENCIL_TEST) self._gl.glStencilMask(0xff) self._gl.glClearStencil(0) self._gl.glClear(self._gl.GL_STENCIL_BUFFER_BIT) self._gl.glStencilFunc(self._gl.GL_ALWAYS, 0xff, 0xff) self._gl.glStencilOp(self._gl.GL_REPLACE, self._gl.GL_REPLACE, self._gl.GL_REPLACE) self._gl.glStencilMask(0) for item in self._solids_queue: if Selection.isSelected(item["node"]): self._gl.glStencilMask(0xff) self._renderItem(item) self._gl.glStencilMask(0) else: self._renderItem(item) if self._render_selection: self._gl.glStencilMask(0) self._gl.glStencilFunc(self._gl.GL_EQUAL, 0, 0xff) self._gl.glLineWidth(2 * self.getPixelMultiplier()) for node in Selection.getAllSelectedObjects(): if node.getMeshData() and type(node) is not PointCloudNode: self._renderItem({ "node": node, "material": self._outline_material, "mode": self._gl.GL_TRIANGLES, "wireframe": True }) self._gl.glLineWidth(self.getPixelMultiplier()) self._gl.glDisable(self._gl.GL_STENCIL_TEST) self._gl.glDepthMask(self._gl.GL_FALSE) self._gl.glEnable(self._gl.GL_BLEND) self._gl.glEnable(self._gl.GL_CULL_FACE) self._gl.glBlendFunc(self._gl.GL_SRC_ALPHA, self._gl.GL_ONE_MINUS_SRC_ALPHA) for item in self._transparent_queue: self._renderItem(item) self._gl.glDisable(self._gl.GL_DEPTH_TEST) self._gl.glDisable(self._gl.GL_CULL_FACE) for item in self._overlay_queue: self._renderItem(item) self._scene.releaseLock()
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._selection_shader: self._selection_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "default.shader")) self._selection_shader.setUniformValue("u_color", Color(32, 32, 32, 128)) for node in DepthFirstIterator(scene.getRoot()): # We do not want to render ConvexHullNode as it conflicts with the bottom layers. # However, it is somewhat relevant when the node is selected, so do render it then. if type(node) is ConvexHullNode and not Selection.isSelected(node.getWatchedNode()): continue if not node.render(renderer): if node.getMeshData() and node.isVisible(): if Selection.isSelected(node): renderer.queueNode(node, transparent = True, shader = self._selection_shader) layer_data = node.callDecoration("getLayerData") if not layer_data: continue # Render all layers below a certain number as line mesh instead of vertices. if self._current_layer_num - self._solid_layers > -1: start = 0 end = 0 element_counts = layer_data.getElementCounts() for layer, counts in element_counts.items(): if layer + self._solid_layers > self._current_layer_num: break end += counts # This uses glDrawRangeElements internally to only draw a certain range of lines. renderer.queueNode(node, mesh = layer_data, mode = RenderBatch.RenderMode.Lines, range = (start, end)) # We currently recreate the current "solid" layers every time a if not self._current_layer_mesh: self._current_layer_mesh = MeshData() for i in range(self._solid_layers): layer = self._current_layer_num - i if layer < 0: continue try: layer_mesh = layer_data.getLayer(layer).createMesh() if not layer_mesh or layer_mesh.getVertices() is None: continue except: continue if self._current_layer_mesh: #Threading thing; Switching between views can cause the current layer mesh to be deleted. self._current_layer_mesh.addVertices(layer_mesh.getVertices()) # Scale layer color by a brightness factor based on the current layer number # This will result in a range of 0.5 - 1.0 to multiply colors by. brightness = (2.0 - (i / self._solid_layers)) / 2.0 if self._current_layer_mesh: self._current_layer_mesh.addColors(layer_mesh.getColors() * brightness) if self._current_layer_mesh: renderer.queueNode(node, mesh = self._current_layer_mesh) if not self._current_layer_jumps: self._current_layer_jumps = MeshData() for i in range(1): layer = self._current_layer_num - i if layer < 0: continue try: layer_mesh = layer_data.getLayer(layer).createJumps() if not layer_mesh or layer_mesh.getVertices() is None: continue except: continue self._current_layer_jumps.addVertices(layer_mesh.getVertices()) # Scale layer color by a brightness factor based on the current layer number # This will result in a range of 0.5 - 1.0 to multiply colors by. brightness = (2.0 - (i / self._solid_layers)) / 2.0 self._current_layer_jumps.addColors(layer_mesh.getColors() * brightness) renderer.queueNode(node, mesh = self._current_layer_jumps)
def undo(self): self._node.setParent(None) self._selected = Selection.isSelected(self._node) if self._selected: Selection.remove(self._node) # Also remove the node from the selection.
def beginRendering(self): scene = self.getController().getScene() renderer = self.getRenderer() if not self._extruders_model: self._extruders_model = Application.getInstance().getExtrudersModel() 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: if Application.getInstance().getPreferences().getValue("view/show_overhang"): # Make sure the overhang angle is valid before passing it to the shader if self._support_angle is not None and self._support_angle >= 0 and self._support_angle <= 90: self._enabled_shader.setUniformValue("u_overhangAngle", math.cos(math.radians(90 - self._support_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 undo(self): self._node.setParent(None) self._selected = Selection.isSelected(self._node) if self._selected: Selection.remove(self._node)
def _onChangeTimerFinished(self): if not self._enabled: return root = self._controller.getScene().getRoot() for node in BreadthFirstIterator(root): if node is root or type(node) is not SceneNode: continue bbox = node.getBoundingBox() if not bbox or not bbox.isValid(): self._change_timer.start() continue build_volume_bounding_box = copy.deepcopy(self._build_volume.getBoundingBox()) build_volume_bounding_box.setBottom(-9001) # Ignore intersections with the bottom # Mark the node as outside the build volume if the bounding box test fails. if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection: node._outside_buildarea = True else: node._outside_buildarea = False # Move it downwards if bottom is above platform move_vector = Vector() if not (node.getParent() and node.getParent().callDecoration("isGroup")): #If an object is grouped, don't move it down if bbox.bottom > 0: move_vector.setY(-bbox.bottom) #if not Float.fuzzyCompare(bbox.bottom, 0.0): # pass#move_vector.setY(-bbox.bottom) # If there is no convex hull for the node, start calculating it and continue. if not node.getDecorator(ConvexHullDecorator): node.addDecorator(ConvexHullDecorator()) if not node.callDecoration("getConvexHull"): if not node.callDecoration("getConvexHullJob"): job = ConvexHullJob.ConvexHullJob(node) job.start() node.callDecoration("setConvexHullJob", job) elif Selection.isSelected(node): pass elif Preferences.getInstance().getValue("physics/automatic_push_free"): # Check for collisions between convex hulls for other_node in BreadthFirstIterator(root): # Ignore root, ourselves and anything that is not a normal SceneNode. if other_node is root or type(other_node) is not SceneNode or other_node is node: continue # Ignore colissions of a group with it's own children if other_node in node.getAllChildren() or node in other_node.getAllChildren(): continue # Ignore colissions within a group if other_node.getParent().callDecoration("isGroup") is not None or node.getParent().callDecoration("isGroup") is not None: continue #if node.getParent().callDecoration("isGroup") is other_node.getParent().callDecoration("isGroup"): # continue # Ignore nodes that do not have the right properties set. if not other_node.callDecoration("getConvexHull") or not other_node.getBoundingBox(): continue # Check to see if the bounding boxes intersect. If not, we can ignore the node as there is no way the hull intersects. #if node.getBoundingBox().intersectsBox(other_node.getBoundingBox()) == AxisAlignedBox.IntersectionResult.NoIntersection: # continue # Get the overlap distance for both convex hulls. If this returns None, there is no intersection. try: head_hull = node.callDecoration("getConvexHullHead") if head_hull: overlap = head_hull.intersectsPolygon(other_node.callDecoration("getConvexHull")) if not overlap: other_head_hull = other_node.callDecoration("getConvexHullHead") if other_head_hull: overlap = node.callDecoration("getConvexHull").intersectsPolygon(other_head_hull) else: overlap = node.callDecoration("getConvexHull").intersectsPolygon(other_node.callDecoration("getConvexHull")) except: overlap = None #It can sometimes occur that the caclulated convex hull has no size, in which case there is no overlap. if overlap is None: continue move_vector.setX(overlap[0] * 1.01) move_vector.setZ(overlap[1] * 1.01) convex_hull = node.callDecoration("getConvexHull") if convex_hull: if not convex_hull.isValid(): return # Check for collisions between disallowed areas and the object for area in self._build_volume.getDisallowedAreas(): overlap = convex_hull.intersectsPolygon(area) if overlap is None: continue node._outside_buildarea = True if move_vector != Vector(): op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector) op.push()