深秋红枫 发表于 2025-6-3 05:47

《朱利亚集合》随机演示图

本帖最后由 深秋红枫 于 2025-6-3 05:56 编辑 <br /><br /><!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>朱利亚集合 (Julia Set) 演示</title>
    <style>
      body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin: 20px;
            background-color: #f0f0f0;
      }
      canvas {
            border: 1px solid #333;
            margin: 20px auto;
            display: block;
            background-color: white;
      }
      .controls {
            margin: 20px;
            padding: 15px;
            background-color: #e0e0e0;
            border-radius: 8px;
            display: inline-block;
      }
      button {
            padding: 8px 15px;
            margin: 5px;
            cursor: pointer;
      }
      input {
            margin: 5px;
      }
    </style>
</head>
<body>
    <h1>朱利亚集合 (Julia Set) 演示</h1>
   
    <div class="controls">
      <label for="real">实部 (c<sub>real</sub>):</label>
      <input type="range" id="real" min="-1.5" max="1.5" step="0.01" value="-0.7">
      <span id="realValue">-0.70</span><br>
      
      <label for="imag">虚部 (c<sub>imag</sub>):</label>
      <input type="range" id="imag" min="-1.5" max="1.5" step="0.01" value="0.27">
      <span id="imagValue">0.27</span><br>
      
      <label for="iterations">迭代次数:</label>
      <input type="range" id="iterations" min="20" max="200" step="10" value="100">
      <span id="iterationsValue">100</span><br>
      
      <button id="draw">绘制</button>
      <button id="random">随机参数</button>
    </div>
   
    <canvas id="juliaCanvas" width="600" height="600"></canvas>
   
    <p>朱利亚集合是复平面上给定复数c后,通过迭代函数 f(z) = z² + c 不逃逸的点集。</p>
   
    <script>
      const canvas = document.getElementById('juliaCanvas');
      const ctx = canvas.getContext('2d');
      const width = canvas.width;
      const height = canvas.height;
      
      // 默认参数
      let cReal = -0.7;
      let cImag = 0.27;
      let maxIterations = 100;
      
      // 更新显示的值
      document.getElementById('real').addEventListener('input', function() {
            document.getElementById('realValue').textContent = this.value;
      });
      
      document.getElementById('imag').addEventListener('input', function() {
            document.getElementById('imagValue').textContent = this.value;
      });
      
      document.getElementById('iterations').addEventListener('input', function() {
            document.getElementById('iterationsValue').textContent = this.value;
      });
      
      // 绘制按钮
      document.getElementById('draw').addEventListener('click', function() {
            cReal = parseFloat(document.getElementById('real').value);
            cImag = parseFloat(document.getElementById('imag').value);
            maxIterations = parseInt(document.getElementById('iterations').value);
            drawJuliaSet();
      });
      
      // 随机参数按钮
      document.getElementById('random').addEventListener('click', function() {
            cReal = (Math.random() * 2 - 1).toFixed(2);
            cImag = (Math.random() * 2 - 1).toFixed(2);
            document.getElementById('real').value = cReal;
            document.getElementById('imag').value = cImag;
            document.getElementById('realValue').textContent = cReal;
            document.getElementById('imagValue').textContent = cImag;
            drawJuliaSet();
      });
      
      // 绘制朱利亚集合
      function drawJuliaSet() {
            const imageData = ctx.createImageData(width, height);
            const data = imageData.data;
            
            // 定义绘图区域的范围(复平面)
            const xMin = -2, xMax = 2;
            const yMin = -2, yMax = 2;
            
            for (let x = 0; x < width; x++) {
                for (let y = 0; y < height; y++) {
                  // 将像素坐标映射到复平面
                  const zx = xMin + (xMax - xMin) * x / width;
                  const zy = yMin + (yMax - yMin) * y / height;
                  
                  let i = 0;
                  let zx2 = zx, zy2 = zy;
                  
                  // 迭代计算
                  while (zx2 * zx2 + zy2 * zy2 < 4 && i < maxIterations) {
                        const tmp = zx2 * zx2 - zy2 * zy2 + cReal;
                        zy2 = 2 * zx2 * zy2 + cImag;
                        zx2 = tmp;
                        i++;
                  }
                  
                  // 根据迭代次数设置颜色
                  const idx = (x + y * width) * 4;
                  if (i === maxIterations) {
                        // 集合内的点 - 黑色
                        data = 0;
                        data = 0;
                        data = 0;
                  } else {
                        // 集合外的点 - 根据迭代次数设置颜色
                        const hue = (i / maxIterations * 360) % 360;
                        const saturation = 100;
                        const lightness = 50 + (i / maxIterations * 40);
                        
                        // 将HSL转换为RGB
                        const rgb = hslToRgb(hue / 360, saturation / 100, lightness / 100);
                        data = rgb;
                        data = rgb;
                        data = rgb;
                  }
                  data = 255; // Alpha通道
                }
            }
            
            ctx.putImageData(imageData, 0, 0);
      }
      
      // HSL转RGB函数
      function hslToRgb(h, s, l) {
            let r, g, b;
            
            if (s === 0) {
                r = g = b = l;
            } else {
                const hue2rgb = (p, q, t) => {
                  if (t < 0) t += 1;
                  if (t > 1) t -= 1;
                  if (t < 1/6) return p + (q - p) * 6 * t;
                  if (t < 1/2) return q;
                  if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
                  return p;
                };
               
                const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
                const p = 2 * l - q;
               
                r = hue2rgb(p, q, h + 1/3);
                g = hue2rgb(p, q, h);
                b = hue2rgb(p, q, h - 1/3);
            }
            
            return [
                Math.round(r * 255),
                Math.round(g * 255),
                Math.round(b * 255)
            ];
      }
      
      // 初始绘制
      drawJuliaSet();
    </script>
</body>
</html>
<br><br>

功能说明<br>

交互控制:

可以调整复数c的实部和虚部

可以设置最大迭代次数

有"绘制"按钮应用新参数

有"随机参数"按钮生成随机参数<br>

可视化效果:

朱利亚集合内的点显示为黑色

集合外的点根据逃逸时间显示不同颜色

使用HSL色彩空间生成平滑的颜色过渡<br>

数学原理:

对复平面上的每个点z,计算迭代函数f(z) = z² + c

如果迭代序列不发散(模不超过2),则该点属于朱利亚集合

发散速度决定了点的颜色

樵歌 发表于 2025-6-3 09:59

这个有点意思。{:4_199:}

梦江南 发表于 2025-6-3 10:23

老师很厉害。

红影 发表于 2025-6-3 12:27

这个交互运作很有趣,可以得到很多效果。{:4_204:}
代码貌似和论坛有冲突呢。
页: [1]
查看完整版本: 《朱利亚集合》随机演示图