当前位置:首页>python>从“滚动”到“轨迹”:几何直觉如何被 Python 具象化——正方形沿正三角形外侧滚动的一次记录

从“滚动”到“轨迹”:几何直觉如何被 Python 具象化——正方形沿正三角形外侧滚动的一次记录

  • 2026-10-21 13:28:43
从“滚动”到“轨迹”:几何直觉如何被 Python 具象化——正方形沿正三角形外侧滚动的一次记录
  在中学的期间,我一直在想一个问题。

如果一个几何图形,在另一个几何图形的边界上“滚动”,它的某个固定点,会留下些什么?

不是公式,不是结论,而是那种真正走过之后留下的轨迹。

但很快我发现,这个问题在脑子里是想不清楚的。尤其当滚动的不再是圆,而是一个有棱有角的多边形时,想象力几乎立刻失效。

  现在有了python这个强大的工具应该能实现这个梦想中的轨迹吧?

但一开始的时后,我总是失败。这种失败并不是需要什么复杂的计算公式,

而是你不知道下一步该让图形“怎么动”。支点在哪里?转多少?什么时候换边?

所有这些问题,在脑中都是模糊的。

后来我意识到,与其在一个完全想不清楚的情形里反复尝试,不如先把问题压缩到最简单的情况。

于是我做了一个几乎没有任何“理论依据”的选择:

先让正方形的边长,等于正三角形的边长。


这个 1:1 的比例,并不是为了研究比例,只是为了让滚动这件事,在代码和视觉上先“站得住”。在这个设定下,

我终于可以把“滚动”拆解成一件可执行的事情:

这是正方形ABED按顺序在三角形的BC,CA,AB边上滚动的示意说明图

我们把上面图示的三个滚动阶段称为1轮。

推理表显示:相位的“漂移”规律

我们可以发现一个非常漂亮的数学循环。每一轮(三个阶段)结束后,与三角形起始支点 B 重合的正方形顶点会按以下顺序演变:

轮次阶段结束点与三角形 B 点重合的正方形顶点说明
第0轮初始 B初始对齐
第1轮第3阶段后 A逆时针位移 1 个顶点
第2轮第6阶段后 D逆时针位移 2 个顶点
第3轮第9阶段后 E逆时针位移 3 个顶点
第4轮第12阶段后 B完全复原

结论:由于正方形有 4 个顶点,三角形有 3 个顶点,这个运动系统需要完整地绕三角形转 4 圈(共 12 个旋转阶段),正方形的顶点标注才会和最开始第一图之前的初始状态完全重合。

在代码里,这不再是连续的“滑动”,而是一段一段明确的刚体旋转。

在 1:1 的比例下,整个滚动过程可以被压缩成一个极其简单的循环:
# 三个三角形顶点,依次作为旋转支点pivots = [B_tri, C_tri, A_tri]# 每一轮包含 3 次旋转,共 4 轮 = 12 次for step inrange(12):    pivot = pivots[step % 3]# 每一次滚动,都是一次刚体旋转    self.play(        Rotate(            square,            angle=210 * DEGREES,            about_point=pivot,            rate_func=linear        )    )

当我第一次看到正方形真的沿着三角形翻滚起来时,我意识到一件事:

几何直觉,有时候不是靠想出来的,而是靠“跑出来的”。


在整个实现过程中,我并没有单独去“画轨迹”。

我只是做了一件很简单的事:在正方形滚动的过程中,顺手记录下某个顶点的位置。

path = TracedPath(lambda i=i: square.get_vertices()[i],    stroke_width=3,    stroke_opacity=0.6)

当动画播放结束,那些被记录下来的点,自然连成了一条曲线。

这条轨迹并不是我设计的形状,而是运动本身留下的痕迹。

当正方形和正三角形边长相等时,滚动这件事,第一次在屏幕上成功了。

我终于可以不再靠想象,而是靠几条明确的规则,让图形动起来:

  • 支点在哪里

  • 围绕哪个点旋转

  • 旋转多少角度

  • 什么时候“翻到下一条边”

在这个设定下,正方形 ABED 依次沿着三角形的BC → CA → AB,外侧滚动。

这并不意味着问题“解决了”。恰恰相反——正是在这个看似简单的 1:1 情形里,我第一次意识到:

滚动不是连续的而是被“相位”切成了一段一段

每一次贴边,每一次换支点,每一次转角,本质上都是一次状态跃迁。而代码之所以能跑通,

不是因为我理解了全部几何,而是因为在这个比例下:

  • 支点切换刚好“对齐”

  • 旋转角度不会出现歧义

  • 下一步几乎是“显而易见的”

