Flutter中旋转Canvas矩形后如何计算其Rect的LTRB值?
计算Canvas旋转矩形后的LTRB参数
核心思路
要得到旋转后矩形的LTRB(左、上、右、下)参数,本质是找到矩形四个顶点旋转后的全局坐标,再取这些坐标的最小/最大X、Y值,步骤如下:
- 确定旋转中心(此处为原矩形左上角
(100,100)) - 将原矩形四个顶点转换为以旋转中心为原点的局部坐标
- 对每个局部坐标应用旋转公式
- 把旋转后的局部坐标转换回全局坐标
- 从四个全局坐标中提取
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
相关产品推荐
相关产品推荐

