You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中旋转Canvas矩形后如何计算其Rect的LTRB值?

计算Canvas旋转矩形后的LTRB参数

核心思路

要得到旋转后矩形的LTRB(左、上、右、下)参数,本质是找到矩形四个顶点旋转后的全局坐标,再取这些坐标的最小/最大X、Y值,步骤如下:

  1. 确定旋转中心(此处为原矩形左上角(100,100))
  2. 将原矩形四个顶点转换为以旋转中心为原点的局部坐标
  3. 对每个局部坐标应用旋转公式
  4. 把旋转后的局部坐标转换回全局坐标
  5. 从四个全局坐标中提取minX(左)、minY(上)、maxX(右)、maxY(下)

具体计算步骤

原矩形Rect.fromLTRB(100,100,200,200)的四个全局顶点:

  • 左上角:(100, 100)
  • 右上角:(200, 100)
  • 右下角:(200, 200)
  • 左下角:(100, 200)

1. 转换为旋转中心的局部坐标

以(100,100)为原点,局部坐标 = 全局坐标 - (100,100):

  • 左上角:(0, 0)
  • 右上角:(100, 0)
  • 右下角:(100, 100)
  • 左下角:(0, 100)

2. 应用旋转公式

旋转角度30°,对应弧度radians = π/6,三角函数值:
cos30° = √3/2 ≈ 0.8660,sin30° = 0.5

旋转公式(局部坐标(x,y)旋转后得到(x', y')):

x' = x * cosθ - y * sinθ
y' = x * sinθ + y * cosθ

逐个计算旋转后的局部坐标:

  • 左上角:(0*0.8660 - 0*0.5, 0*0.5 + 0*0.8660) = (0, 0)
  • 右上角:(100*0.8660 - 0*0.5, 100*0.5 + 0*0.8660) = (86.60, 50)
  • 右下角:(100*0.8660 - 100*0.5, 100*0.5 + 100*0.8660) = (36.60, 136.60)
  • 左下角:(0*0.8660 - 100*0.5, 0*0.5 + 100*0.8660) = (-50, 86.60)

3. 转换回全局坐标

全局坐标 = 旋转后局部坐标 + (100,100):

  • 左上角:(100+0, 100+0) = (100, 100)
  • 右上角:(100+86.60, 100+50) = (186.60, 150)
  • 右下角:(100+36.60, 100+136.60) = (136.60, 236.60)
  • 左下角:(100-50, 100+86.60) = (50, 186.60)

4. 提取LTRB参数

从四个全局坐标中取极值:

  • 左(minX):50
  • 上(minY):100
  • 右(maxX):186.60
  • 下(maxY):236.60

最终旋转后的Rect为:Rect.fromLTRB(50, 100, 186.60, 236.60)

通用代码实现(Flutter环境)

如果需要动态计算任意矩形和角度,可以封装成方法:

import 'dart:math' as math;

Rect getRotatedRect(Rect originalRect, double degrees, Offset pivot) {
  final radians = degrees * math.pi / 180;
  final cosθ = math.cos(radians);
  final sinθ = math.sin(radians);

  // 原矩形四个顶点
  final points = [
    originalRect.topLeft,
    originalRect.topRight,
    originalRect.bottomRight,
    originalRect.bottomLeft,
  ];

  List<Offset> rotatedPoints = [];
  for (var point in points) {
    // 转换为局部坐标
    double localX = point.dx - pivot.dx;
    double localY = point.dy - pivot.dy;
    // 旋转
    double rotatedLocalX = localX * cosθ - localY * sinθ;
    double rotatedLocalY = localX * sinθ + localY * cosθ;
    // 转回全局坐标
    rotatedPoints.add(Offset(pivot.dx + rotatedLocalX, pivot.dy + rotatedLocalY));
  }

  // 找极值
  double minX = rotatedPoints.reduce((a, b) => a.dx < b.dx ? a : b).dx;
  double maxX = rotatedPoints.reduce((a, b) => a.dx > b.dx ? a : b).dx;
  double minY = rotatedPoints.reduce((a, b) => a.dy < b.dy ? a : b).dy;
  double maxY = rotatedPoints.reduce((a, b) => a.dy > b.dy ? a : b).dy;

  return Rect.fromLTRB(minX, minY, maxX, maxY);
}

// 使用示例
void main() {
  Rect rect = Rect.fromLTRB(100, 100, 200, 200);
  Offset pivot = Offset(100, 100);
  Rect rotatedRect = getRotatedRect(rect, 30, pivot);
  print(rotatedRect); // 输出 Rect.fromLTRB(50.0, 100.0, 186.60254037844386, 236.60254037844386)
}

内容的提问来源于stack exchange,提问作者Kevin Yang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 15:57:20