掌控板编程实现三角形面积公式可视化推导:从割补法到图形动画
1. 项目缘起当掌控板遇上数学可视化最近在整理创客教育的课程资源发现一个挺有意思的现象很多老师想用掌控板这类开源硬件来做数学教学但往往停留在“用掌控板做个计算器”或者“显示个公式结果”的层面。这其实有点大材小用了。掌控板的核心优势在于它的交互性和丰富的传感器完全可以用它来“玩”数学把抽象的数学概念变成看得见、摸得着、甚至可以互动的过程。这次我们就来“玩”一个经典的几何问题三角形面积计算。小学就学过的公式面积 底 × 高 ÷ 2对很多学生来说它可能只是一个需要记忆和套用的符号。但如果我们能用掌控板上的点阵屏把这个公式的推导过程——比如“等积变形”的思想——动态地画出来效果就完全不一样了。这不仅仅是做一个面积计算器而是做一个“面积公式推导过程的可视化演示器”。通过编程让掌控板自己“画”出切割、平移、拼接的过程最终形成一个长方形从而直观地理解为什么面积公式是那样。这个项目我称之为“图解三角形面积”它瞄准的不是计算结果而是数学思维和空间想象力的培养。2. 核心设计思路从“算”到“画”的转变这个项目的目标很明确不满足于输入底和高然后显示一个数字而是要在掌控板的16x8 LED点阵屏上动态展示三角形转化为等面积长方形的过程。这听起来简单但实现起来需要拆解几个关键的设计决策。2.1 为何选择“割补法”进行可视化三角形面积公式的推导方法有很多比如拼成平行四边形、直接用坐标计算海伦公式等。我选择最经典的“割补法”来可视化主要基于两点考虑符合认知规律“割补”是小学阶段接触面积计算时最早引入的思想之一如平行四边形变长方形用它来推导三角形面积逻辑链条短学生容易跟上。适合点阵屏表现16x8的屏幕分辨率很低画精细的斜线或曲线效果不好。而“割补法”涉及的主要是垂直或水平的切割、平移这些动作在点阵屏上用点亮和熄灭LED的方式表现非常清晰、直观每一步的图形变化都能被清楚地看到。具体到“割补”的策略我选择了“倍拼法”的变体不是用两个完全一样的三角形拼成平行四边形而是展示如何将一个三角形通过切割重新组合成一个长方形。这样在单一块屏幕上就能完成整个推导叙事更完整。2.2 图形坐标系的建立与映射这是项目的第一个技术难点。掌控板的点阵屏是16列x轴0-15、8行y轴0-7。我们需要在这个微观画布上定义三角形。为了编程方便且图形美观我决定固定三角形的底边在屏幕底部y7顶点在上方。这样三角形的高就是竖直方向的方便计算和绘制。定义三个参数base_length: 底边长度占用的LED数比如10。height: 三角形高度从底边到顶点的垂直行数比如5。left_start: 底边左端点的x坐标比如3。那么三角形的三个顶点坐标就是左下角(left_start, 7)右下角(left_start base_length - 1, 7)注意长度10意味着从x3到x12共10个点顶点(left_start base_length // 2, 7 - height)顶点在底边中点的正上方注意这里有一个细节base_length是LED的数量而坐标是索引值所以右下角x坐标需要减1。height是行数从y7向上减所以顶点的y坐标是7 - height。2.3 动画分解四步讲清一个公式整个可视化过程我设计为四个清晰的步骤每一步都在点阵屏上通过动画呈现并在串口或OLED副屏如果拓展了上输出说明文字。第一步绘制原始三角形。在屏幕上点亮构成三角形三条边的LED。这里需要用到一个核心算法Bresenham画线算法。因为我们需要在点阵屏上画出斜边从顶点到底角。掌控板的mpython库通常没有直接画线的函数到点阵屏我们需要自己实现或使用简单的循环模拟。这一步让用户看到我们初始的图形。第二步标记中点并垂直切割。找到底边的中点(mid_x, 7)然后从顶点(mid_x, 7-height)向底边中点画一条垂直线实际上就是点亮这一列上从顶点到底边的所有LED。这一步在视觉上把三角形分成了左右两个小三角形。动画效果可以是从顶点到底边LED逐行点亮。第三步旋转与平移视觉错觉处理。这是最精彩的一步。我们需要将右侧的小三角形“移动”到左侧与左边部分拼成一个长方形。在低分辨率点阵屏上直接“移动”一个图形块比较困难。我采用的策略是先擦除原始三角形和切割线。重新绘制一个长方形。这个长方形的长等于原三角形的底边长度(base_length)宽等于原三角形高度的一半(height // 2)。绘制时采用一种“生长式”动画比如从左到右逐列点亮或者从下到上逐行点亮模拟出拼接的过程。关键技巧这里其实是一个“视觉演示”。我们并不需要真正编程去旋转一个像素矩阵那会非常复杂而是通过“擦除-重绘为长方形”的动画配合文字说明让观看者在脑海中完成“切割下来的部分刚好能补过去”的想象。这是教育演示中常用的手法重点在于传达思想而非精确的图形学仿真。第四步揭示公式。当长方形绘制完成后在旁边或通过串口显示文字“长方形面积 长 × 宽 base_length× (height/2)”。然后闪烁显示最终公式“三角形面积 底 × 高 ÷ 2”。将具体的数字代入完成从具体到抽象的升华。3. 代码实现与核心算法剖析我们将使用 mPython 进行编程。下面分模块拆解代码实现。3.1 硬件初始化与画线函数首先初始化掌控板并实现一个在点阵屏上画线的函数。这是整个项目图形显示的基础。from mpython import * import time # 初始化 display.fill(0) # 清屏 display.show() def draw_line(x0, y0, x1, y1): 使用 Bresenham 算法在点阵屏上画线。 注意掌控板点阵屏的坐标系原点(0,0)在左上角。 dx abs(x1 - x0) dy abs(y1 - y0) sx 1 if x0 x1 else -1 sy 1 if y0 y1 else -1 err dx - dy while True: # 点亮一个点。注意点阵屏的 pixel 方法1为点亮 display.pixel(x0, y0, 1) if x0 x1 and y0 y1: break e2 2 * err if e2 -dy: err - dy x0 sx if e2 dx: err dx y0 sy display.show()这个draw_line函数是图形显示的基石。它确保了我们在任何两点之间都能画出一条连续、准确的直线对于绘制三角形的斜边至关重要。3.2 主程序流程与动画控制接下来是主程序它按照我们设计的四步流程控制整个动画的演绎。def visualize_triangle_area(base_len, tri_height, left_x): 主可视化函数 base_len: 底边长度 (LED数量) tri_height: 三角形高度 (行数) left_x: 底边左下角x坐标 # ---- 第一步绘制原始三角形 ---- display.fill(0) top_x left_x base_len // 2 top_y 7 - tri_height right_x left_x base_len - 1 # 画三条边 draw_line(left_x, 7, top_x, top_y) # 左边斜线 draw_line(top_x, top_y, right_x, 7) # 右边斜线 draw_line(left_x, 7, right_x, 7) # 底边 time.sleep(2) # 暂停2秒观察 # ---- 第二步垂直切割 ---- # 画从中点向上的垂直线 mid_x left_x base_len // 2 for y in range(top_y, 8): # 从顶点y坐标画到y7包含 display.pixel(mid_x, y, 1) display.show() time.sleep(0.05) # 逐行点亮形成动画效果 time.sleep(1) # ---- 第三步擦除并绘制长方形模拟拼接 ---- display.fill(0) display.show() time.sleep(0.5) # 计算长方形的参数 rect_height tri_height // 2 # 长方形高是三角形高的一半 rect_top_y 7 - rect_height # 以“从下往上生长”的动画绘制长方形 for current_y in range(7, rect_top_y - 1, -1): # 从y7向上画到rect_top_y for x in range(left_x, right_x 1): display.pixel(x, current_y, 1) display.show() time.sleep(0.1) time.sleep(1) # ---- 第四步显示公式 ---- display.fill(0) # 在点阵屏上显示文字比较拥挤这里我们简单显示关键数字和符号 # 更佳实践是使用OLED扩展屏这里用点阵屏模拟 display.text(S {} * {}.format(base_len, tri_height), 0, 0, 1) display.text(/ 2, 40, 8, 1) # 注意调整坐标使其可读 display.show() time.sleep(3) # 也可以通过串口打印详细过程方便教学讲解 print(--- 三角形面积公式推导 ---) print(第一步绘制底为{}高为{}的三角形。.format(base_len, tri_height)) print(第二步从顶点垂直切割到底边中点得到两个全等的小三角形。) print(第三步将右边的小三角形平移至左侧可拼成一个长方形。) print(第四步新长方形的长 原三角形底 {}.format(base_len)) print( 新长方形的高 原三角形高的一半 {} / 2 {}.format(tri_height, rect_height)) print( 长方形面积 {} * {} {}.format(base_len, rect_height, base_len * rect_height)) print(因此三角形面积 长方形面积 底 * 高 / 2) print(公式S {} * {} / 2 {}.format(base_len, tri_height, base_len * tri_height // 2)) # 调用函数示例底长10高6从x3开始 visualize_triangle_area(10, 6, 3)这段代码是一个完整的演示。它包含了动画切割线的逐行绘制、长方形的逐行生长、逻辑计算坐标、面积和教学输出串口打印。你可以通过修改visualize_triangle_area(10, 6, 3)中的参数生成不同形状的三角形进行演示。3.3 关键算法低分辨率图形动画的取舍在实现过程中有一个关键点需要深入讨论为什么我们选择“擦除-重绘”而不是真正的“图形旋转平移”在PC上我们可以轻松操作一个像素矩阵进行旋转、剪切、平移等变换。但在掌控板这样的微控制器上内存和计算能力都有限。16x8的点阵屏其显示缓冲区就是一个128位的映射。实现一个通用的、任意图形的旋转算法代码会相对复杂且运行时可能会占用较多资源导致动画卡顿。我们的目标是教学演示核心是传达“等积变形”的数学思想。因此采用“擦除-重绘”的策略是最高效、最可靠的选择。它用最简单的代码达到了最清晰的演示目的。在课堂上老师可以配合代码讲解“看程序现在清屏了然后它画出了一个长方形。这模拟的就是我们把切下来的那块三角形平移过去之后拼成的样子。” 学生能够理解这个“模拟”的过程重点放在了数学逻辑上而不是图形学算法上。实操心得在创客教育项目中经常需要在“效果完美”和“实现简单可靠”之间做权衡。尤其是面对初学者时一个能稳定运行、逻辑清晰的项目远比一个充满炫酷技术但bug频出的项目更有教学价值。这个“图解三角形面积”项目就贯彻了这一思想用最直接的方式呈现核心概念。4. 项目优化与教学拓展基础版本完成后我们可以从互动性和教学深度两个方向进行拓展让这个项目变得更加强大和有趣。4.1 增加交互性让参数“活”起来基础版本中三角形的底和高是固定在代码里的。我们可以利用掌控板的按键或光线传感器让学生能动态改变这些参数实时观察不同形状三角形的推导过程。方案一使用A/B按键控制# 在循环中检测按键调整参数 base_len 10 tri_height 6 while True: if button_a.value() 0: # 按下A键 base_len (base_len % 12) 4 # 让底长在4到15之间循环 visualize_triangle_area(base_len, tri_height, 2) if button_b.value() 0: # 按下B键 tri_height (tri_height % 6) 2 # 让高在2到7之间循环 visualize_triangle_area(base_len, tri_height, 2) time.sleep_ms(200) # 防抖这样每按一次键就会生成一个新的三角形并自动演示面积推导过程非常适合课堂互动提问。方案二使用电位器模拟输入需扩展板如果使用了有模拟输入接口的扩展板可以连接两个电位器。一个电位器的电压值映射为底长另一个映射为高。程序不断读取电位器值并实时刷新三角形图形可以只刷新第一步的三角形绘制或者放慢完整推导的速度实现“旋钮调节三角形形状”的直观效果。这能让学生深刻理解底和高的变化如何影响三角形的面积。4.2 拓展推导方法从一种到多种“割补法”只是其中一种推导方式。我们可以编程实现其他方法的可视化对比教学。拼凑法在屏幕上绘制两个完全相同的三角形然后通过动画将它们拼凑成一个平行四边形。再展示这个平行四边形可以切割、平移变成长方形。这能直观展示“三角形面积是等底等高平行四边形面积的一半”。“以盈补虚”法刘徽原理对于直角三角形可以用四个一样的三角形拼成一个以斜边为边的大正方形中间空出一个小正方形。通过面积关系推导出勾股定理进而联系到面积计算。这适合学有余力的学生进行跨知识点融合。实现这些拓展核心是设计好图形变换的动画步骤并在代码中封装成不同的函数如visualize_by_parallelogram()、visualize_by_liuhui()。4.3 连接物理世界从图形到测量这是创客项目的精髓——与物理世界互动。我们可以尝试用超声波传感器测“底”和“高”假设一个直角三角形把掌控板放在直角顶点。用超声波传感器测量两条直角边的距离假设物体垂直摆放将测得的厘米数按比例转换为点阵屏上的LED长度然后自动进行面积计算和可视化。这实现了从真实世界测量到数学计算再到图形演示的完整闭环。用光线传感器控制动画速度环境光越强动画播放速度越快环境光越暗速度越慢。这增加了项目的趣味性和对传感器应用的理解。5. 教学实施建议与常见问题把这个项目带入课堂或工作坊有一些实践经验可以分享。5.1 课程环节设计建议分为三个环节总时长约90-120分钟概念引入与演示20分钟老师先不展示代码而是用已完成的项目进行演示。通过提问引导学生观察“屏幕上发生了什么变化”“切割线在哪里”“拼成的长方形和原来的三角形有什么关系”让学生先关注数学过程本身。代码探索与重构50分钟分发基础代码框架可能省略画线函数或动画延时。引导学生阅读代码将代码行与演示的每一步对应起来。重点讲解坐标计算、draw_line函数和动画循环。然后让学生尝试修改参数底、高、起始位置观察变化。创意拓展与分享30分钟提出挑战任务如“如何用按键控制三角形大小”或“你能让切割线的颜色亮度不一样吗”掌控板LED可调亮度。让学生分组尝试并分享他们的修改成果。5.2 学生常见问题与调试技巧问题三角形画歪了或不是等腰的。检查顶点坐标计算是否正确。确保top_x left_x base_len // 2。//是整除运算符确保顶点在底边中点的正上方。检查draw_line函数是否工作正常。可以用它单独画一个正方形测试。问题动画太快或太慢看不清楚。调整代码中所有的time.sleep()参数。切割动画的time.sleep(0.05)和长方形生长动画的time.sleep(0.1)是主要控制点。可以根据需要增大变慢或减小变快这些值。问题长方形绘制时看起来不是从底部“长”起来的。检查绘制长方形的双重循环逻辑。外层循环for current_y in range(7, rect_top_y - 1, -1):中的-1是步长确保是从下往上y值从大到小绘制。内层循环for x in range(left_x, right_x 1):中的right_x 1是因为range函数不包含终点需要1才能画到最右侧点。问题屏幕显示混乱有残留图像。检查在每次绘制新图形前是否执行了display.fill(0)来清屏。动画步骤之间要有足够的display.show()和time.sleep确保前一帧完全显示后再进行下一帧。这个项目最让我满意的地方在于它用一个非常具体的硬件和编程任务承载了一个抽象的数学原理。学生动手做的过程中不仅练习了编程思维顺序、循环、函数、数学计算坐标、几何更重要的是他们亲眼看到了一个公式是如何从图形中“生长”出来的。这种通过创造来理解的学习方式比单纯听讲和做题要深刻得多。下次或许可以试试“图解圆的面积”用点阵屏来模拟极限分割的思想那又将是一个有趣的挑战。