我正在实现一个使用角手柄旋转形状的功能.旋转对于正方形效果很好,但我面临的问题是非正方形(长宽比不同于1:1的矩形).当通过拖动角控制柄旋转这些形状时,它们会意外地"捕捉"或旋转,而不考虑形状的纵横比.这会导致光标的初始单击点和形状的旋转行为之间不对齐.

我怀疑问题在于我的旋转计算,它没有考虑纵横比,导致旋转过程中的Angular 偏移不正确.

如何正确计算旋转,并考虑形状的纵横比,以确保用户旋转非正方形形状时的流畅和预期行为?

也许我也在试着解决一个问题的问题,所以我想解决的核心问题基本上是如何通过角手柄绕中心旋转一个矩形.你可以看到这video个人的行为.

代码:

pub fn handle_rotating(
    composition: &CompositionRes,
    selected_nodes_query: &mut Query<
        (
            &mut RelativeTransformMixin,
            &AbsoluteTransformMixin,
            &mut DimensionMixin,
        ),
        With<Selected>,
    >,
    event: &CursorMovedOnComposition,
    corner: u8,
    initial_rotation: f32,
) {
    let CursorMovedOnComposition {
        position: cursor_position,
        ..
    } = event;
    let cursor_position = transform_point_to_view_box(composition, cursor_position, true);

    selected_nodes_query.for_each_mut(
        |(mut relative_transform_mixin, absolute_transform_mixin, dimension_mixin)| {
            let relative_pivot_point = Vec2::new(
                dimension_mixin.width as f32 / 2.0,
                dimension_mixin.height as f32 / 2.0,
            );
            let absolute_pivot_point =
                apply_transform_to_point(absolute_transform_mixin.0, relative_pivot_point);

            // Determine rotation offset based on corner
            let rotation_offset_in_radians: f32 = match corner {
                _ if corner == (HandleSide::Top as u8 | HandleSide::Left as u8) => {
                    (-135.0 as f32).to_radians()
                }
                _ if corner == (HandleSide::Top as u8 | HandleSide::Right as u8) => {
                    (-45.0 as f32).to_radians()
                }
                _ if corner == (HandleSide::Bottom as u8 | HandleSide::Right as u8) => {
                    (45.0 as f32).to_radians()
                }
                _ if corner == (HandleSide::Bottom as u8 | HandleSide::Left as u8) => {
                    (135.0 as f32).to_radians()
                }
                _ => 0.0,
            };

            // Calculate rotation based on the corner
            let rotation_angle =
                calculate_rotation(initial_rotation, &cursor_position, &absolute_pivot_point);
            let final_rotation_angle =
                rotation_angle + rotation_offset_in_radians - initial_rotation;
            relative_transform_mixin.0 = set_rotation(
                relative_transform_mixin.0,
                final_rotation_angle,
                relative_pivot_point,
            );
        },
    );
}

fn calculate_rotation(
    initial_angle_in_radians: f32,
    cursor_point: &Vec2,
    pivot_point: &Vec2,
) -> f32 {
    // Calculate the angle from the pivot point to the current cursor position
    let current_angle = (cursor_point.y - pivot_point.y).atan2(cursor_point.x - pivot_point.x);

    // Calculate the raw angle difference
    let angle_diff = current_angle - initial_angle_in_radians;

    return -angle_diff;
}

推荐答案

rotation_offset_in_radians个值设置错误.对应于各个角的Angular 假设形状为正方形,因此从中心看,角间隔90度.在矩形中则不是这样:

Angles in a square, angles in a rectangle

你需要做的是使用矩形的长宽比(或其实际尺寸,没有区别),结合例如atan2来计算每个角对应的Angular .

当宽度和高度相同时,这将提供与原始代码相同的Angular :

let width: f32 = dimension_mixin.width as f32;
let height: f32 = dimension_mixin.height as f32;
let rotation_offset_in_radians: f32 = match corner {
    _ if corner == (HandleSide::Top as u8 | HandleSide::Left as u8) => f32::atan2(-height, -width),
    _ if corner == (HandleSide::Top as u8 | HandleSide::Right as u8) => f32::atan2(-height, width),
    _ if corner == (HandleSide::Bottom as u8 | HandleSide::Right as u8) => f32::atan2(height, width),
    _ if corner == (HandleSide::Bottom as u8 | HandleSide::Left as u8) => f32::atan2(height, -width),
    _ => 0.0,
};

Rust相关问答推荐

限制未使用的泛型导致编译错误

异步FN中的 rust 递归

在Rust中宏的表达式中提取对象

在铁 rust 中传递所有权

如何循环遍历0..V.len()-1何时v可能为空?

如何在不调用Collect()的情况下为新型vec实现IntoIterator?

如何创建一个可变的嵌套迭代器?

如何获取光标下的像素 colored颜色 ?

Rust wasm 中的 Closure::new 和 Closure::wrap 有什么区别

Rust,如何从 Rc> 复制内部值并返回它?

通过写入 std::io::stdout() 输出不可见

当推送到 HashMap 中的 Vector 时,类型 `()` 无法取消引用

如何使用 Bincode 在 Rust 中序列化 Enum,同时保留 Enum 判别式而不是索引?

在 Rust 中忽略 None 值的正确样式

从 Rust 中的 if/else 中的引用创建 MappedRwLockWriteGuard

为什么不可变特征的实现可以是可变的?

从 HashMap>, _> 中删除的生命周期问题

SDL2 没有在终端键上触发?

Rust,使用枚举从 HashMap 获取值

如果我立即等待,为什么 `tokio::spawn` 需要一个 `'static` 生命周期?