Exemplo n.º 1
0
    def setZ(self, Z):
        if float(Z) != self._Z_angle:
            self._angle = ((float(Z) % 360) - (self._Z_angle % 360)) % 360

            self._Z_angle = float(Z)

            #rotation = Quaternion.fromAngleAxis(math.radians( self._angle ), Vector.Unit_Z)
            rotation = Quaternion()
            rotation.setByAngleAxis(math.radians(self._angle), Vector.Unit_Z)

            # Save the current positions of the node, as we want to rotate around their current centres
            self._saved_node_positions = []
            for node in Selection.getAllSelectedObjects():
                self._saved_node_positions.append((node, node.getPosition()))
                node._rotationZ = self._Z_angle

            # Rate-limit the angle change notification
            # This is done to prevent the UI from being flooded with property change notifications,
            # which in turn would trigger constant repaints.
            new_time = time.monotonic()
            if not self._angle_update_time or new_time - self._angle_update_time > 0.1:
                self._angle_update_time = new_time

                # Rotate around the saved centeres of all selected nodes
                op = GroupedOperation()
                for node, position in self._saved_node_positions:
                    op.addOperation(
                        RotateOperation(node,
                                        rotation,
                                        rotate_around_point=position))
                op.push()

            self._angle = 0
            self.propertyChanged.emit()
Exemplo n.º 2
0
def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"],
                                   build_volume: "BuildVolume",
                                   fixed_nodes: Optional[List["SceneNode"]] = None,
                                   factor = 10000,
                                   add_new_nodes_in_scene: bool = False)  -> Tuple[GroupedOperation, int]:
    scene_root = Application.getInstance().getController().getScene().getRoot()
    found_solution_for_all, node_items = findNodePlacement(nodes_to_arrange, build_volume, fixed_nodes, factor)

    not_fit_count = 0
    grouped_operation = GroupedOperation()
    for node, node_item in zip(nodes_to_arrange, node_items):
        if add_new_nodes_in_scene:
            grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root))

        if node_item.binId() == 0:
            # We found a spot for it
            rotation_matrix = Matrix()
            rotation_matrix.setByRotationAxis(node_item.rotation(), Vector(0, -1, 0))
            grouped_operation.addOperation(RotateOperation(node, Quaternion.fromMatrix(rotation_matrix)))
            grouped_operation.addOperation(TranslateOperation(node, Vector(node_item.translation().x() / factor, 0,
                                                                           node_item.translation().y() / factor)))
        else:
            # We didn't find a spot
            grouped_operation.addOperation(
                TranslateOperation(node, Vector(200, node.getWorldPosition().y, -not_fit_count * 20), set_position = True))
            not_fit_count += 1

    return grouped_operation, not_fit_count
Exemplo n.º 3
0
    def _onSelectedFaceChanged(self):
        self._handle.setEnabled(not Selection.getFaceSelectMode())

        selected_face = Selection.getSelectedFace()
        if not Selection.getSelectedFace() or not (Selection.hasSelection() and Selection.getFaceSelectMode()):
            return

        original_node, face_id = selected_face
        meshdata = original_node.getMeshDataTransformed()
        if not meshdata or face_id < 0:
            return

        rotation_point, face_normal = meshdata.getFacePlane(face_id)
        rotation_point_vector = Vector(rotation_point[0], rotation_point[1], rotation_point[2])
        face_normal_vector = Vector(face_normal[0], face_normal[1], face_normal[2])
        rotation_quaternion = Quaternion.rotationTo(face_normal_vector.normalized(), Vector(0.0, -1.0, 0.0))

        operation = GroupedOperation()
        current_node = None  # type: Optional[SceneNode]
        for node in Selection.getAllSelectedObjects():
            current_node = node
            parent_node = current_node.getParent()
            while parent_node and parent_node.callDecoration("isGroup"):
                current_node = parent_node
                parent_node = current_node.getParent()
        if current_node is None:
            return

        rotate_operation = RotateOperation(current_node, rotation_quaternion, rotation_point_vector)
        operation.addOperation(rotate_operation)
        operation.push()
