def test_setSimpleScale(): node = SceneNode() op = ScaleOperation(node, Vector(1, 2, 3), set_scale = True) op.redo() assert node.getScale() == Vector(1, 2, 3) op.undo() assert node.getScale() == Vector(1, 1, 1)
def _scaleSelectedNodes(self, scale_vector: Vector) -> None: selected_nodes = self._getSelectedObjectsWithoutSelectedAncestors() if len(selected_nodes) > 1: op = GroupedOperation() for node in selected_nodes: op.addOperation(ScaleOperation(node, scale_vector, scale_around_point=node.getWorldPosition())) op.push() else: for node in selected_nodes: ScaleOperation(node, scale_vector, scale_around_point=node.getWorldPosition()).push()
def test_relativeScale(): node = SceneNode() op = ScaleOperation(node, Vector(2, 2, 2), set_scale=True) op.redo() op2 = ScaleOperation(node, Vector(1, 2, 3), relative_scale=True) op2.redo() assert node.getScale() == Vector(3, 4, 5)
def test_addScale(): node = SceneNode() op = ScaleOperation(node, Vector(1, 2, 3), set_scale=True) op.redo() op2 = ScaleOperation(node, Vector(1, 2, 3), add_scale=True) op2.redo() assert node.getScale() == Vector(2, 4, 6)
def event(self, event): super().event(event) if event.type == Event.MousePressEvent: if MouseEvent.LeftButton not in event.buttons: return False id = self._renderer.getIdAtCoordinate(event.x, event.y) if not id: return False if ToolHandle.isAxis(id): self.setLockedAxis(id) return True if event.type == Event.MouseReleaseEvent: if self.getLockedAxis(): op = None if Selection.getCount() == 1: node = Selection.getSelectedObject(0) scale = node.getScale() if self.getLockedAxis() == ToolHandle.XAxis: scale.setX(-scale.x) elif self.getLockedAxis() == ToolHandle.YAxis: scale.setY(-scale.y) elif self.getLockedAxis() == ToolHandle.ZAxis: scale.setZ(-scale.z) op = ScaleOperation(node, scale, set_scale=True) else: op = GroupedOperation() for node in Selection.getAllSelectedObjects(): scale = node.getScale() if self.getLockedAxis() == ToolHandle.XAxis: scale.setX(-scale.x) elif self.getLockedAxis() == ToolHandle.YAxis: scale.setY(-scale.y) elif self.getLockedAxis() == ToolHandle.ZAxis: scale.setZ(-scale.z) op.addOperation( ScaleOperation(node, scale, set_scale=True)) op.push() self.setLockedAxis(None) return True return False
def test_relativeScale(): node = SceneNode() op = ScaleOperation(node, Vector(2, 2, 2), set_scale=True) op.redo() op2 = ScaleOperation(node, Vector(1, 2, 3), relative_scale=True) op2.redo() assert node.getScale() == Vector(3, 4, 5)
def test_addScale(): node = SceneNode() op = ScaleOperation(node, Vector(1, 2, 3), set_scale = True) op.redo() op2 = ScaleOperation(node, Vector(1, 2, 3), add_scale = True) op2.redo() assert node.getScale() == Vector(2, 4, 6)
def test_setSimpleScale(): node = SceneNode() op = ScaleOperation(node, Vector(1, 2, 3), set_scale=True) op.redo() assert node.getScale() == Vector(1, 2, 3) op.undo() assert node.getScale() == Vector(1, 1, 1)
def setScaleZ(self, scale): obj = Selection.getSelectedObject(0) if obj: obj_scale = obj.getScale() if round(float(obj_scale.z), 4) != scale: scale_factor = abs(scale / obj_scale.z) if self._non_uniform_scale: scale_vector = Vector(1, 1, scale_factor) else: scale_vector = Vector(scale_factor, scale_factor, scale_factor) op = GroupedOperation() for node in self._getSelectedObjectsWithoutSelectedAncestors(): op.addOperation( ScaleOperation( node, scale_vector, scale_around_point=node.getWorldPosition())) op.push()
def setScaleZ(self, scale): obj = Selection.getSelectedObject(0) if obj: obj_scale = self._getScaleInWorldCoordinates(obj) if round(float(obj_scale.z), 4) != scale: scale_factor = abs(scale / obj_scale.z) if self._non_uniform_scale: scale_vector = Vector(1, 1, scale_factor) else: scale_vector = Vector(scale_factor, scale_factor, scale_factor) op = GroupedOperation() for node in Selection.getAllSelectedObjects(): op.addOperation( ScaleOperation( node, scale_vector, scale_around_point=node.getWorldPosition())) op.push()
def event(self, event): super().event(event) if event.type == Event.MousePressEvent: if MouseEvent.LeftButton not in event.buttons: return False id = self._renderer.getIdAtCoordinate(event.x, event.y) if not id: return False if ToolHandle.isAxis(id): self.setLockedAxis(id) return True if event.type == Event.MouseReleaseEvent: if self.getLockedAxis(): op = None if Selection.getCount() == 1: node = Selection.getSelectedObject(0) scale = node.getScale() if self.getLockedAxis() == ToolHandle.XAxis: scale.setX(-scale.x) elif self.getLockedAxis() == ToolHandle.YAxis: scale.setY(-scale.y) elif self.getLockedAxis() == ToolHandle.ZAxis: scale.setZ(-scale.z) op = ScaleOperation(node, scale, set_scale=True) else: op = GroupedOperation() for node in Selection.getAllSelectedObjects(): scale = node.getScale() if self.getLockedAxis() == ToolHandle.XAxis: scale.setX(-scale.x) elif self.getLockedAxis() == ToolHandle.YAxis: scale.setY(-scale.y) elif self.getLockedAxis() == ToolHandle.ZAxis: scale.setZ(-scale.z) op.addOperation(ScaleOperation(node, scale, set_scale = True)) op.push() self.setLockedAxis(None) return True return False
def setObjectDepth(self, depth): obj = Selection.getSelectedObject(0) if obj: depth = float(depth) obj_depth = obj.getBoundingBox().depth if not Float.fuzzyCompare(obj_depth, depth, DIMENSION_TOLERANCE): scale_factor = depth / obj_depth if self._non_uniform_scale: scale_vector = Vector(1, 1, scale_factor) else: scale_vector = Vector(scale_factor, scale_factor, scale_factor) op = GroupedOperation() for node in self._getSelectedObjectsWithoutSelectedAncestors(): op.addOperation( ScaleOperation( node, scale_vector, scale_around_point=node.getWorldPosition())) op.push()
def setScaleY(self, scale): obj = Selection.getSelectedObject(0) if obj: obj_scale = self.getObjectHeight() / obj.getMeshData().getExtents( ).height if round(float(obj_scale), 4) != scale: scale_factor = abs(scale / obj_scale) if self._non_uniform_scale: scale_vector = Vector(1, scale_factor, 1) else: scale_vector = Vector(scale_factor, scale_factor, scale_factor) op = GroupedOperation() for node in self._getSelectedObjectsWithoutSelectedAncestors(): op.addOperation( ScaleOperation( node, scale_vector, scale_around_point=node.getWorldPosition())) op.push()
def setObjectHeight(self, height): obj = Selection.getSelectedObject(0) if obj: height = float(height) obj_height = obj.getBoundingBox().height if not Float.fuzzyCompare(obj_height, height, DIMENSION_TOLERANCE): scale_factor = height / obj_height if self._non_uniform_scale: scale_vector = Vector(1, scale_factor, 1) else: scale_vector = Vector(scale_factor, scale_factor, scale_factor) op = GroupedOperation() for node in self._getSelectedObjectsWithoutSelectedAncestors(): op.addOperation( ScaleOperation( node, scale_vector, scale_around_point=node.getWorldPosition())) op.push()
def setObjectWidth(self, width): obj = Selection.getSelectedObject(0) if obj: width = float(width) obj_width = obj.getBoundingBox().width if not Float.fuzzyCompare(obj_width, width, DIMENSION_TOLERANCE): scale_factor = width / obj_width if self._non_uniform_scale: scale_vector = Vector(scale_factor, 1, 1) else: scale_vector = Vector(scale_factor, scale_factor, scale_factor) op = GroupedOperation() for node in Selection.getAllSelectedObjects(): op.addOperation( ScaleOperation( node, scale_vector, scale_around_point=node.getWorldPosition())) op.push()
def event(self, event): """Handle mouse and keyboard events :param event: type(Event) """ super().event(event) if event.type == Event.ToolActivateEvent: for node in self._getSelectedObjectsWithoutSelectedAncestors(): node.boundingBoxChanged.connect(self.propertyChanged) if event.type == Event.ToolDeactivateEvent: for node in self._getSelectedObjectsWithoutSelectedAncestors(): node.boundingBoxChanged.disconnect(self.propertyChanged) # Handle modifier keys: Shift toggles snap, Control toggles uniform scaling if event.type == Event.KeyPressEvent: if event.key == KeyEvent.ShiftKey: self.setScaleSnap(not self._snap_scale) elif event.key == KeyEvent.ControlKey: self.setNonUniformScale(not self._non_uniform_scale) if event.type == Event.KeyReleaseEvent: if event.key == KeyEvent.ShiftKey: self.setScaleSnap(not self._snap_scale) elif event.key == KeyEvent.ControlKey: self.setNonUniformScale(not self._non_uniform_scale) if event.type == Event.MousePressEvent and self._controller.getToolsEnabled( ): # Initialise a scale 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) self._saved_handle_position = self._handle.getWorldPosition() # Save the current positions of the node, as we want to scale arround their current centres self._saved_node_positions = [] for node in self._getSelectedObjectsWithoutSelectedAncestors(): self._saved_node_positions.append((node, node.getPosition())) self._scale_sum = 0.0 self._last_event = event if id == ToolHandle.XAxis: self.setDragPlane( Plane(Vector(0, 0, 1), self._saved_handle_position.z)) elif id == ToolHandle.YAxis: self.setDragPlane( Plane(Vector(0, 0, 1), self._saved_handle_position.z)) elif id == ToolHandle.ZAxis: self.setDragPlane( Plane(Vector(0, 1, 0), self._saved_handle_position.y)) else: self.setDragPlane( Plane(Vector(0, 1, 0), self._saved_handle_position.y)) self.setDragStart(event.x, event.y) return True if event.type == Event.MouseMoveEvent: # Perform a scale operation if not self.getDragPlane(): return False drag_position = self.getDragPosition(event.x, event.y) if drag_position: if self.getLockedAxis() == ToolHandle.XAxis: drag_position = drag_position.set(y=0, z=0) elif self.getLockedAxis() == ToolHandle.YAxis: drag_position = drag_position.set(x=0, z=0) elif self.getLockedAxis() == ToolHandle.ZAxis: drag_position = drag_position.set(x=0, y=0) drag_length = (drag_position - self._saved_handle_position).length() if self._drag_length > 0: drag_change = (drag_length - self._drag_length) / 100 * self._scale_speed if self.getLockedAxis() in [ ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis ]: # drag the handle, axis is already determined if self._snap_scale: scale_factor = round(drag_change, 1) else: scale_factor = drag_change else: # uniform scaling; because we use central cube, we use the screen x, y for scaling. # upper right is scale up, lower left is scale down scale_factor_delta = ( (self._last_event.y - event.y) - (self._last_event.x - event.x)) * self._scale_speed self._scale_sum += scale_factor_delta if self._snap_scale: scale_factor = round(self._scale_sum, 1) # remember the decimals when snap scaling self._scale_sum -= scale_factor else: scale_factor = self._scale_sum self._scale_sum = 0.0 if scale_factor: scale_change = Vector(0.0, 0.0, 0.0) if self._non_uniform_scale: if self.getLockedAxis() == ToolHandle.XAxis: scale_change = scale_change.set(x=scale_factor) elif self.getLockedAxis() == ToolHandle.YAxis: scale_change = scale_change.set(y=scale_factor) elif self.getLockedAxis() == ToolHandle.ZAxis: scale_change = scale_change.set(z=scale_factor) else: # Middle handle scale_change = scale_change.set(x=scale_factor, y=scale_factor, z=scale_factor) else: scale_change = scale_change.set(x=scale_factor, y=scale_factor, z=scale_factor) # Scale around the saved centers of all selected nodes if len(self._saved_node_positions) > 1: op = GroupedOperation() for node, position in self._saved_node_positions: op.addOperation( ScaleOperation( node, scale_change, relative_scale=True, scale_around_point=position)) op.push() else: for node, position in self._saved_node_positions: ScaleOperation( node, scale_change, relative_scale=True, scale_around_point=position).push() self._drag_length = (self._saved_handle_position - drag_position).length() else: self.operationStarted.emit(self) self._drag_length = ( self._saved_handle_position - drag_position ).length() #First move, do nothing but set right length. self._last_event = event # remember for uniform drag return True if event.type == Event.MouseReleaseEvent: # Finish a scale operation if self.getDragPlane(): self.setDragPlane(None) self.setLockedAxis(ToolHandle.NoAxis) self._drag_length = 0 self.operationStopped.emit(self) return True
def event(self, event): super().event(event) if event.type == Event.ToolActivateEvent: self._old_scale = Selection.getSelectedObject(0).getScale() for node in Selection.getAllSelectedObjects(): node.boundingBoxChanged.connect(self.propertyChanged) if event.type == Event.ToolDeactivateEvent: for node in Selection.getAllSelectedObjects(): node.boundingBoxChanged.disconnect(self.propertyChanged) # Handle modifier keys: Shift toggles snap, Control toggles uniform scaling if event.type == Event.KeyPressEvent: if event.key == KeyEvent.ShiftKey: self._snap_scale = False self.propertyChanged.emit() elif event.key == KeyEvent.ControlKey: self._non_uniform_scale = True self.propertyChanged.emit() if event.type == Event.KeyReleaseEvent: if event.key == KeyEvent.ShiftKey: self._snap_scale = True self.propertyChanged.emit() elif event.key == KeyEvent.ControlKey: self._non_uniform_scale = False self.propertyChanged.emit() if event.type == Event.MousePressEvent and self._controller.getToolsEnabled(): # Initialise a scale 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 ToolHandle.isAxis(id): self.setLockedAxis(id) # Save the current positions of the node, as we want to scale arround their current centres self._saved_node_positions = [] for node in Selection.getAllSelectedObjects(): self._saved_node_positions.append((node, node.getWorldPosition())) self._saved_handle_position = self._handle.getWorldPosition() if id == ToolHandle.XAxis: self.setDragPlane(Plane(Vector(0, 0, 1), self._saved_handle_position.z)) elif id == ToolHandle.YAxis: self.setDragPlane(Plane(Vector(0, 0, 1), self._saved_handle_position.z)) elif id == ToolHandle.ZAxis: self.setDragPlane(Plane(Vector(0, 1, 0), self._saved_handle_position.y)) else: self.setDragPlane(Plane(Vector(0, 1, 0), self._saved_handle_position.y)) self.setDragStart(event.x, event.y) self.operationStarted.emit(self) if event.type == Event.MouseMoveEvent: # Perform a scale operation if not self.getDragPlane(): return False drag_position = self.getDragPosition(event.x, event.y) if drag_position: drag_length = (drag_position - self._saved_handle_position).length() if self._drag_length > 0: drag_change = (drag_length - self._drag_length) / 100 * self._scale_speed if self._snap_scale: scale_factor = round(drag_change, 1) else: scale_factor = drag_change if scale_factor: scale_change = Vector(0.0, 0.0, 0.0) if self._non_uniform_scale: if self.getLockedAxis() == ToolHandle.XAxis: scale_change.setX(scale_factor) elif self.getLockedAxis() == ToolHandle.YAxis: scale_change.setY(scale_factor) elif self.getLockedAxis() == ToolHandle.ZAxis: scale_change.setZ(scale_factor) else: scale_change.setX(scale_factor) scale_change.setY(scale_factor) scale_change.setZ(scale_factor) # Scale around the saved centeres of all selected nodes op = GroupedOperation() for node, position in self._saved_node_positions: op.addOperation(ScaleOperation(node, scale_change, relative_scale = True, scale_around_point = position)) op.push() self._drag_length = (self._saved_handle_position - drag_position).length() else: self._drag_length = (self._saved_handle_position - drag_position).length() #First move, do nothing but set right length. return True if event.type == Event.MouseReleaseEvent: # Finish a scale operation if self.getDragPlane(): self.setDragPlane(None) self.setLockedAxis(None) self._drag_length = 0 self.operationStopped.emit(self) return True