椭圆函数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; }
- 彩色相位映射:
技术实现亮点
-
核心算法:
- 使用AGM算法近似计算椭圆积分K(k)
- 泰勒展开与周期特性结合的复合计算策略
-
可视化优化:
// 表面数据生成逻辑 for(let i=0; i<=res; i++){ for(let j=0; j<=res; j++){ zValues.push(computeEllipticFunction(z)); } }
-
性能控制:
- 分辨率分级控制(低/中/高)
- Web Worker异步计算支持(预留接口)
教学应用场景
-
周期性观察实验:
- 调整k值观察周期变化
- 对比不同函数的周期特性
-
奇点分析演示:
- 关闭高度限制观察极点
- 配合等高线分析函数行为
-
比较研究:
| 函数类型 | 周期表达式 | 奇点分布 | |----------|--------------------|----------------| | sn(z,k) | 4K, 2iK' | 单极点周期排列 | | ℘(z) | 用户自定义周期格点 | 双极点结构 |
使用注意事项
- 当k → 1时计算稳定性会下降
- 高分辨率模式需要较强GPU支持
- 魏尔斯特拉斯函数采用简化周期模型
提示:按住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>