Exemplo n.º 4
0
def arrange(nodes_to_arrange: List["SceneNode"],
            build_volume: "BuildVolume",
            fixed_nodes: Optional[List["SceneNode"]] = None,
            factor=10000,
            add_new_nodes_in_scene: bool = False) -> bool:
    """
    Find placement for a set of scene nodes, and move them by using a single grouped operation.
    :param nodes_to_arrange: The list of nodes that need to be moved.
    :param build_volume: The build volume that we want to place the nodes in. It gets size & disallowed areas from this.
    :param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes
                        are placed.
    :param factor: The library that we use is int based. This factor defines how accuracte we want it to be.
    :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations

    :return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects
    """
    scene_root = Application.getInstance().getController().getScene().getRoot()
    found_solution_for_all, node_items = findNodePlacement(
        nodes_to_arrange, build_volume, fixed_nodes, factor)

    not_fit_count = 0
    grouped_operation = GroupedOperation()
    for node, node_item in zip(nodes_to_arrange, node_items):
        if add_new_nodes_in_scene:
            grouped_operation.addOperation(
                AddSceneNodeOperation(node, scene_root))

        if node_item.binId() == 0:
            # We found a spot for it
            rotation_matrix = Matrix()
            rotation_matrix.setByRotationAxis(node_item.rotation(),
                                              Vector(0, -1, 0))
            grouped_operation.addOperation(
                RotateOperation(node, Quaternion.fromMatrix(rotation_matrix)))
            grouped_operation.addOperation(
                TranslateOperation(
                    node,
                    Vector(node_item.translation().x() / factor, 0,
                           node_item.translation().y() / factor)))
        else:
            # We didn't find a spot
            grouped_operation.addOperation(
                TranslateOperation(node,
                                   Vector(200,
                                          node.getWorldPosition().y,
                                          -not_fit_count * 20),
                                   set_position=True))
            not_fit_count += 1
    grouped_operation.push()

    return found_solution_for_all
Exemplo n.º 5
0
    def _onSelectedFaceChanged(self):
        if not self._select_face_mode:
            return

        self._handle.setEnabled(not Selection.getFaceSelectMode())

        selected_face = Selection.getSelectedFace()
        if not Selection.getSelectedFace() or not (
                Selection.hasSelection() and Selection.getFaceSelectMode()):
            return

        original_node, face_id = selected_face
        meshdata = original_node.getMeshDataTransformed()
        if not meshdata or face_id < 0:
            return
        if face_id > (meshdata.getVertexCount() / 3 if
                      not meshdata.hasIndices() else meshdata.getFaceCount()):
            return

        face_mid, face_normal = meshdata.getFacePlane(face_id)
        object_mid = original_node.getBoundingBox().center
        rotation_point_vector = Vector(object_mid.x, object_mid.y, face_mid[2])
        face_normal_vector = Vector(face_normal[0], face_normal[1],
                                    face_normal[2])
        rotation_quaternion = Quaternion.rotationTo(
            face_normal_vector.normalized(), Vector(0.0, -1.0, 0.0))

        operation = GroupedOperation()
        current_node = None  # type: Optional[SceneNode]
        for node in Selection.getAllSelectedObjects():
            current_node = node
            parent_node = current_node.getParent()
            while parent_node and parent_node.callDecoration("isGroup"):
                current_node = parent_node
                parent_node = current_node.getParent()
        if current_node is None:
            return

        rotate_operation = RotateOperation(current_node, rotation_quaternion,
                                           rotation_point_vector)
        gravity_operation = GravityOperation(current_node)
        operation.addOperation(rotate_operation)
        operation.addOperation(gravity_operation)
        operation.push()
Exemplo n.º 6
0
    def bottomFaceSelection(self) -> None:
        selected_face = Selection.getSelectedFace()
        if not selected_face:
            Logger.log(
                "e",
                "Bottom face operation shouldn't have been called without a selected face."
            )
            return

        original_node, face_id = selected_face
        meshdata = original_node.getMeshDataTransformed()
        if not meshdata or face_id < 0 or face_id > Selection.getMaxFaceSelectionId(
        ):
            return

        rotation_point, face_normal = meshdata.getFacePlane(face_id)
        rotation_point_vector = Vector(rotation_point[0], rotation_point[1],
                                       rotation_point[2])
        face_normal_vector = Vector(face_normal[0], face_normal[1],
                                    face_normal[2])
        rotation_quaternion = Quaternion.rotationTo(
            face_normal_vector.normalized(), Vector(0.0, -1.0, 0.0))

        operation = GroupedOperation()
        current_node = None  # type: Optional[SceneNode]
        for node in Selection.getAllSelectedObjects():
            current_node = node
            parent_node = current_node.getParent()
            while parent_node and parent_node.callDecoration("isGroup"):
                current_node = parent_node
                parent_node = current_node.getParent()
        if current_node is None:
            return

        rotate_operation = RotateOperation(current_node, rotation_quaternion,
                                           rotation_point_vector)
        operation.addOperation(rotate_operation)
        operation.push()
