凸透镜成像小应用

03 11月
作者:cinjep|分类:辅助教学

功能说明:

  • 用户可调节 物距(u) 和 焦距(f)

  • 实时显示:

    • 成像公式计算结果(像距 v)

    • 像的性质:实像/虚像放大/缩小/等大正立/倒立

    • 动态光路图(简化版,用 Canvas 绘制)

  • 支持常见成像情况(u > 2f, u = 2f, f < u < 2f, u = f, u < f)

凸透镜成像模拟器_QWen3.PNG

以下是实现代码( 由 阿里QWen3 依据人工指令生成):


<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>凸透镜成像模拟器</title>
  <style>
    body {
      font-family: "Microsoft YaHei", sans-serif;
      text-align: center;
      background-color: #f0f8ff;
      padding: 20px;
    }
    h1 {
      color: #0066cc;
    }
    .container {
      max-width: 800px;
      margin: 0 auto;
      background: white;
      padding: 20px;
      border-radius: 10px;
      box-shadow: 0 0 10px rgba(0,0,0,0.1);
    }
    canvas {
      border: 1px solid #ccc;
      margin: 15px 0;
      background-color: #fff;
    }
    .controls {
      margin: 15px 0;
    }
    label {
      display: inline-block;
      width: 120px;
      text-align: right;
      margin-right: 10px;
    }
    input[type="range"] {
      width: 300px;
    }
    .result {
      margin-top: 15px;
      padding: 10px;
      background-color: #e6f2ff;
      border-radius: 5px;
      font-weight: bold;
    }
  </style>
