当前位置: 首页 > article >正文

椭圆函数3D双重周期性交互式演示工具

椭圆函数3D双重周期性交互式演示工具

功能概述

本工具通过Web技术实现了以下核心功能:

1. 多维度参数控制

  • 函数类型选择
    • 雅可比椭圆函数:sn(z,k)/cn(z,k)/dn(z,k)
    • 魏尔斯特拉斯℘函数
  • 动态参数调节
    • 模数k实时调节(0.1 ≤ k ≤ 0.999)
    • 复平面范围设置:
      <input type="number" id="realMin" value="-4">
      <input type="number" id="realMax" value="4">
      
  • 显示效果控制
    • 分辨率选择(40x40至80x80)
    • 高度裁剪(防止奇点干扰)
    • 周期格点显示开关

2. 交互式3D可视化

功能特性操作方式
视图旋转鼠标拖拽
缩放控制鼠标滚轮
视图重置双击画布
表面类型切换模值/实部/虚部三视图模式

3. 实时数学信息反馈

function getPeriodInfo(type, k) {
  // 动态计算并显示周期信息
  return `ω₁ = ${(4*K).toFixed(4)}, ω₂ = ${(2*Kp).toFixed(4)}i`;
}

4. **理论可视化辅助

  • 周期格点动态绘制
    function createPeriodGrid() {
      // 根据当前周期参数生成格线
      return gridLines;
    }
    
  • 彩色相位映射

技术实现亮点

  1. 核心算法

    • 使用AGM算法近似计算椭圆积分K(k)
    • 泰勒展开与周期特性结合的复合计算策略
  2. 可视化优化

    // 表面数据生成逻辑
    for(let i=0; i<=res; i++){
      for(let j=0; j<=res; j++){
        zValues.push(computeEllipticFunction(z));
      }
    }
    
  3. 性能控制

    • 分辨率分级控制(低/中/高)
    • Web Worker异步计算支持(预留接口)

教学应用场景

  1. 周期性观察实验

    • 调整k值观察周期变化
    • 对比不同函数的周期特性
  2. 奇点分析演示

    • 关闭高度限制观察极点
    • 配合等高线分析函数行为
  3. 比较研究

    | 函数类型 | 周期表达式          | 奇点分布       |
    |----------|--------------------|----------------|
    | sn(z,k)  | 4K, 2iK'          | 单极点周期排列 |
    | ℘(z)     | 用户自定义周期格点 | 双极点结构    |
    

使用注意事项

  1. 当k → 1时计算稳定性会下降
  2. 高分辨率模式需要较强GPU支持
  3. 魏尔斯特拉斯函数采用简化周期模型

提示:按住Shift键拖拽可平移观察平面,Ctrl+单击可保存当前视角快照
接下来给出完整代码,可以保存成html文件来使用和预览,加载可能需要一些时间,不过请耐心等待。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>椭圆函数3D双重周期性演示</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdn.plot.ly/plotly-2.12.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/11.2.0/math.min.js"></script>
    <style>
        .math {
            font-family: 'Times New Roman', Times, serif;
            font-style: italic;
        }
        .katex-display {
            overflow-x: auto;
            overflow-y: hidden;
            padding: 0.5em 0;
        }
        .control-panel {
            border-radius: 8px;
            background-color: #f8fafc;
        }
    </style>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css">
    <script src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/contrib/auto-render.min.js"></script>