Exemplo n.º 7
0
    def event(self, event):
        super().event(event)

        if event.type == Event.KeyPressEvent and event.key == KeyEvent.ShiftKey:
            # Snap is toggled when pressing the shift button
            self.setRotationSnap(not self._snap_rotation)

        if event.type == Event.KeyReleaseEvent and event.key == KeyEvent.ShiftKey:
            # Snap is "toggled back" when releasing the shift button
            self.setRotationSnap(not self._snap_rotation)

        if event.type == Event.MousePressEvent and self._controller.getToolsEnabled(
        ):
            # Start a rotate operation
            if MouseEvent.LeftButton not in event.buttons:
                return False

            id = self._selection_pass.getIdAtPosition(event.x, event.y)
            if not id:
                return False

            if self._handle.isAxis(id):
                self.setLockedAxis(id)
            else:
                # Not clicked on an axis: do nothing.
                return False

            handle_position = self._handle.getWorldPosition()

            # Save the current positions of the node, as we want to rotate around their current centres
            self._saved_node_positions = []
            for node in self._getSelectedObjectsWithoutSelectedAncestors():
                self._saved_node_positions.append((node, node.getPosition()))

            if id == ToolHandle.XAxis:
                self.setDragPlane(Plane(Vector(1, 0, 0), handle_position.x))
            elif id == ToolHandle.YAxis:
                self.setDragPlane(Plane(Vector(0, 1, 0), handle_position.y))
            elif self._locked_axis == ToolHandle.ZAxis:
                self.setDragPlane(Plane(Vector(0, 0, 1), handle_position.z))
            else:
                self.setDragPlane(Plane(Vector(0, 1, 0), handle_position.y))

            self.setDragStart(event.x, event.y)
            self._rotating = False
            self._angle = 0
            return True

        if event.type == Event.MouseMoveEvent:
            # Perform a rotate operation
            if not self.getDragPlane():
                return False

            if not self.getDragStart():
                self.setDragStart(event.x, event.y)
                if not self.getDragStart():  #May have set it to None.
                    return False

            if not self._rotating:
                self._rotating = True
                self.operationStarted.emit(self)

            handle_position = self._handle.getWorldPosition()

            drag_start = (self.getDragStart() - handle_position).normalized()
            drag_position = self.getDragPosition(event.x, event.y)
            if not drag_position:
                return False
            drag_end = (drag_position - handle_position).normalized()

            try:
                angle = math.acos(drag_start.dot(drag_end))
            except ValueError:
                angle = 0

            if self._snap_rotation:
                angle = int(angle / self._snap_angle) * self._snap_angle
                if angle == 0:
                    return False

            rotation = None
            if self.getLockedAxis() == ToolHandle.XAxis:
                direction = 1 if Vector.Unit_X.dot(
                    drag_start.cross(drag_end)) > 0 else -1
                rotation = Quaternion.fromAngleAxis(direction * angle,
                                                    Vector.Unit_X)
            elif self.getLockedAxis() == ToolHandle.YAxis:
                direction = 1 if Vector.Unit_Y.dot(
                    drag_start.cross(drag_end)) > 0 else -1
                rotation = Quaternion.fromAngleAxis(direction * angle,
                                                    Vector.Unit_Y)
            elif self.getLockedAxis() == ToolHandle.ZAxis:
                direction = 1 if Vector.Unit_Z.dot(
                    drag_start.cross(drag_end)) > 0 else -1
                rotation = Quaternion.fromAngleAxis(direction * angle,
                                                    Vector.Unit_Z)
            else:
                direction = -1

            # Rate-limit the angle change notification
            # This is done to prevent the UI from being flooded with property change notifications,
            # which in turn would trigger constant repaints.
            new_time = time.monotonic()
            if not self._angle_update_time or new_time - self._angle_update_time > 0.1:
                self._angle_update_time = new_time
                self._angle += direction * angle
                self.propertyChanged.emit()

                # Rotate around the saved centeres of all selected nodes
                if len(self._saved_node_positions) > 1:
                    op = GroupedOperation()
                    for node, position in self._saved_node_positions:
                        op.addOperation(
                            RotateOperation(node,
                                            rotation,
                                            rotate_around_point=position))
                    op.push()
                else:
                    for node, position in self._saved_node_positions:
                        RotateOperation(node,
                                        rotation,
                                        rotate_around_point=position).push()

                self.setDragStart(event.x, event.y)
            return True

        if event.type == Event.MouseReleaseEvent:
            # Finish a rotate operation
            if self.getDragPlane():
                self.setDragPlane(None)
                self.setLockedAxis(ToolHandle.NoAxis)
                self._angle = None
                self.propertyChanged.emit()
                if self._rotating:
                    self.operationStopped.emit(self)
                return True