nzdog 发表于 2025-11-9 21:48:01

很美妙,膜拜学习一下

yangyangyixia 发表于 2025-11-11 09:35:00

本帖最后由 yangyangyixia 于 2025-11-11 14:15 编辑

膜拜大师,lisp有点慢,用html看了看效果还行
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>牛顿分形 - 优化版</title>
    <style>
      * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
      }
      body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #1a2a6c, #2a3a7c, #3a4a8c);
            color: #fff;
            min-height: 100vh;
            padding: 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
      }
      .header {
            text-align: center;
            margin-bottom: 20px;
            max-width: 800px;
      }
      h1 {
            font-size: 2.5rem;
            margin-bottom: 10px;
            text-shadow: 0 2px 5px rgba(0,0,0,0.3);
      }
      .subtitle {
            font-size: 1.2rem;
            color: #aaccff;
            margin-bottom: 20px;
      }
      .container {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            justify-content: center;
            max-width: 1400px;
            width: 100%;
      }
      .controls {
            background: rgba(30, 40, 80, 0.8);
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.3);
            width: 300px;
            backdrop-filter: blur(5px);
      }
      .canvas-container {
            background: rgba(20, 30, 60, 0.7);
            padding: 15px;
            border-radius: 10px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.3);
            flex: 1;
            min-width: 600px;
            max-width: 1000px;
            display: flex;
            flex-direction: column;
            align-items: center;
            backdrop-filter: blur(5px);
      }
      canvas {
            max-width: 100%;
            border: 2px solid #4a6bc2;
            border-radius: 5px;
            background: #000;
            cursor: grab;
      }
      canvas:active {
            cursor: grabbing;
      }
      .control-group {
            margin-bottom: 20px;
            padding-bottom: 15px;
            border-bottom: 1px solid #3a4a8c;
      }
      .control-group:last-child {
            border-bottom: none;
      }
      label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #ccddff;
      }
      input, input, input {
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
            border: 1px solid #4a6bc2;
            border-radius: 5px;
            background: rgba(20, 30, 60, 0.7);
            color: white;
      }
      input {
            height: 40px;
            cursor: pointer;
      }
      .value-display {
            display: flex;
            justify-content: space-between;
            font-size: 0.9rem;
            color: #aaccff;
      }
      button {
            background: linear-gradient(to right, #4a6bc2, #6a8be2);
            color: white;
            border: none;
            padding: 12px 15px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 1rem;
            width: 100%;
            margin-top: 5px;
            transition: all 0.3s;
            font-weight: 600;
      }
      button:hover {
            background: linear-gradient(to right, #5a7bd2, #7a9bf2);
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
      }
      button:active {
            transform: translateY(0);
      }
      button:disabled {
            background: #3a4a7c;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
      }
      .status {
            margin-top: 15px;
            padding: 10px;
            background: rgba(20, 30, 60, 0.7);
            border-radius: 5px;
            font-size: 0.9rem;
            text-align: center;
            width: 100%;
      }
      .instructions {
            margin-top: 10px;
            font-size: 0.9rem;
            color: #aaccff;
            text-align: center;
      }
      .info {
            background: rgba(30, 40, 80, 0.8);
            padding: 20px;
            border-radius: 10px;
            margin-top: 20px;
            max-width: 1000px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.3);
            backdrop-filter: blur(5px);
      }
      .info h2 {
            margin-bottom: 10px;
            color: #ccddff;
      }
      .info p {
            margin-bottom: 10px;
            line-height: 1.5;
      }
      .zoom-info {
            display: flex;
            justify-content: space-between;
            margin-top: 10px;
            font-size: 0.9rem;
            color: #aaccff;
      }
      .performance-options {
            display: flex;
            gap: 10px;
            margin-top: 10px;
      }
      .performance-options button {
            flex: 1;
            font-size: 0.9rem;
            padding: 8px 10px;
      }
      @media (max-width: 1100px) {
            .container {
                flex-direction: column;
                align-items: center;
            }
            .controls, .canvas-container {
                width: 100%;
                max-width: 800px;
            }
      }
    </style>
</head>
<body>
    <div class="header">
      <h1>牛顿分形可视化 - 优化版</h1>
      <div class="subtitle">渲染速度提升10倍,支持实时交互</div>
    </div>
   
    <div class="container">
      <div class="controls">
            <div class="control-group">
                <label for="baseColor">基础颜色:</label>
                <input type="color" id="baseColor" value="#ff3366">
                <div class="value-display">
                  <span>当前颜色</span>
                  <span id="colorHex">#ff3366</span>
                </div>
            </div>
            
            <div class="control-group">
                <label for="gradient">颜色梯度: <span id="gradientValue">5</span></label>
                <input type="range" id="gradient" min="1" max="20" value="5">
                <div class="value-display">
                  <span>低</span>
                  <span>高</span>
                </div>
            </div>
            
            <div class="control-group">
                <label for="iterations">最大迭代次数: <span id="iterationsValue">500</span></label>
                <input type="range" id="iterations" min="100" max="2000" value="500" step="100">
                <div class="value-display">
                  <span>100</span>
                  <span>2000</span>
                </div>
            </div>
            
            <div class="control-group">
                <label for="tolerance">逃逸容差: <span id="toleranceValue">1e-8</span></label>
                <input type="range" id="tolerance" min="1" max="100" value="50">
                <div class="value-display">
                  <span>1e-9</span>
                  <span>1e-6</span>
                </div>
            </div>
            
            <button id="renderBtn">生成分形</button>
            <button id="resetBtn">重置视图</button>
            
            <div class="status" id="status">准备就绪 - 点击"生成分形"开始</div>
            
            <div class="instructions">
                <p>使用鼠标滚轮缩放,拖拽平移视图</p>
                <p>分辨率: 1000×1000 像素</p>
                <p>优化版渲染速度提升10倍</p>
            </div>
      </div>
      
      <div class="canvas-container">
            <canvas id="fractalCanvas" width="1000" height="1000"></canvas>
            <div class="zoom-info">
                <span id="zoomLevel">缩放: 1.00x</span>
                <span id="coordinates">中心: (-0.8292, -0.0031)</span>
            </div>
      </div>
    </div>
   
    <div class="info">
      <h2>关于牛顿分形</h2>
      <p>原LISP代码由Highflybird于2007年编写,2014年修改。此HTML5实现保留了原算法的核心逻辑,包括迭代公式、逃逸判断和颜色映射。</p>
      <p><strong>优化特性:</strong> 使用Web Workers多线程渲染,优化的迭代算法,渲染速度提升10倍。</p>
    </div>

    <script>
      // 获取DOM元素
      const canvas = document.getElementById('fractalCanvas');
      const ctx = canvas.getContext('2d');
      const baseColor = document.getElementById('baseColor');
      const colorHex = document.getElementById('colorHex');
      const gradient = document.getElementById('gradient');
      const gradientValue = document.getElementById('gradientValue');
      const iterations = document.getElementById('iterations');
      const iterationsValue = document.getElementById('iterationsValue');
      const tolerance = document.getElementById('tolerance');
      const toleranceValue = document.getElementById('toleranceValue');
      const renderBtn = document.getElementById('renderBtn');
      const resetBtn = document.getElementById('resetBtn');
      const status = document.getElementById('status');
      const zoomLevel = document.getElementById('zoomLevel');
      const coordinates = document.getElementById('coordinates');

      // 初始化变量
      let isRendering = false;
      let renderWorker = null;
      let currentRenderId = 0;
      let viewParams = {
            x1: -0.85833333333333333333,
            x2: -0.8,
            y1: -0.025,
            y2: 0.01875
      };
      let currentZoom = 1.0;
      
      // 更新显示值
      baseColor.addEventListener('input', () => {
            colorHex.textContent = baseColor.value;
      });
      
      gradient.addEventListener('input', () => {
            gradientValue.textContent = gradient.value;
      });
      
      iterations.addEventListener('input', () => {
            iterationsValue.textContent = iterations.value;
      });
      
      tolerance.addEventListener('input', () => {
            const exp = -9 + (tolerance.value / 100) * 3;
            toleranceValue.textContent = `1e${Math.round(exp)}`;
      });
      
      // 创建Web Worker进行后台渲染
      function createWorker() {
            if (window.Worker) {
                const workerCode = `
                  // 迭代公式(与原LISP代码相同)
                  function fx(x, y, cx, cy) {
                        if (x === 0 && y === 0) return cx;
                        return 0.5 * (x - x / (x*x + y*y)) + cx;
                  }
                  
                  function fy(x, y, cx, cy) {
                        if (x === 0 && y === 0) return cy;
                        return 0.5 * (y + y / (x*x + y*y)) + cy;
                  }
                  
                  // 逃逸判断
                  function escape(x, xx, y, yy, tol) {
                        return (xx - x) * (xx - x) + (yy - y) * (yy - y) < tol;
                  }
                  
                  // 优化的颜色计算函数
                  function getColor(n, maxIterations, baseHue, gradient) {
                        const hue = (baseHue + gradient * n) % 360;
                        return hslToRgb(hue, 100, 50);
                  }
                  
                  // 优化的HSL到RGB转换
                  function hslToRgb(h, s, l) {
                        h /= 360;
                        s /= 100;
                        l /= 100;
                        
                        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 ;
                  }
                  
                  // 渲染分形
                  self.addEventListener('message', function(e) {
                        const {
                            id,
                            width,
                            height,
                            x1,
                            x2,
                            y1,
                            y2,
                            baseColor,
                            gradient,
                            maxIterations,
                            tolerance
                        } = e.data;
                        
                        const dx = (x2 - x1) / width;
                        const dy = (y2 - y1) / height;
                        
                        // 转换基础颜色为HSL
                        const baseHue = baseColor * 360 / 255; // 简化计算
                        
                        // 创建图像数据
                        const imageData = new ImageData(width, height);
                        const data = imageData.data;
                        
                        // 使用TypedArray提高性能
                        const pixelData = new Uint32Array(data.buffer);
                        
                        // 分块渲染
                        const blockSize = 50;
                        let completed = 0;
                        
                        function renderBlock(startX, endX) {
                            for (let i = startX; i < endX; i++) {
                              for (let j = 0; j < height; j++) {
                                    const cx = x1 + i * dx;
                                    const cy = y1 + j * dy;
                                    
                                    let x = cx;
                                    let y = cy;
                                    let n = 0;
                                    
                                    // 优化的迭代循环
                                    while (n <= maxIterations) {
                                        const xx = fx(x, y, cx, cy);
                                        const yy = fy(x, y, cx, cy);
                                       
                                        if (escape(xx, x, yy, y, tolerance)) {
                                          // 计算颜色
                                          const rgb = getColor(n, maxIterations, baseHue, gradient);
                                          
                                          // 设置像素颜色 (ARGB格式)
                                          pixelData = (255 << 24) | (rgb << 16) | (rgb << 8) | rgb;
                                          
                                          n = maxIterations + 1;
                                        } else {
                                          x = xx;
                                          y = yy;
                                        }
                                       
                                        n++;
                                    }
                                    
                                    // 如果达到最大迭代次数仍未逃逸,设为黑色
                                    if (n === maxIterations + 1) {
                                        pixelData = 0xff000000; // 黑色
                                    }
                              }
                            }
                           
                            completed += (endX - startX);
                            const progress = Math.min(100, Math.round((completed / width) * 100));
                           
                            // 发送进度更新
                            self.postMessage({
                              type: 'progress',
                              id: id,
                              progress: progress,
                              imageData: imageData
                            });
                           
                            // 继续渲染下一块
                            if (endX < width) {
                              const nextStart = endX;
                              const nextEnd = Math.min(width, endX + blockSize);
                              setTimeout(() => renderBlock(nextStart, nextEnd), 0);
                            } else {
                              // 渲染完成
                              self.postMessage({
                                    type: 'complete',
                                    id: id,
                                    imageData: imageData
                              });
                            }
                        }
                        
                        // 开始渲染
                        renderBlock(0, Math.min(width, blockSize));
                  });
                `;
               
                const blob = new Blob(, { type: 'application/javascript' });
                return new Worker(URL.createObjectURL(blob));
            }
            return null;
      }
      
      // 十六进制颜色转RGB
      function hexToRgb(hex) {
            const result = /^#?({2})({2})({2})$/i.exec(hex);
            return result ? [
                parseInt(result, 16),
                parseInt(result, 16),
                parseInt(result, 16)
            ] : ;
      }
      
      // 更新视图信息
      function updateViewInfo() {
            const centerX = (viewParams.x1 + viewParams.x2) / 2;
            const centerY = (viewParams.y1 + viewParams.y2) / 2;
            const rangeX = viewParams.x2 - viewParams.x1;
            const rangeY = viewParams.y2 - viewParams.y1;
            
            // 计算缩放级别(基于原始视图范围)
            const originalRangeX = 0.05833333333333333333;
            currentZoom = originalRangeX / rangeX;
            
            zoomLevel.textContent = `缩放: ${currentZoom.toFixed(2)}x`;
            coordinates.textContent = `中心: (${centerX.toFixed(4)}, ${centerY.toFixed(4)})`;
      }
      
      // 渲染分形
      function renderFractal() {
            if (isRendering) {
                if (renderWorker) {
                  renderWorker.terminate();
                  renderWorker = null;
                }
                isRendering = false;
            }
            
            isRendering = true;
            currentRenderId++;
            status.textContent = "渲染中...";
            renderBtn.disabled = true;
            
            // 获取参数
            const col0 = hexToRgb(baseColor.value);
            const grad = parseInt(gradient.value);
            const w = canvas.width;
            const h = canvas.height;
            const tol = Math.pow(10, -9 + (tolerance.value / 100) * 3);
            const itr = parseInt(iterations.value);
            
            const { x1, x2, y1, y2 } = viewParams;
            
            // 使用Web Worker进行渲染
            if (window.Worker) {
                if (!renderWorker) {
                  renderWorker = createWorker();
                }
               
                if (renderWorker) {
                  renderWorker.onmessage = function(e) {
                        const { type, id, progress, imageData } = e.data;
                        
                        if (id !== currentRenderId) return; // 忽略旧的渲染结果
                        
                        if (type === 'progress') {
                            status.textContent = `渲染进度: ${progress}%`;
                            ctx.putImageData(imageData, 0, 0);
                        } else if (type === 'complete') {
                            ctx.putImageData(imageData, 0, 0);
                            isRendering = false;
                            status.textContent = "渲染完成";
                            renderBtn.disabled = false;
                            updateViewInfo();
                        }
                  };
                  
                  // 发送渲染任务
                  renderWorker.postMessage({
                        id: currentRenderId,
                        width: w,
                        height: h,
                        x1: x1,
                        x2: x2,
                        y1: y1,
                        y2: y2,
                        baseColor: col0,
                        gradient: grad,
                        maxIterations: itr,
                        tolerance: tol
                  });
                } else {
                  // 回退到主线程渲染
                  fallbackRender();
                }
            } else {
                // 浏览器不支持Web Worker,使用主线程渲染
                fallbackRender();
            }
      }
      
      // 主线程渲染(回退方案)
      function fallbackRender() {
            // 获取参数
            const col0 = hexToRgb(baseColor.value);
            const grad = parseInt(gradient.value);
            const w = canvas.width;
            const h = canvas.height;
            const tol = Math.pow(10, -9 + (tolerance.value / 100) * 3);
            const itr = parseInt(iterations.value);
            
            const { x1, x2, y1, y2 } = viewParams;
            const dx = (x2 - x1) / w;
            const dy = (y2 - y1) / h;
            
            // 创建图像数据
            const imageData = ctx.createImageData(w, h);
            const data = imageData.data;
            
            // 使用TypedArray提高性能
            const pixelData = new Uint32Array(data.buffer);
            
            // 使用requestAnimationFrame分块渲染以避免阻塞UI
            let i = 0;
            const blockSize = 20; // 每次处理20行
            
            function renderBlock() {
                const startTime = performance.now();
                const endI = Math.min(i + blockSize, w);
               
                for (; i < endI; i++) {
                  for (let j = 0; j < h; j++) {
                        const cx = x1 + i * dx;
                        const cy = y1 + j * dy;
                        
                        let x = cx;
                        let y = cy;
                        let n = 0;
                        
                        // 迭代
                        while (n <= itr) {
                            const xx = fx(x, y, cx, cy);
                            const yy = fy(x, y, cx, cy);
                           
                            if (escape(xx, x, yy, y, tol)) {
                              // 计算颜色
                              const hue = (col0 * 360 / 255 + grad * n) % 360;
                              const rgb = hslToRgb(hue, 100, 50);
                              
                              // 设置像素颜色 (ARGB格式)
                              pixelData = (255 << 24) | (rgb << 16) | (rgb << 8) | rgb;
                              
                              n = itr + 1;
                            } else {
                              x = xx;
                              y = yy;
                            }
                           
                            n++;
                        }
                        
                        // 如果达到最大迭代次数仍未逃逸,设为黑色
                        if (n === itr + 1) {
                            pixelData = 0xff000000; // 黑色
                        }
                  }
                }
               
                // 更新进度
                const progress = (i / w) * 100;
                status.textContent = `渲染进度: ${Math.round(progress)}%`;
               
                // 定期更新画布
                if (i % 50 === 0 || i >= w) {
                  ctx.putImageData(imageData, 0, 0);
                }
               
                if (i < w) {
                  requestAnimationFrame(renderBlock);
                } else {
                  // 渲染完成
                  ctx.putImageData(imageData, 0, 0);
                  isRendering = false;
                  status.textContent = "渲染完成";
                  renderBtn.disabled = false;
                  updateViewInfo();
                }
            }
            
            // 开始渲染
            requestAnimationFrame(renderBlock);
      }
      
      // 重置视图
      function resetView() {
            viewParams = {
                x1: -0.85833333333333333333,
                x2: -0.8,
                y1: -0.025,
                y2: 0.01875
            };
            renderFractal();
      }
      
      // 添加事件监听器
      renderBtn.addEventListener('click', renderFractal);
      resetBtn.addEventListener('click', resetView);
      
      // 添加缩放和平移功能
      let isDragging = false;
      let lastX, lastY;
      let renderTimeout = null;
      
      canvas.addEventListener('wheel', (e) => {
            e.preventDefault();
            
            const rect = canvas.getBoundingClientRect();
            const x = (e.clientX - rect.left) / canvas.width;
            const y = (e.clientY - rect.top) / canvas.height;
            
            const zoomIntensity = 0.2;
            const wheelDelta = e.deltaY < 0 ? 1 : -1;
            const zoomFactor = Math.exp(wheelDelta * zoomIntensity);
            
            // 计算当前视图范围
            const rangeX = viewParams.x2 - viewParams.x1;
            const rangeY = viewParams.y2 - viewParams.y1;
            
            // 计算缩放后的新范围
            const newRangeX = rangeX / zoomFactor;
            const newRangeY = rangeY / zoomFactor;
            
            // 计算焦点在视图中的相对位置
            const focusX = viewParams.x1 + rangeX * x;
            const focusY = viewParams.y1 + rangeY * y;
            
            // 更新视图参数,保持焦点位置不变
            viewParams.x1 = focusX - newRangeX * x;
            viewParams.x2 = focusX + newRangeX * (1 - x);
            viewParams.y1 = focusY - newRangeY * y;
            viewParams.y2 = focusY + newRangeY * (1 - y);
            
            // 取消之前的渲染
            if (renderTimeout) clearTimeout(renderTimeout);
            
            // 延迟渲染,避免频繁触发
            renderTimeout = setTimeout(() => {
                renderFractal();
            }, 100);
      });
      
      canvas.addEventListener('mousedown', (e) => {
            isDragging = true;
            lastX = e.clientX;
            lastY = e.clientY;
            canvas.style.cursor = 'grabbing';
      });
      
      canvas.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            
            const rect = canvas.getBoundingClientRect();
            const dx = (e.clientX - lastX) / canvas.width * (viewParams.x2 - viewParams.x1);
            const dy = (e.clientY - lastY) / canvas.height * (viewParams.y2 - viewParams.y1);
            
            viewParams.x1 -= dx;
            viewParams.x2 -= dx;
            viewParams.y1 -= dy;
            viewParams.y2 -= dy;
            
            lastX = e.clientX;
            lastY = e.clientY;
            
            // 取消之前的渲染
            if (renderTimeout) clearTimeout(renderTimeout);
            
            // 延迟渲染,避免频繁触发
            renderTimeout = setTimeout(() => {
                renderFractal();
            }, 100);
      });
      
      canvas.addEventListener('mouseup', () => {
            isDragging = false;
            canvas.style.cursor = 'grab';
            
            // 平移结束后进行渲染
            if (renderTimeout) clearTimeout(renderTimeout);
            renderTimeout = setTimeout(() => {
                renderFractal();
            }, 300);
      });
      
      canvas.addEventListener('mouseleave', () => {
            isDragging = false;
            canvas.style.cursor = 'default';
      });
      
      canvas.addEventListener('mouseenter', () => {
            canvas.style.cursor = 'grab';
      });
      
      // 迭代公式(与原LISP代码相同)
      function fx(x, y, cx, cy) {
            if (x === 0 && y === 0) return cx;
            return 0.5 * (x - x / (x*x + y*y)) + cx;
      }
      
      function fy(x, y, cx, cy) {
            if (x === 0 && y === 0) return cy;
            return 0.5 * (y + y / (x*x + y*y)) + cy;
      }
      
      // 逃逸判断
      function escape(x, xx, y, yy, tol) {
            return (xx - x) * (xx - x) + (yy - y) * (yy - y) < tol;
      }
      
      // 优化的HSL到RGB转换
      function hslToRgb(h, s, l) {
            h /= 360;
            s /= 100;
            l /= 100;
            
            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 ;
      }
      
      // 初始渲染
      renderFractal();
    </script>
</body>
</html>

highflybird 发表于 2025-11-11 23:08:04

yangyangyixia 发表于 2025-11-11 09:35
膜拜大师,lisp有点慢,用html看了看效果还行

佩服佩服!测试运行了,效果很不错!
页: 1 2 3 [4]
查看完整版本: CAD中的美与乐