这让我产生了一种错觉:是不是问题本来就这么简单?

在代码终于稳定跑完 1:1 之后,我几乎是本能地,做了下一步。

既然简单的已经能跑,那我想看看——复杂的,会发生什么。

我把比例改成了:

正方形边长为 L,正三角形边长为 3L。

也正是在这一刻,之前被 1:1 “遮住”的东西,一下子全暴露出来了。

滚动不再是“一边贴完,顺势翻下去”。而是又乱套了

但是有了比例为1:1的经历

我们很快精准对齐物理接触点和相位变化。当正方形边长为 L,三角形边长为 3L 时:

    阶段 1:跨越顶点

    • 起点:正方形顶点 B 与三角形顶点 B 重合

    • 动作:绕顶点 B 旋转 210°

    • 结果:正方形的 BE 边平贴在三角形 BC 边上

    • 位置:正方形占据 BC 边的前 1/3,E 点距离 B 为 L

    阶段 2:第一次沿边翻滚

    • 支点:BC 边上距离 B 点的 L 处 E 点

    • 动作:绕 E 点旋转 90°

    • 结果:ED 边贴在 BC 边中段

    • 位置:D 点距离 三角形 B 点 为 2L

    阶段 3:第二次沿边翻滚

    • 支点:BC 边上距离 B 2L 的 D 点

    • 动作:绕 D 点旋转 90°

    • 结果:下一条边平贴 BC 边

    • 位置:A 点与三角形顶点 C 对齐

    阶段 4:进入下一条边

    • 顶点 A 与 C 重合

    • 动作:绕 C 顶点旋转 210°

    • 结果:正方形下一条AB边贴在 CA 边上

    • 循环重复

    通过这四个阶段,我第一次清楚地看到:轨迹的复杂性,是由多次分段相位累积产生的。

    已关注
    关注
    重播 分享 赞

    每一次旋转、每一个支点,都像是在控制一个“离散几何系统”,

    phase = [    ("vertex", 210),    ("edge", 90),    ("edge", 90),]
    没有一步可以随意,否则,轨迹不会“稍微错一点”,而是直接崩掉。

    而这一切的精确知道得益于正方形与三角形边长有着确定的比例

    我最初那些失败的尝试,问题在于——比例关系根本没有被约束清楚。

    比例,是滚动能否发生的隐形规则。

    正方形与三角形边长之间,一旦存在确定的比例,

    接触点的位置、阶段的切换、以及“下一步该怎么转”,才第一次变成了可以被精确描述的事情。

    也正是从这一刻开始,轨迹不再是“试出来的”,而是被运动本身一步步逼出来的

    也正是从这一刻开始,我才真正意识到:

    我一开始问的那个问题,

    其实从来就不是“轨迹长什么样”。

    而是——在怎样的约束下,一个几何系统,才被允许留下轨迹。

    当比例不清楚时,图形当然也可以动,代码当然也可以跑,但那只是一种“看起来在滚”的假象。支点是随意的,角度是拍脑袋的,下一步只能靠猜。

    这种运动,不可能留下真正的痕迹。

    只有当比例被固定下来,当每一次接触、每一次旋转、

    每一次“不得不这样转”的选择,都被约束住时,轨迹才第一次成为一个必然的结果。

      直到这时,我才回头重新理解,读中学时那个最原始的念头:

    如果一个几何图形,在另一个几何图形的边界上滚动,它的某个固定点,会留下些什么?

    现在我终于可以回答它了。

    它不会留下一个“我想象中的形状”,也不会留下一个“可以事先写下的公式”。

    它留下的,只是它在所有约束之下,所能走过的全部路径。


    这也是为什么,当我看着最后生成的视频我并不关心它们像不像花,像不像心形,

    或者能不能被一句话概括。

    我看到的,是另一件事:

    一个被严格约束的几何系统,在没有任何“审美目标”的前提下,仍然不可避免地,生成了某种秩序。


    这次尝试让我越来越确信一件事:

    理解,并不总是从复杂开始的,很多时候,它是从一个“能跑起来的简化”开始的。

    而 Python 在这里,让我把几何的运动,看得更慢一点,也更清楚一点。

    当结构退场,,

    运动留下的东西,

    才第一次显现为对象

      当我的视线再一次停留在视频结束时的最后一帧画面的对象上。我发现它很美,真的很美!今天,我终于实现了年轻时隐藏在梦中角落里的那种数学之美“

    最新文章

    随机文章