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

如何检测旋转Line与固定Circle的碰撞并改变Circle颜色?

问题描述

我有一个旋转的Line和一个固定的Circle,希望检测两者发生碰撞时,对应改变Circle的颜色。我尝试使用Intersection()函数,但怀疑由于Line不是VMobject导致该函数无效(我并不完全确定这一点)。

请问该如何实现这一需求?以下是我的简化代码:

class Test(Scene):
    def construct(self):
        b1_l = Line([-1.,-1.,0.],[3,3,0]).set_color(YELLOW).set_angle(57.5)
        obj_1 = Circle(radius=.1, color=RED, fill_opacity=1).move_to([0,1.5,0])

        def updateObject(obj: Mobject):
                    if(Intersection(obj, b1_l).has_points()):
                        obj.set_color(BLUE) # Never here
                    else:
                        obj.set_color(YELLOW) # Always here

        obj_1.add_updater(updateObject)

        self.add(obj_1)
        self.play(b1_l.animate.set_angle(57.5*DEGREES + 20*DEGREES))
        self.wait(0.05)
        self.play(b1_l.animate.set_angle(57.5*DEGREES))

目前代码运行后仅显示黄色Circle,两者碰撞时没有任何颜色变化。


解决方案

问题根源

Intersection函数对Line这类1D的VMobject(Line实际是VMobject子类)检测精度极低,因为它依赖Mobject的填充区域或采样点,而Line本身无填充,仅靠线条采样点很难与Circle区域产生有效交集检测。

两种可行实现方式

方式一:几何公式判断(精度高,推荐)

直接通过几何计算判断线段与圆是否相交:

from manim import *

class Test(Scene):
    def construct(self):
        b1_l = Line([-1.,-1.,0.],[3,3,0]).set_color(YELLOW).set_angle(57.5 * DEGREES)
        obj_1 = Circle(radius=.1, color=RED, fill_opacity=1).move_to([0,1.5,0])

        def updateObject(obj: Mobject):
            # 获取线段端点与圆心坐标
            start, end = b1_l.get_start_and_end()
            center = obj.get_center()
            # 计算线段方向向量与圆心到起点的向量
            line_vec = end - start
            center_to_start = center - start
            # 计算圆心投影在线段上的位置,限制在线段范围内
            t = np.dot(center_to_start, line_vec) / np.dot(line_vec, line_vec)
            t_clamped = max(0, min(1, t))
            # 线段上离圆心最近的点
            closest_point = start + t_clamped * line_vec
            # 判断距离是否小于等于圆半径
            if np.linalg.norm(center - closest_point) <= obj.radius:
                obj.set_color(BLUE)
            else:
                obj.set_color(YELLOW)

        obj_1.add_updater(updateObject)

        self.add(b1_l, obj_1)  # 必须将Line添加到场景中
        self.play(b1_l.animate.set_angle(57.5*DEGREES + 20*DEGREES))
        self.wait(0.05)
        self.play(b1_l.animate.set_angle(57.5*DEGREES))

方式二:给Line添加碰撞代理(实现简单)

创建一个极窄的Rectangle作为Line的碰撞检测代理,利用Intersection检测矩形与圆的交集:

from manim import *

class Test(Scene):
    def construct(self):
        b1_l = Line([-1.,-1.,0.],[3,3,0]).set_color(YELLOW).set_angle(57.5 * DEGREES)
        # 生成Line的碰撞代理:极窄矩形,与Line重合
        line_collider = Rectangle(
            width=b1_l.get_length(),
            height=0.02,
            fill_opacity=1
        ).align_to(b1_l, LEFT).set_angle(b1_l.get_angle())
        line_collider.set_opacity(0)  # 隐藏代理,不显示在画面中
        obj_1 = Circle(radius=.1, color=RED, fill_opacity=1).move_to([0,1.5,0])

        def updateObject(obj: Mobject):
            # 保持代理与Line角度同步
            line_collider.set_angle(b1_l.get_angle())
            if Intersection(obj, line_collider).has_points():
                obj.set_color(BLUE)
            else:
                obj.set_color(YELLOW)

        obj_1.add_updater(updateObject)

        self.add(b1_l, line_collider, obj_1)
        self.play(b1_l.animate.set_angle(57.5*DEGREES + 20*DEGREES))
        self.wait(0.05)
        self.play(b1_l.animate.set_angle(57.5*DEGREES))

关键修正点

  • 原代码未将b1_l添加到场景,导致看不到Line的旋转,必须加入self.add(b1_l)。
  • set_angle参数需传入弧度值,原代码中57.5会被当作弧度,应改为57.5 * DEGREES转换为角度对应的弧度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 05:13:12