独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>铰接式履带系统原理验证 - IFR理想解</title>
<style>
:root {
--bg-color: #060913;
--grid-color: #121a2f;
--cyan-glow: #00f0ff;
--orange-alert: #ff5500;
--green-safe: #00ff66;
--text-main: #a3b8cc;
--text-dim: #4d6680;
--panel-bg: rgba(6, 9, 19, 0.85);
--panel-border: rgba(0, 240, 255, 0.2);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: var(--bg-color);
color: var(--text-main);
font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
overflow: hidden;
width: 100vw;
height: 100vh;
}
/* 绝对定位的极简UI面板,严格限制尺寸与位置,避免遮挡动画主体 */
.overlay-panel {
position: absolute;
background: var(--panel-bg);
border: 1px solid var(--panel-border);
padding: 12px 16px;
border-radius: 4px;
backdrop-filter: blur(4px);
pointer-events: none;
z-index: 10;
}
.top-left { top: 20px; left: 20px; }
.top-right { top: 20px; right: 20px; }
.bottom-left { bottom: 20px; left: 20px; }
.bottom-right { bottom: 20px; right: 20px; }
.text-sm { font-size: 13px; line-height: 1.6; }
.text-xs { font-size: 11px; line-height: 1.4; color: var(--text-dim); }
.title { color: var(--cyan-glow); font-weight: bold; font-size: 14px; margin-bottom: 8px; text-transform: uppercase; letter-spacing: 1px; }
.data-row { display: flex; justify-content: space-between; gap: 24px; }
.data-label { color: var(--text-dim); }
.data-value { color: var(--green-safe); font-weight: bold; font-variant-numeric: tabular-nums; }
.data-value.alert { color: var(--orange-alert); }
#canvas-container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
svg {
width: 100%;
height: 100%;
max-height: 100vh;
}
/* SVG 内部样式 */
.grid-line { stroke: var(--grid-color); stroke-width: 1; }
.terrain-line { fill: none; stroke: var(--text-dim); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.terrain-fill { fill: rgba(77, 102, 128, 0.05); }
.module-body { fill: #0f1626; stroke: var(--cyan-glow); stroke-width: 1.5; }
.track-path { fill: none; stroke: var(--text-main); stroke-width: 4; stroke-dasharray: 6 4; stroke-linecap: round; }
.joint-line { fill: none; stroke-width: 4; stroke-linecap: round; transition: stroke 0.2s; }
.joint-node { fill: var(--bg-color); stroke-width: 2; transition: stroke 0.2s; }
.annotation { font-family: sans-serif; font-size: 12px; fill: var(--text-dim); }
.divider { stroke: var(--grid-color); stroke-width: 2; stroke-dasharray: 10 10; }
</style>
</head>
<body>
<!-- 极简信息面板:布局于边缘,采用小字号 -->
<div class="overlay-panel top-left text-sm">
<div class="title">IFR 系统状态 // 空间分离与动态性原理</div>
<div class="text-xs">
> 核心矛盾已消除:传统长履带的高转弯阻力与地形适应性差<br>
> 创新方案:多段独立短履带 + 柔性扭力弹簧万向节<br>
> 观测对象:左侧 [台阶自适应] / 右侧 [零半径差速转向]
</div>
</div>
<div class="overlay-panel top-right text-sm">
<div class="title">差速驱动监控 (俯视图)</div>
<div id="diff-telemetry">
<!-- 由JS动态填充 -->
</div>
<div class="text-xs" style="margin-top: 8px;">
*外侧履带增速,内侧减速以实现柔顺过弯
</div>
</div>
<div class="overlay-panel bottom-left text-sm">
<div class="title">铰接弯折角监控 (侧视图)</div>
<div id="angle-telemetry">
<!-- 由JS动态填充 -->
</div>
<div class="text-xs" style="margin-top: 8px;">
*允许最大弯折角: 45°
</div>
</div>
<div class="overlay-panel bottom-right text-sm">
<div class="text-xs text-right">
[ 纯运动学原理验证 ]<br>
自动循环播放中...
</div>
</div>
<div id="canvas-container">
<svg id="main-canvas" viewBox="0 0 1200 600" preserveAspectRatio="xMidYMid meet">
<defs>
<pattern id="bg-grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" class="grid-line" />
</pattern>
<filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<filter id="glow-orange" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="4" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
</defs>
<!-- 背景网格 -->
<rect width="100%" height="100%" fill="url(#bg-grid)" />
<!-- 左右分界线 -->
<line x1="600" y1="50" x2="600" y2="550" class="divider" />
<!-- 场景标注 -->
<text x="300" y="40" class="annotation" text-anchor="middle" fill="var(--cyan-glow)">[ 剖面侧视图:被动地形自适应起伏 ]</text>
<text x="900" y="40" class="annotation" text-anchor="middle" fill="var(--cyan-glow)">[ 俯视平面图:多舱段协同差速过弯 ]</text>
<!-- 左侧:侧视图地形 (台阶) -->
<g id="terrain-side">
<path id="side-path-line" class="terrain-line" d="" />
<path id="side-path-fill" class="terrain-fill" d="" />
</g>
<!-- 右侧:俯视图地形 (L型转角平台) -->
<g id="terrain-top">
<path id="top-path-line" class="terrain-line" d="" stroke-dasharray="10 10" />
<!-- 绘制平台边缘 -->
<path d="M 650 350 L 800 350 A 50 50 0 0 0 850 300 L 850 100" class="terrain-line" opacity="0.3" />
<path d="M 650 450 L 800 450 A 150 150 0 0 0 950 300 L 950 100" class="terrain-line" opacity="0.3" />
</g>
<!-- 动态渲染的车辆组 -->
<g id="vehicles">
<g id="vehicle-side"></g>
<g id="vehicle-top"></g>
</g>
</svg>
</div>
<script>
/**
* 纯运动学数学模型与渲染逻辑
* 核心设计:基于TRIZ最终理想解,直接展示系统如何利用柔性铰接消除矛盾。
*/
const canvas = document.getElementById('main-canvas');
const vehicleSideGroup = document.getElementById('vehicle-side');
const vehicleTopGroup = document.getElementById('vehicle-top');
const diffTelemetry = document.getElementById('diff-telemetry');
const angleTelemetry = document.getElementById('angle-telemetry');
// 系统参数
const NUM_MODULES = 4;
const MOD_LENGTH = 50; // 单个舱段基础长度
const SPACING = 65; // 舱段中心间距
const BASE_SPEED = 1.2; // 基础运行速度
// 状态变量
let global_s = 0; // 全局路径进度
// 存储各个舱段的履带滚动偏移量,用于独立差速展示
let trackOffsetsSide = [0, 0, 0, 0];
let trackOffsetsTopL = [0, 0, 0, 0];
let trackOffsetsTopR = [0, 0, 0, 0];
/**
* 侧视图路径函数:模拟台阶地形
* 输入路径长度s,返回 {x, y, angle}
*/
function getSideTransform(s) {
// 地形分段定点
// 平地 -> 斜坡(爬上台阶) -> 平地平台 -> 斜坡(爬上第二台阶) -> 平地
if (s < 150) return { x: s, y: 400, angle: 0 };
s -= 150;
if (s < 99) return { x: 150 + s * 0.707, y: 400 - s * 0.707, angle: -45 };
s -= 99;
if (s < 130) return { x: 220 + s, y: 330, angle: 0 };
s -= 130;
if (s < 99) return { x: 350 + s * 0.707, y: 330 - s * 0.707, angle: -45 };
s -= 99;
return { x: 420 + s, y: 260, angle: 0 };
}
/**
* 俯视图路径函数:模拟L型狭窄平台过弯
* 输入路径长度s,返回 {x, y, angle}
*/
function getTopTransform(s) {
// 平直 -> 90度圆弧转向 -> 平直
if (s < 200) return { x: 650 + s, y: 400, angle: 0 };
s -= 200;
if (s < 157.08) { // 100 * PI / 2
let a = s / 100; // 弧度
return {
x: 850 + 100 * Math.sin(a),
y: 300 + 100 * Math.cos(a),
angle: -a * 180 / Math.PI
};
}
s -= 157.08;
return { x: 950, y: 300 - s, angle: -90 };
}
// 初始化绘制静态地形线
function initTerrain() {
let sideD = "M 0 400 L 150 400 L 220 330 L 350 330 L 420 260 L 600 260";
document.getElementById('side-path-line').setAttribute('d', sideD);
document.getElementById('side-path-fill').setAttribute('d', sideD + " L 600 500 L 0 500 Z");
let topD = "M 650 400 L 850 400 A 100 100 0 0 0 950 300 L 950 100";
document.getElementById('top-path-line').setAttribute('d', topD);
}
// 创建SVG元素的辅助函数
function createSVG(tag, attrs) {
let el = document.createElementNS("http://www.w3.org/2000/svg", tag);
for (let k in attrs) el.setAttribute(k, attrs[k]);
return el;
}
// 初始化车辆DOM结构
function initVehicles() {
for (let i = 0; i < NUM_MODULES; i++) {
// 侧视图舱段
let gSide = createSVG('g', { id: `mod-side-${i}` });
// 履带(背景)
gSide.appendChild(createSVG('rect', { x: -28, y: -16, width: 56, height: 32, rx: 8, class: 'track-path' }));
// 车体
gSide.appendChild(createSVG('rect', { x: -25, y: -10, width: 50, height: 20, rx: 4, class: 'module-body' }));
// 俯视图舱段
let gTop = createSVG('g', { id: `mod-top-${i}` });
// 左履带
gTop.appendChild(createSVG('rect', { x: -28, y: -24, width: 56, height: 10, rx: 3, class: 'track-path' }));
// 右履带
gTop.appendChild(createSVG('rect', { x: -28, y: 14, width: 56, height: 10, rx: 3, class: 'track-path' }));
// 车体
gTop.appendChild(createSVG('rect', { x: -25, y: -20, width: 50, height: 40, rx: 4, class: 'module-body' }));
vehicleSideGroup.appendChild(gSide);
vehicleTopGroup.appendChild(gTop);
// 添加关节连接线与节点 (不给第0节车头加)
if (i > 0) {
vehicleSideGroup.appendChild(createSVG('line', { id: `joint-line-side-${i}`, class: 'joint-line' }));
vehicleSideGroup.appendChild(createSVG('circle', { id: `joint-node-side-${i}`, r: 4, class: 'joint-node' }));
vehicleTopGroup.appendChild(createSVG('line', { id: `joint-line-top-${i}`, class: 'joint-line' }));
vehicleTopGroup.appendChild(createSVG('circle', { id: `joint-node-top-${i}`, r: 4, class: 'joint-node' }));
}
}
}
// 格式化数字
function fmt(num) {
return num.toFixed(1).padStart(5, '\u00A0'); // 保持等宽对齐
}
// 动画主循环
function renderLoop() {
global_s += BASE_SPEED;
if (global_s > 850) global_s = -50; // 循环播放
let sideHtml = '';
let topHtml = '';
// 临时存储各节点中心用于绘制关节
let sideCenters = [];
let topCenters = [];
for (let i = 0; i < NUM_MODULES; i++) {
// 计算当前舱段在路径上的位置
let s_mod = global_s - i * SPACING;
let tSide = getSideTransform(s_mod);
let tTop = getTopTransform(s_mod);
sideCenters.push(tSide);
topCenters.push(tTop);
// --- 逻辑与数据计算 ---
// 1. 侧视图弯折角计算 (与前一节的夹角)
let angleDiffSide = 0;
if (i > 0) {
angleDiffSide = Math.abs(sideCenters[i-1].angle - tSide.angle);
}
// 2. 俯视图差速计算
// 在 s=200 到 s=357 的区间内处于转弯状态
let isTurning = s_mod > 200 && s_mod < 357;
let vL = BASE_SPEED;
let vR = BASE_SPEED;
if (isTurning) {
// 左转弯,外侧(右)履带增速,内侧(左)履带减速
vL = BASE_SPEED * 0.5;
vR = BASE_SPEED * 1.5;
}
// 更新履带位移状态
trackOffsetsSide[i] -= BASE_SPEED;
trackOffsetsTopL[i] -= vL;
trackOffsetsTopR[i] -= vR;
// --- DOM 渲染 ---
// 侧视图舱段更新
let elSide = document.getElementById(`mod-side-${i}`);
elSide.setAttribute('transform', `translate(${tSide.x}, ${tSide.y}) rotate(${tSide.angle})`);
elSide.children[0].setAttribute('stroke-dashoffset', trackOffsetsSide[i]); // 更新履带滚动
// 俯视图舱段更新
let elTop = document.getElementById(`mod-top-${i}`);
elTop.setAttribute('transform', `translate(${tTop.x}, ${tTop.y}) rotate(${tTop.angle})`);
elTop.children[0].setAttribute('stroke-dashoffset', trackOffsetsTopL[i]); // 左履带
elTop.children[1].setAttribute('stroke-dashoffset', trackOffsetsTopR[i]); // 右履带
// 关节渲染与视觉警示
if (i > 0) {
let pSide = sideCenters[i-1];
let pTop = topCenters[i-1];
// 侧视关节
let jlSide = document.getElementById(`joint-line-side-${i}`);
let jnSide = document.getElementById(`joint-node-side-${i}`);
let midSideX = (tSide.x + pSide.x)/2;
let midSideY = (tSide.y + pSide.y)/2;
jlSide.setAttribute('x1', tSide.x); jlSide.setAttribute('y1', tSide.y);
jlSide.setAttribute('x2', pSide.x); jlSide.setAttribute('y2', pSide.y);
jnSide.setAttribute('cx', midSideX); jnSide.setAttribute('cy', midSideY);
// 角度大时触发高亮(表示万向节柔性生效)
let alertColor = angleDiffSide > 10 ? 'var(--orange-alert)' : 'var(--cyan-glow)';
jlSide.setAttribute('stroke', alertColor);
jnSide.setAttribute('stroke', alertColor);
if(angleDiffSide > 10) jnSide.setAttribute('filter', 'url(#glow-orange)');
else jnSide.removeAttribute('filter');
// 俯视关节
let jlTop = document.getElementById(`joint-line-top-${i}`);
let jnTop = document.getElementById(`joint-node-top-${i}`);
let midTopX = (tTop.x + pTop.x)/2;
let midTopY = (tTop.y + pTop.y)/2;
jlTop.setAttribute('x1', tTop.x); jlTop.setAttribute('y1', tTop.y);
jlTop.setAttribute('x2', pTop.x); jlTop.setAttribute('y2', pTop.y);
jnTop.setAttribute('cx', midTopX); jnTop.setAttribute('cy', midTopY);
let turnAlert = isTurning ? 'var(--green-safe)' : 'var(--cyan-glow)';
jlTop.setAttribute('stroke', turnAlert);
jnTop.setAttribute('stroke', turnAlert);
}
// --- UI 面板数据构建 ---
if (i > 0) {
let alertClass = angleDiffSide > 10 ? 'alert' : '';
sideHtml += `<div class="data-row"><span class="data-label">关节 ${i-1}-${i} 角度差:</span><span class="data-value ${alertClass}">${fmt(angleDiffSide)}°</span></div>`;
}
let diffStatus = isTurning ? `<span style="color:var(--orange-alert)">减速</span> / <span style="color:var(--green-safe)">增速</span>` : '匀速同步';
topHtml += `<div class="data-row"><span class="data-label">舱段 ${i} L/R:</span><span class="data-value">${diffStatus}</span></div>`;
}
// 更新DOM数据
angleTelemetry.innerHTML = sideHtml;
diffTelemetry.innerHTML = topHtml;
requestAnimationFrame(renderLoop);
}
// 启动系统
initTerrain();
initVehicles();
requestAnimationFrame(renderLoop);
</script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