</head>
<body>
  <div>
    <h1>🔍 凸透镜成像模拟器</h1>
    <p>调节物距和焦距,观察成像规律</p>

    <div>
      <label for="uSlider">物距 u (cm):</label>
      <input type="range" id="uSlider" min="1" max="100" value="30" />
      <span id="uValue">30</span>
    </div>

    <div>
      <label for="fSlider">焦距 f (cm):</label>
      <input type="range" id="fSlider" min="1" max="30" value="10" />
      <span id="fValue">10</span>
    </div>

    <canvas id="lensCanvas" width="600" height="300"></canvas>

    <div id="resultBox">
      正在计算成像结果...
    </div>

    <p style="font-size: 0.9em; color: #666;">
      💡 提示:<br>
      实像:可在光屏上呈现,倒立;虚像:不能呈现在光屏上,正立。<br>
      成像公式:1/f = 1/u + 1/v
    </p>
  </div>

  <script>
    const canvas = document.getElementById('lensCanvas');
    const ctx = canvas.getContext('2d');
    const uSlider = document.getElementById('uSlider');
    const fSlider = document.getElementById('fSlider');
    const uValue = document.getElementById('uValue');
    const fValue = document.getElementById('fValue');
    const resultBox = document.getElementById('resultBox');

    // 初始值
    let u = parseFloat(uSlider.value);
    let f = parseFloat(fSlider.value);

    // 更新显示
    function update() {
      u = parseFloat(uSlider.value);
      f = parseFloat(fSlider.value);
      uValue.textContent = u;
      fValue.textContent = f;

      drawLens();
      calculateImage();
    }

    // 绘制简化的光路图
    function drawLens() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      const centerX = canvas.width / 2;
      const centerY = canvas.height / 2;
      const scale = 5; // 1cm = 5px

      // 画主光轴
      ctx.beginPath();
      ctx.moveTo(0, centerY);
      ctx.lineTo(canvas.width, centerY);
      ctx.strokeStyle = '#999';
      ctx.stroke();

      // 画透镜(竖线)
      ctx.beginPath();
      ctx.moveTo(centerX, centerY - 80);
      ctx.lineTo(centerX, centerY + 80);
      ctx.strokeStyle = '#0066cc';
      ctx.lineWidth = 3;
      ctx.stroke();
      ctx.lineWidth = 1;

      // 画焦点 F(左右各一个)
      const fPx = f * scale;
      ctx.beginPath();
      ctx.arc(centerX - fPx, centerY, 3, 0, Math.PI * 2);
      ctx.arc(centerX + fPx, centerY, 3, 0, Math.PI * 2);
      ctx.fillStyle = 'red';
      ctx.fill();
      ctx.fillText('F', centerX - fPx - 10, centerY - 5);
      ctx.fillText('F', centerX + fPx + 5, centerY - 5);

      // 画物体(箭头,在左侧)
      const uPx = u * scale;
      const objX = centerX - uPx;
      if (objX > 0) {
        drawArrow(ctx, objX, centerY, objX, centerY - 40, 'blue');
        ctx.fillText('物体', objX - 15, centerY + 15);
      }

      // 计算像距 v
      let v;
      if (u === f) {
        // 平行光,不成像
        resultBox.innerHTML = '物体位于焦点,光线平行,<b>不成像</b>。';
        return;
      } else {
        v = 1 / (1/f - 1/u); // 透镜公式:1/f = 1/u + 1/v → v = 1/(1/f - 1/u)
      }

      // 画像(根据 v 的正负判断位置)
      if (v > 0) {
        // 实像,在右侧
        const imgX = centerX + v * scale;
        const imgHeight = (v / u) * 40; // 放大率 = |v/u|
        drawArrow(ctx, imgX, centerY, imgX, centerY + imgHeight, 'green');
        ctx.fillText('实像', imgX - 15, centerY - 10);
      } else if (v < 0) {
        // 虚像,在左侧(同侧)
        const imgX = centerX + v * scale; // v 为负,所以 imgX < centerX
        const imgHeight = Math.abs(v / u) * 40;
        drawArrow(ctx, imgX, centerY, imgX, centerY - imgHeight, 'purple', true);
        ctx.fillText('虚像', imgX - 15, centerY + 15);
      }
    }

    // 画箭头函数
    function drawArrow(context, fromX, fromY, toX, toY, color, dashed = false) {
      context.beginPath();
      if (dashed) {
        context.setLineDash([5, 5]);
      } else {
        context.setLineDash([]);
      }
      context.moveTo(fromX, fromY);
      context.lineTo(toX, toY);
      context.strokeStyle = color;
      context.stroke();

      // 箭头头
      const angle = Math.atan2(toY - fromY, toX - fromX);
      const headLen = 10;
      context.beginPath();
      context.moveTo(toX, toY);
      context.lineTo(
        toX - headLen * Math.cos(angle - Math.PI / 6),
        toY - headLen * Math.sin(angle - Math.PI / 6)
      );
      context.moveTo(toX, toY);
      context.lineTo(
        toX - headLen * Math.cos(angle + Math.PI / 6),
        toY - headLen * Math.sin(angle + Math.PI / 6)
      );
      context.strokeStyle = color;
      context.stroke();
      context.setLineDash([]);
    }

    // 计算并显示成像性质
    function calculateImage() {
      if (u === f) {
        resultBox.innerHTML = '物体位于焦点,光线平行,<b>不成像</b>。';
        return;
      }

      const v = 1 / (1/f - 1/u);
      const magnification = Math.abs(v / u);

      let type, size, orientation;

      if (v > 0) {
        type = '实像';
        orientation = '倒立';
      } else {
        type = '虚像';
        orientation = '正立';
      }

      if (magnification > 1) {
        size = '放大';
      } else if (magnification < 1) {
        size = '缩小';
      } else {
        size = '等大';
      }

      let summary = `像距 v ≈ ${v.toFixed(2)} cm,成<b>${type}</b>、<b>${orientation}</b>、<b>${size}</b>的像。`;

      // 补充典型情况说明
      if (u > 2 * f) {
        summary += '(u > 2f:照相机原理)';
      } else if (u === 2 * f) {
        summary += '(u = 2f:等大实像)';
      } else if (u > f && u < 2 * f) {
        summary += '(f < u < 2f:投影仪原理)';
      } else if (u < f) {
        summary += '(u < f:放大镜原理)';
      }

      resultBox.innerHTML = summary;
    }

    // 绑定事件
    uSlider.addEventListener('input', update);
    fSlider.addEventListener('input', update);

    // 初始化
    update();
  </script>
</body>
</html>

凸透镜成像模拟器.html


浏览248
返回
目录
返回
首页
交互式的凸透镜成像应用 桌面摄像头人像采集程序