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

如何实现旋转扇形(Circle Slice)与固定矩形的碰撞检测?

解决旋转扇形与固定矩形的碰撞检测问题

你的代码核心问题是坐标系不匹配:扇形路径是在经过translate和rotate后的局部坐标系中创建的,但检测碰撞时用的是全局坐标系下的barrier矩形,导致path.contains(barrier)的判断完全错误。

解决思路

要正确检测碰撞,需要将固定矩形barrier转换到扇形所在的局部坐标系中,步骤如下:

  1. 在执行坐标系变换(translate/rotate)前,获取painter的变换矩阵;
  2. 将全局坐标系的barrier矩形,通过逆变换转换到局部坐标系;
  3. 用转换后的矩形与扇形路径做相交检测。

修改后的关键代码

在paintEvent中,调整碰撞检测的部分:

def paintEvent(self, event: QPaintEvent) -> super:
    # ... 其他代码保持不变 ...
    painter.setPen(QPen(QColor(20, 20, 20),  -1, Qt.PenStyle.SolidLine))
    painter.setBrush(QBrush(QColor(20, 20, 160), Qt.BrushStyle.SolidPattern))
    barrier = QRectF(1920//2-25, 1080//2-25-40, 50, 20)
    painter.drawRect(barrier)
    
    # 保存初始变换状态,获取逆变换用于转换barrier
    painter.save()
    painter.translate(QPoint(1920//2, 1080//2))
    painter.rotate(self.angle)
    # 获取当前变换的逆变换,将全局坐标的barrier转换到局部坐标系
    transform = painter.worldTransform().inverted()[0]
    local_barrier = transform.mapRect(barrier)
    
    painter.setBrush(QBrush(QColor(200, 200, 200, 50), Qt.BrushStyle.SolidPattern))
    r = 200
    a = 40
    b = a * 2
    rect = QRectF(-r/2, -r/2, r, r)
    
    # 前视角扇形
    path = QPainterPath()
    path.arcTo(rect, -a, b)
    path.closeSubpath()
    # 用转换后的local_barrier检测相交
    if path.intersects(local_barrier):
        painter.setBrush(QBrush(QColor(200, 20, 20, 50), Qt.BrushStyle.SolidPattern))
    else:
        painter.setBrush(QBrush(QColor(20, 200, 20, 50), Qt.BrushStyle.SolidPattern))
    painter.drawPath(path)
    
    # 右视角扇形(原+90度)
    path = QPainterPath()
    path.arcTo(rect, -a+90, b)
    path.closeSubpath()
    if path.intersects(local_barrier):
        painter.setBrush(QBrush(QColor(200, 20, 20, 50), Qt.BrushStyle.SolidPattern))
    else:
        painter.setBrush(QBrush(QColor(20, 200, 20, 50), Qt.BrushStyle.SolidPattern))
    painter.drawPath(path)
    
    # 左视角扇形(原-90度)
    path = QPainterPath()
    path.arcTo(rect, -a-90, b)
    path.closeSubpath()
    if path.intersects(local_barrier):
        painter.setBrush(QBrush(QColor(200, 20, 20, 50), Qt.BrushStyle.SolidPattern))
    else:
        painter.setBrush(QBrush(QColor(20, 200, 20, 50), Qt.BrushStyle.SolidPattern))
    painter.drawPath(path)
    
    # ... 后续绘制代码保持不变 ...
    painter.restore()  # 恢复初始变换状态
    painter.end()
    self.angle += 1
    if self.angle == 360:
        self.angle = 0
    return super().paintEvent(event)

关键修改点说明

  1. 坐标系转换:通过painter.worldTransform().inverted()获取当前变换的逆矩阵,将全局坐标系的barrier转换到旋转后的局部坐标系,得到local_barrier;
  2. 碰撞检测方法:使用path.intersects()替代path.contains(),因为contains()要求矩形完全在路径内,而intersects()只要有重叠就会返回True,更符合“相交/碰撞”的需求;
  3. 状态保存与恢复:用painter.save()和painter.restore()确保后续绘制不受当前变换影响,这是GUI绘制的良好习惯。

其他优化建议

  • 可以将扇形的创建逻辑封装成函数,避免重复代码;
  • 把窗口尺寸(1920、1080)定义为类变量,避免硬编码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 10:55:50