</head>
<body class="bg-gray-100 min-h-screen">
    <div class="container mx-auto px-4 py-8">
        <header class="mb-8 text-center">
            <h1 class="text-3xl font-bold text-indigo-700 mb-2">椭圆函数的3D双重周期性演示</h1>
            <p class="text-gray-600">通过3D图形交互式探索椭圆函数的复平面行为和周期性质</p>
        </header>

        <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
            <!-- 左侧控制面板 -->
            <div class="control-panel border p-4 shadow-md">
                <h2 class="text-xl font-semibold mb-4 text-indigo-600">参数控制</h2>
                
                <div class="mb-4">
                    <label class="block text-sm font-medium text-gray-700 mb-1">椭圆函数类型</label>
                    <select id="functionType" class="w-full px-3 py-2 border rounded-md">
                        <option value="sn">雅可比椭圆函数 sn(z,k)</option>
                        <option value="cn">雅可比椭圆函数 cn(z,k)</option>
                        <option value="dn">雅可比椭圆函数 dn(z,k)</option>
                        <option value="wp">魏尔斯特拉斯 ℘(z)</option>
                    </select>
                </div>
                
                <div class="mb-4">
                    <label class="block text-sm font-medium text-gray-700 mb-1">模数 k (对于雅可比函数)</label>
                    <input type="range" id="modulusK" min="0.1" max="0.999" step="0.001" value="0.8" class="w-full">
                    <div class="flex justify-between">
                        <span class="text-xs">0.1</span>
                        <span id="kValue" class="text-xs font-semibold">0.8</span>
                        <span class="text-xs">0.999</span>
                    </div>
                </div>
                
                <div class="mb-4">
                    <label class="block text-sm font-medium text-gray-700 mb-1">实部范围</label>
                    <div class="flex items-center space-x-2">
                        <input type="number" id="realMin" value="-4" class="w-1/4 px-2 py-1 border rounded-md">
                        <span></span>
                        <input type="number" id="realMax" value="4" class="w-1/4 px-2 py-1 border rounded-md">
                    </div>
                </div>
                
                <div class="mb-4">
                    <label class="block text-sm font-medium text-gray-700 mb-1">虚部范围</label>
                    <div class="flex items-center space-x-2">
                        <input type="number" id="imagMin" value="-4" class="w-1/4 px-2 py-1 border rounded-md">
                        <span></span>
                        <input type="number" id="imagMax" value="4" class="w-1/4 px-2 py-1 border rounded-md">
                    </div>
                </div>
                
                <div class="mb-4">
                    <label class="block text-sm font-medium text-gray-700 mb-1">分辨率</label>
                    <select id="resolution" class="w-full px-3 py-2 border rounded-md">
                        <option value="40">低 (40x40)</option>
                        <option value="60" selected>中 (60x60)</option>
                        <option value="80">高 (80x80)</option>
                    </select>
                </div>
                
                <div class="mb-4">
                    <label class="block text-sm font-medium text-gray-700 mb-1">显示选项</label>
                    <div class="flex items-center mb-2">
                        <input type="checkbox" id="showGrid" class="mr-2" checked>
                        <span>显示周期格点</span>
                    </div>
                    <div class="flex items-center mb-2">
                        <input type="checkbox" id="showContours" class="mr-2" checked>
                        <span>显示等高线</span>
                    </div>
                    <div class="flex items-center">
                        <input type="checkbox" id="clipHeight" class="mr-2" checked>
                        <span>限制高度 (防止奇点)</span>
                    </div>
                </div>
                
                <div class="mb-4">
                    <label class="block text-sm font-medium text-gray-700 mb-1">3D视图</label>
                    <select id="viewType" class="w-full px-3 py-2 border rounded-md">
                        <option value="magnitude">模值 |f(z)| 的3D表面</option>
                        <option value="real">实部 Re(f(z)) 的3D表面</option>
                        <option value="imag">虚部 Im(f(z)) 的3D表面</option>
                    </select>
                </div>
                
                <button id="updatePlot" class="w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 transition-colors">
                    更新图像
                </button>
            </div>
            
            <!-- 中间图形区域 -->
            <div class="lg:col-span-2 bg-white border shadow-md rounded-md p-4">
                <div class="flex flex-col h-full">
                    <div class="mb-4">
                        <h2 class="text-xl font-semibold text-indigo-600">3D函数可视化</h2>
                        <p id="currentFunction" class="text-gray-600 text-sm my-1">当前函数: sn(z, 0.8)</p>
                        <p class="text-gray-500 text-xs">提示: 可以用鼠标拖动旋转3D图像,滚轮缩放,双击重置视图</p>
                    </div>
                    
                    <div class="h-[500px] w-full mb-4">
                        <div id="surface3dPlot" class="w-full h-full"></div>
                    </div>
                    
                    <div class="p-2">
                        <div class="border rounded-md p-3 bg-gray-50">
                            <h3 class="text-md font-semibold text-gray-700 mb-2">基本周期信息</h3>
                            <div id="periodInfo" class="text-sm">
                                <!-- 基本周期信息将在JavaScript中动态填充 -->
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- 下方理论解释 -->
        <div class="mt-8 bg-white border shadow-md rounded-md p-6">
            <h2 class="text-2xl font-semibold text-indigo-700 mb-4">椭圆函数的双重周期性解释</h2>
            
            <div class="text-gray-800">
                <p class="mb-3">椭圆函数是复分析中一类重要的特殊函数,其最显著的特点是具有<strong>双重周期性</strong>。这意味着对于复变量 z,椭圆函数 f(z) 满足:</p>
                
                <div class="mb-4" id="formula1"></div>
                
                <p class="mb-3">其中 ω₁ 和 ω₂ 是复平面上的两个基本周期,它们线性无关(即 ω₁/ω₂ 不是实数)。这两个周期形成了复平面上的一个平行四边形格点,称为<strong>基本周期平行四边形</strong></p>
                
                <div class="mb-3">
                    <h3 class="text-lg font-semibold text-indigo-600 mb-2">通过3D图形理解双重周期性</h3>
                    <p>在上面的3D图形中,我们可以清晰地看到椭圆函数的周期性表现:</p>
                    <ul class="list-disc list-inside space-y-1 ml-4 my-2">
                        <li>沿着实轴方向,函数值以第一个基本周期 ω₁ 为周期重复</li>
                        <li>沿着虚轴方向,函数值以第二个基本周期 ω₂ 为周期重复</li>
                        <li>整个复平面被划分为周期平行四边形,函数在每个平行四边形中的行为完全相同</li>
                    </ul>
                    <p>通过旋转3D图形,您可以从不同角度观察这种周期性结构,理解椭圆函数如何在复平面上构成"周期性山峰和谷底"的图案。</p>
                </div>
                
                <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
                    <div>
                        <h3 class="text-lg font-semibold text-indigo-600 mb-2">雅可比椭圆函数</h3>
                        <p class="mb-2">雅可比椭圆函数 sn(z,k)、cn(z,k) 和 dn(z,k) 是三个最常见的椭圆函数,其中k是模数(0 < k < 1)。</p>
                        <ul class="list-disc list-inside space-y-1 ml-2">
                            <li>sn(z,k) 具有周期 4K 和 2iK'</li>
                            <li>cn(z,k) 具有周期 4K 和 2K+2iK'</li>
                            <li>dn(z,k) 具有周期 2K 和 4iK'</li>
                        </ul>
                        <p class="mt-2">其中 K=K(k) 是第一类完全椭圆积分,K'=K(k') 是余模数 k'=√(1-k²) 对应的积分。</p>
                    </div>
                    
                    <div>
                        <h3 class="text-lg font-semibold text-indigo-600 mb-2">魏尔斯特拉斯椭圆函数</h3>
                        <p class="mb-2">魏尔斯特拉斯椭圆函数 ℘(z) 是另一类重要的椭圆函数,它可以表示为:</p>
                        <div id="formula2" class="mb-2"></div>
                        <p>其中求和是在格点 Λ=mω₁+nω₂ (m,n∈Z, 除了m=n=0) 上进行的。℘(z) 是一个二重周期函数,具有周期 ω₁ 和 ω₂。</p>
                    </div>
                </div>
                
                <p class="text-sm text-gray-600">注意:在3D视图中,我们可能会看到函数在某些点(如奇点)附近的值非常大。椭圆函数在复平面上具有极点,这在3D表面上表现为"尖峰"。为了更好地观察整体结构,可以使用控制面板中的"限制高度"选项来裁剪这些极值。</p>
            </div>
        </div>
    </div>

    <script>
        // 渲染KaTeX公式
        document.addEventListener("DOMContentLoaded", function() {
            // 渲染第一个公式
            katex.render("f(z + \\omega_1) = f(z) \\quad \\text{和} \\quad f(z + \\omega_2) = f(z)", 
                          document.getElementById("formula1"), {
                              displayMode: true
                          });
            
            // 渲染第二个公式
            katex.render("\\wp(z) = \\frac{1}{z^2} + \\sum_{\\omega \\in \\Lambda \\setminus \\{0\\}} \\left(\\frac{1}{(z-\\omega)^2} - \\frac{1}{\\omega^2}\\right)", 
                          document.getElementById("formula2"), {
                              displayMode: true
                          });
            
            // 初始化图像
            updatePlot();
        });

        // 获取DOM元素
        const updateButton = document.getElementById("updatePlot");
        const functionType = document.getElementById("functionType");
        const modulusK = document.getElementById("modulusK");
        const kValue = document.getElementById("kValue");
        const realMin = document.getElementById("realMin");
        const realMax = document.getElementById("realMax");
        const imagMin = document.getElementById("imagMin");
        const imagMax = document.getElementById("imagMax");
        const resolution = document.getElementById("resolution");
        const viewType = document.getElementById("viewType");
        const showGrid = document.getElementById("showGrid");
        const showContours = document.getElementById("showContours");
        const clipHeight = document.getElementById("clipHeight");
        const currentFunction = document.getElementById("currentFunction");
        const periodInfo = document.getElementById("periodInfo");

        // 更新k值显示
        modulusK.addEventListener("input", function() {
            kValue.textContent = parseFloat(this.value).toFixed(3);
        });

        // 绑定更新按钮事件
        updateButton.addEventListener("click", updatePlot);

        // 椭圆函数的计算
        function computeJacobiSn(z, k) {
            // 这是一个近似实现,完整实现需要更复杂的算法
            let x = z.re;
            let y = z.im;
            
            // 对于小的z,使用泰勒级数近似
            if (Math.abs(x) < 0.1 && Math.abs(y) < 0.1) {
                return math.complex(
                    x - (1 + k*k) * x * x * x / 6,
                    y - (1 + k*k) * x * x * y / 2
                );
            }
            
            // 使用近似周期性质
            let K = calculateK(k);
            let Kp = calculateK(Math.sqrt(1 - k*k));
            
            let re = Math.sin(Math.PI * x / (2 * K)) * Math.cosh(Math.PI * y / (2 * Kp));
            let im = Math.cos(Math.PI * x / (2 * K)) * Math.sinh(Math.PI * y / (2 * Kp));
            let denom = Math.pow(Math.sin(Math.PI * x / (2 * K)), 2) + Math.pow(Math.sinh(Math.PI * y / (2 * Kp)), 2);
            
            return math.complex(re / Math.sqrt(denom), im / Math.sqrt(denom));
        }

        function computeJacobiCn(z, k) {
            let x = z.re;
            let y = z.im;
            
            let K = calculateK(k);
            let Kp = calculateK(Math.sqrt(1 - k*k));
            
            let re = Math.cos(Math.PI * x / (2 * K)) * Math.cosh(Math.PI * y / (2 * Kp));
            let im = -Math.sin(Math.PI * x / (2 * K)) * Math.sinh(Math.PI * y / (2 * Kp));
            let denom = Math.pow(Math.sin(Math.PI * x / (2 * K)), 2) + Math.pow(Math.sinh(Math.PI * y / (2 * Kp)), 2);
            
            return math.complex(re / Math.sqrt(denom), im / Math.sqrt(denom));
        }

        function computeJacobiDn(z, k) {
            let x = z.re;
            let y = z.im;
            
            let K = calculateK(k);
            let Kp = calculateK(Math.sqrt(1 - k*k));
            
            let re = Math.cos(Math.PI * x / (2 * K)) / Math.cosh(Math.PI * y / (2 * Kp));
            let im = Math.sin(Math.PI * x / (2 * K)) * Math.tanh(Math.PI * y / (2 * Kp)) / Math.cosh(Math.PI * y / (2 * Kp));
            
            return math.complex(re, im);
        }

        function computeWeierstrassP(z) {
            // 简化的魏尔斯特拉斯函数计算
            let x = z.re;
            let y = z.im;
            
            // 基本周期选为 2 和 2i
            let wx = 2;
            let wy = 2;
            
            // 取最接近的周期点
            let nx = Math.round(x / wx);
            let ny = Math.round(y / wy);
            
            // 转换到基本周期平行四边形内
            let xp = x - nx * wx;
            let yp = y - ny * wy;
            
            // 模拟魏尔斯特拉斯函数在基本区域的行为
            let r2 = xp*xp + yp*yp;
            if (r2 < 0.01) r2 = 0.01; // 避免除零
            
            let val = 1/r2 + Math.sin(Math.PI * xp / wx) * Math.sin(Math.PI * yp / wy);
            return math.complex(val, 0);
        }

        // 计算椭圆积分K(k)的近似值
        function calculateK(k) {
            if (k >= 1) return 100; // 处理边界情况
            
            // 使用AGM算法计算K
            let a = 1;
            let b = Math.sqrt(1 - k*k);
            let c = k;
            
            for (let i = 0; i < 5; i++) {
                let an = (a + b) / 2;
                let bn = Math.sqrt(a * b);
                let cn = (a - b) / 2;
                
                a = an;
                b = bn;
                c = cn;
            }
            
            return Math.PI / (2 * a);
        }

        // 计算椭圆函数的函数
        function computeEllipticFunction(z, type, k) {
            switch(type) {
                case "sn":
                    return computeJacobiSn(z, k);
                case "cn":
                    return computeJacobiCn(z, k);
                case "dn":
                    return computeJacobiDn(z, k);
                case "wp":
                    return computeWeierstrassP(z);
                default:
                    return math.complex(0, 0);
            }
        }

        // 获取当前函数的周期信息
        function getPeriodInfo(type, k) {
            const K = calculateK(k);
            const Kp = calculateK(Math.sqrt(1 - k*k));
            
            let info = "";
            
            switch(type) {
                case "sn":
                    info = `
                        <p>雅可比椭圆函数 sn(z, ${k.toFixed(3)}) 的基本周期:</p>
                        <ul class="list-disc list-inside ml-4 mt-1">
                            <li>第一基本周期: ω₁ = 4K ≈ ${(4*K).toFixed(4)}</li>
                            <li>第二基本周期: ω₂ = 2iK' ≈ ${(2*Kp).toFixed(4)}i</li>
                        </ul>
                        <p class="mt-2">其中 K = K(${k.toFixed(3)}) ≈ ${K.toFixed(4)} 是第一类完全椭圆积分,<br>
                        K' = K(${Math.sqrt(1-k*k).toFixed(3)}) ≈ ${Kp.toFixed(4)} 是补充模对应的积分。</p>
                    `;
                    break;
                case "cn":
                    info = `
                        <p>雅可比椭圆函数 cn(z, ${k.toFixed(3)}) 的基本周期:</p>
                        <ul class="list-disc list-inside ml-4 mt-1">
                            <li>第一基本周期: ω₁ = 4K ≈ ${(4*K).toFixed(4)}</li>
                            <li>第二基本周期: ω₂ = 2K+2iK' ≈ ${(2*K).toFixed(4)}+${(2*Kp).toFixed(4)}i</li>
                        </ul>
                        <p class="mt-2">其中 K = K(${k.toFixed(3)}) ≈ ${K.toFixed(4)} 是第一类完全椭圆积分,<br>
                        K' = K(${Math.sqrt(1-k*k).toFixed(3)}) ≈ ${Kp.toFixed(4)} 是补充模对应的积分。</p>
                    `;
                    break;
                case "dn":
                    info = `
                        <p>雅可比椭圆函数 dn(z, ${k.toFixed(3)}) 的基本周期:</p>
                        <ul class="list-disc list-inside ml-4 mt-1">
                            <li>第一基本周期: ω₁ = 2K ≈ ${(2*K).toFixed(4)}</li>
                            <li>第二基本周期: ω₂ = 4iK' ≈ ${(4*Kp).toFixed(4)}i</li>
                        </ul>
                        <p class="mt-2">其中 K = K(${k.toFixed(3)}) ≈ ${K.toFixed(4)} 是第一类完全椭圆积分,<br>
                        K' = K(${Math.sqrt(1-k*k).toFixed(3)}) ≈ ${Kp.toFixed(4)} 是补充模对应的积分。</p>
                    `;
                    break;
                case "wp":
                    info = `
                        <p>魏尔斯特拉斯椭圆函数 ℘(z) 的基本周期:</p>
                        <ul class="list-disc list-inside ml-4 mt-1">
                            <li>第一基本周期: ω₁ = 2</li>
                            <li>第二基本周期: ω₂ = 2i</li>
                        </ul>
                        <p class="mt-2">注:在此演示中,我们选择了简化的周期。实际的魏尔斯特拉斯函数允许任意的双周期格点。</p>
                    `;
                    break;
            }
            
            return info;
        }

        // 创建周期格点
        function createPeriodGrid(type, k) {
            let x1, y1, x2, y2;
            let K = calculateK(k);
            let Kp = calculateK(Math.sqrt(1 - k*k));
            
            switch(type) {
                case "sn":
                    x1 = 4 * K;
                    y1 = 0;
                    x2 = 0;
                    y2 = 2 * Kp;
                    break;
                case "cn":
                    x1 = 4 * K;
                    y1 = 0;
                    x2 = 2 * K;
                    y2 = 2 * Kp;
                    break;
                case "dn":
                    x1 = 2 * K;
                    y1 = 0;
                    x2 = 0;
                    y2 = 4 * Kp;
                    break;
                case "wp":
                    x1 = 2;
                    y1 = 0;
                    x2 = 0;
                    y2 = 2;
                    break;
            }
            
            let xMin = parseFloat(realMin.value);
            let xMax = parseFloat(realMax.value);
            let yMin = parseFloat(imagMin.value);
            let yMax = parseFloat(imagMax.value);
            
            let gridLines = [];
            
            // 计算需要绘制多少个周期格子
            let nxMin = Math.floor(xMin / x1) - 1;
            let nxMax = Math.ceil(xMax / x1) + 1;
            let nyMin = Math.floor(yMin / y2) - 1;
            let nyMax = Math.ceil(yMax / y2) + 1;
            
            // 绘制水平方向的格线
            for (let ny = nyMin; ny <= nyMax; ny++) {
                let linex = [];
                let liney = [];
                let linez = [];
                
                for (let x = xMin; x <= xMax; x += (xMax - xMin) / 100) {
                    linex.push(x);
                    liney.push(ny * y2);
                    linez.push(null); // 我们将在z轴上使用null,这样线就会贴在底部
                }
                
                gridLines.push({
                    type: 'scatter3d',
                    mode: 'lines',
                    x: linex,
                    y: liney,
                    z: linez,
                    line: {
                        color: 'rgba(100, 100, 100, 0.4)',
                        width: 1
                    },
                    showlegend: false
                });
            }
            
            // 绘制垂直方向的格线
            for (let nx = nxMin; nx <= nxMax; nx++) {
                let linex = [];
                let liney = [];
                let linez = [];
                
                for (let y = yMin; y <= yMax; y += (yMax - yMin) / 100) {
                    linex.push(nx * x1);
                    liney.push(y);
                    linez.push(null);
                }
                
                gridLines.push({
                    type: 'scatter3d',
                    mode: 'lines',
                    x: linex,
                    y: liney,
                    z: linez,
                    line: {
                        color: 'rgba(100, 100, 100, 0.4)',
                        width: 1
                    },
                    showlegend: false
                });
            }
            
            // 绘制平行四边形格点
            if (x2 !== 0 || y1 !== 0) { // 如果不是矩形格点
                for (let ny = nyMin; ny <= nyMax; ny++) {
                    for (let nx = nxMin; nx <= nxMax; nx++) {
                        let linex = [];
                        let liney = [];
                        let linez = [];
                        
                        // 对角线格线
                        for (let t = 0; t <= 1; t += 0.01) {
                            linex.push(nx * x1 + t * x2);
                            liney.push(ny * y2 + t * y1);
                            linez.push(null);
                        }
                        
                        gridLines.push({
                            type: 'scatter3d',
                            mode: 'lines',
                            x: linex,
                            y: liney,
                            z: linez,
                            line: {
                                color: 'rgba(150, 100, 100, 0.3)',
                                width: 1,
                                dash: 'dot'
                            },
                            showlegend: false
                        });
                    }
                }
            }
            
            return gridLines;
        }

        // 更新图像函数
        function updatePlot() {
            const type = functionType.value;
            const k = parseFloat(modulusK.value);
            const xMin = parseFloat(realMin.value);
            const xMax = parseFloat(realMax.value);
            const yMin = parseFloat(imagMin.value);
            const yMax = parseFloat(imagMax.value);
            const res = parseInt(resolution.value);
            const view = viewType.value;
            const shouldShowGrid = showGrid.checked;
            const shouldShowContours = showContours.checked;
            const shouldClipHeight = clipHeight.checked;
            
            // 更新当前函数显示
            let funcDisplay = "";
            switch(type) {
                case "sn":
                    funcDisplay = `sn(z, ${k.toFixed(3)})`;
                    break;
                case "cn":
                    funcDisplay = `cn(z, ${k.toFixed(3)})`;
                    break;
                case "dn":
                    funcDisplay = `dn(z, ${k.toFixed(3)})`;
                    break;
                case "wp":
                    funcDisplay = `℘(z)`;
                    break;
            }
            currentFunction.textContent = `当前函数: ${funcDisplay}`;
            
            // 更新周期信息
            periodInfo.innerHTML = getPeriodInfo(type, k);
            
            // 生成网格数据
            const dx = (xMax - xMin) / res;
            const dy = (yMax - yMin) / res;
            
            let xValues = Array.from({length: res+1}, (_, i) => xMin + i * dx);
            let yValues = Array.from({length: res+1}, (_, i) => yMin + i * dy);
            let zValues = [];
            let colorValues = []; // 用于存储颜色值(表示相位)
            
            // 最大值上限(用于裁剪极值)
            const maxHeight = 5;
            
            // 生成3D表面数据
            for (let i = 0; i <= res; i++) {
                let zRow = [];
                let colorRow = [];
                let y = yValues[i];
                
                for (let j = 0; j <= res; j++) {
                    let x = xValues[j];
                    let z = math.complex(x, y);
                    
                    let result = computeEllipticFunction(z, type, k);
                    let magnitude = math.abs(result);
                    let phase = math.arg(result);
                    
                    // 根据视图类型确定Z值
                    let zValue;
                    switch(view) {
                        case "magnitude":
                            zValue = magnitude;
                            break;
                        case "real":
                            zValue = result.re;
                            break;
                        case "imag":
                            zValue = result.im;
                            break;
                    }
                    
                    // 裁剪极值
                    if (shouldClipHeight && Math.abs(zValue) > maxHeight) {
                        zValue = Math.sign(zValue) * maxHeight;
                    }
                    
                    zRow.push(zValue);
                    colorRow.push(phase); // 使用相位作为颜色
                }
                
                zValues.push(zRow);
                colorValues.push(colorRow);
            }
            
            // 创建3D表面
            let surfacePlot = {
                type: 'surface',
                x: xValues,
                y: yValues,
                z: zValues,
                colorscale: [
                    [0, 'rgb(255,0,0)'],
                    [0.25, 'rgb(255,255,0)'],
                    [0.5, 'rgb(0,255,0)'],
                    [0.75, 'rgb(0,255,255)'],
                    [1, 'rgb(255,0,0)']
                ],
                showscale: true,
                colorbar: {
                    title: 'arg(f(z))',
                    titleside: 'right',
                    titlefont: {size: 14},
                    tickvals: [-Math.PI, -Math.PI/2, 0, Math.PI/2, Math.PI],
                    ticktext: ['-π', '-π/2', '0', 'π/2', 'π']
                },
                surfacecolor: colorValues,
                cmin: -Math.PI,
                cmax: Math.PI,
                contours: {
                    z: {
                        show: shouldShowContours,
                        usecolormap: true,
                        highlightcolor: "#ffffff",
                        project: {z: true}
                    }
                }
            };
            
            // 图形数据
            let plotData = [surfacePlot];
            
            // 如果需要显示周期格点,添加格线
            if (shouldShowGrid) {
                let gridLines = createPeriodGrid(type, k);
                plotData = plotData.concat(gridLines);
            }
            
            // 布局设置
            let layout = {
                title: '',
                autosize: true,
                margin: {l: 0, r: 0, b: 0, t: 0},
                scene: {
                    xaxis: {title: 'Re(z)'},
                    yaxis: {title: 'Im(z)'},
                    zaxis: {title: view === 'magnitude' ? '|f(z)|' : (view === 'real' ? 'Re(f(z))' : 'Im(f(z))')},
                    aspectratio: {x: 1, y: 1, z: 0.7},
                    camera: {
                        eye: {x: 1.5, y: -1.5, z: 1.2}
                    }
                },
                font: {family: 'Arial'}
            };
            
            // 渲染图像
            Plotly.newPlot('surface3dPlot', plotData, layout);
        }
    </script>
</body>
</html>

http://www.kler.cn/a/572454.html

相关文章:

  • 【hot100】102二叉树的层序遍历
  • 生态安全相关
  • Linux搜索---find
  • 【后端开发面试题】每日 3 题(六)
  • 使用ffmpeg读取mp4文件解码失败
  • Android+SpringBoot的老年人健康饮食小程序平台
  • 基于 Spring Boot 的企业级快速启动模板 —— spring-quick
  • 看视频学习方法总结
  • 知识图谱科研文献推荐系统vue+django+Neo4j的知识图谱
  • 【HarmonyOS Next】自定义Tabs
  • [杂学笔记]面向对象特性、右值引用与移动语义、push_back与emplace_back的区别、读写锁与智能指针对锁的管理、访问网站的全过程
  • 大数据学习(52)-MySQL数据库基本操作
  • QT实现单个控制点在曲线上的贝塞尔曲线
  • c#窗体按键点击事件
  • GenBI 可视化选谁:Python Matplotlib?HTML ?Tableau?
  • 计算机毕业设计SpringBoot+Vue.js电商平台(源码+文档+PPT+讲解)
  • UE身体发光设置覆层材质
  • 高压电路试题(二)
  • sqli-labs靶场通关攻略
  • 网络配置的基本信息