【OpenHarmony/HarmonyOs 】凸透镜成像实验:光路绘制、成像公式与禁止 AI 识图的学习方案
本文基于我的 OpenHarmony/HarmonyOS 项目「物理视界 PhysicsVision」整理。项目中的「凸透镜成像」模型通过 Canvas 绘制主光轴、透镜、焦点、物体、像和两条典型光线,并根据物距和焦距实时计算成像类型。
这一篇对应“沉浸光感”和“禁止 AI 识图、隐私保护方案”的主题:不用拍照识题,也能把光学知识讲清楚。🔍
一、为什么凸透镜成像不一定需要拍照识题?
很多教育 App 会把光学题做成“拍照识别题目,然后给答案”。
但这种方式有几个问题:
- 需要相机权限;
- 图片可能包含学生个人信息;
- 学生容易直接看答案;
- 对理解成像规律帮助有限。
「物理视界」选择了另一种方式:
不拍照、不上传、不识图,而是让学生自己调节焦距、物距和物体高度,看成像结果如何变化。
这更适合物理学习,因为凸透镜成像的重点不是答案,而是规律。
二、核心参数
页面定义了三个输入参数:
@StatefocalLength: number =60@StateobjectDist: number =150@StateobjectHeight: number =50还有三个计算结果:
@StateimageDist: number =0@StateimageHeight: number =0@StateimageType: string =''这对应物理中的:
- 焦距
f; - 物距
u; - 像距
v; - 放大率;
- 成像性质。
三、成像公式计算
项目使用薄透镜公式:
calculate(): void { let u =this.objectDist let f =this.focalLengthif(Math.abs(u - f) <1) {this.imageDist =9999this.imageHeight =9999this.imageType ='平行光(不成像)'return} let v = (u * f) / (u - f)this.imageDist = vthis.imageHeight = -v / u *this.objectHeight }公式本质是:
1/f =1/u +1/v整理后得到:
v=uf / (u - f)这里完全在端侧计算,不需要调用 AI 服务。
四、成像类型判断
根据物距和焦距关系,判断成像类型:
if(u >2* f)this.imageType ='倒立缩小实像'elseif(Math.abs(u -2* f) <1)this.imageType ='倒立等大实像'elseif(u > f)this.imageType ='倒立放大实像'elsethis.imageType ='正立放大虚像'这正是初中光学常见知识点:
u > 2f:倒立缩小实像;u = 2f:倒立等大实像;f < u < 2f:倒立放大实像;u < f:正立放大虚像。
通过代码,物理规律被明确地表达出来。
五、绘制主光轴和透镜
Canvas 中先绘制主光轴:
ctx.strokeStyle = '#B2BEC3' ctx.lineWidth =1ctx.beginPath()ctx.moveTo(10,centerY)ctx.lineTo(w- 10,centerY)ctx.stroke()再绘制透镜:
ctx.strokeStyle = '#1A73E8' ctx.lineWidth =3ctx.beginPath()ctx.moveTo(centerX,centerY- 80)ctx.lineTo(centerX,centerY+ 80)ctx.stroke()蓝色透镜线条在浅色和深色背景下都比较清晰。
六、绘制焦点和 2F 点
letfPx = this.focalLength*scale ctx.fillStyle = '#FF6D00' ctx.beginPath()ctx.arc(centerX - fPx, centerY,4,0, Math.PI*2) ctx.fill()ctx.beginPath()ctx.arc(centerX + fPx, centerY,4,0, Math.PI*2) ctx.fill()ctx.fillText('F',centerX-fPx,centerY+ 16)ctx.fillText("F'",centerX+fPx,centerY+ 16)焦点和 2F 点是判断成像规律的关键参照。
把它们画在图上,学生能更容易理解“物体在 2F 外、F 和 2F 之间、F 内”的区别。
七、绘制物体和像
物体用红色箭头表示:
letobjX = centerX - this.objectDist*scaleletobjTop = centerY - this.objectHeight*0.8ctx.strokeStyle = '#F44336' ctx.lineWidth =3ctx.beginPath()ctx.moveTo(objX,centerY)ctx.lineTo(objX,objTop)ctx.stroke()像用绿色箭头表示:
letimgX = centerX + this.imageDist*scaleletimgH = this.imageHeight*0.8letimgTop = centerY - imgHletisVirtual = this.imageDist <0if(isVirtual) { ctx.setLineDash([5, 5])} ctx.strokeStyle = '#4CAF50' ctx.beginPath()ctx.moveTo(imgX,centerY)ctx.lineTo(imgX,imgTop)ctx.stroke()ctx.setLineDash([])虚像使用虚线,这是一个很适合教学的视觉约定。
八、绘制两条典型光线
项目绘制了平行光线和过光心光线:
ctx.strokeStyle = '#FFB74D' ctx.lineWidth =1ctx.beginPath()ctx.moveTo(objX,objTop)ctx.lineTo(centerX,objTop)ctx.lineTo(imgX,imgTop)ctx.stroke()ctx.beginPath()ctx.moveTo(objX,objTop)ctx.lineTo(imgX,imgTop)ctx.stroke()这比只显示像的位置更好,因为学生能看到成像是如何由光路决定的。
九、滑块调参:主动探索规律
焦距、物距和物体高度都用 Slider 控制:
Slider({value:this.objectDist,min: 20,max: 250,step: 1 }).trackColor($r('app.color.slider_track')) .selectedColor('#1A73E8').onChange((v:number)=> { this.objectDist = v this.calculate()})每次滑动都会重新计算并绘图。
这让学生可以自己观察:
- 物距变小时像距怎么变;
- 什么时候不成像;
- 实像和虚像如何切换;
- 像的大小如何变化。
十、总结
凸透镜成像页面很好地体现了“禁止 AI 识图”的另一种学习方案。
不拍照、不上传、不识别题目,而是让学生通过参数调节和光路观察理解规律。
这篇文章对应的主题是:沉浸光感 + 禁止 AI 识图 + 隐私友好学习。
对 OpenHarmony/HarmonyOS 开发者来说,它也展示了 Canvas 在光学教学中的实用价值。🔍