Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
 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):                
Ejemplo n.º 5
0
    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)
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
 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())
Ejemplo n.º 12
0
 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
Ejemplo n.º 13
0
    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()
Ejemplo n.º 14
0
    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()
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
    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()
Ejemplo n.º 17
0
    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
Ejemplo n.º 18
0
    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()
Ejemplo n.º 19
0
 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
Ejemplo n.º 20
0
    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)
Ejemplo n.º 21
0
    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()
Ejemplo n.º 22
0
    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()
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
    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)
Ejemplo n.º 25
0
    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)
Ejemplo n.º 26
0
    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)
Ejemplo n.º 27
0
    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.
Ejemplo n.º 28
0
    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)
Ejemplo n.º 29
0
    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)
Ejemplo n.º 30
0
    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)
Ejemplo n.º 31
0
    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()
Ejemplo n.º 32
0
    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)
Ejemplo n.º 33
0
    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)
Ejemplo n.º 34
0
    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)
Ejemplo n.º 35
0
    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
Ejemplo n.º 36
0
    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
Ejemplo n.º 37
0
    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)
Ejemplo n.º 38
0
 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
Ejemplo n.º 39
0
    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)
Ejemplo n.º 40
0
    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
Ejemplo n.º 41
0
    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
Ejemplo n.º 42
0
    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)
Ejemplo n.º 43
0
    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())
Ejemplo n.º 44
0
    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()
Ejemplo n.º 45
0
    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()
Ejemplo n.º 46
0
    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()
Ejemplo n.º 47
0
    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)
Ejemplo n.º 48
0
 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)
Ejemplo n.º 49
0
 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):                
Ejemplo n.º 50
0
 def redo(self):
     self._node.setParent(None)
     if Selection.isSelected(self._node):
         Selection.remove(self._node)
Ejemplo n.º 51
0
    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()
Ejemplo n.º 52
0
    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)
Ejemplo n.º 53
0
 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.
Ejemplo n.º 54
0
    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)
Ejemplo n.º 55
0
 def undo(self):
     self._node.setParent(None)
     self._selected = Selection.isSelected(self._node)
     if self._selected:
         Selection.remove(self._node)
Ejemplo n.º 56
0
    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()