分享图
动画工坊
引擎就绪
<!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>
        /* CSS Variables for Bold Cyber-Industrial Aesthetic */
        :root {
            --bg-base: #020617; /* Very dark slate */
            --bg-grid: #1e293b;
            --accent-cyan: #06b6d4;
            --accent-amber: #f59e0b;
            --accent-rose: #e11d48;
            --text-main: #94a3b8;
            --text-bright: #f8fafc;
            --hud-bg: rgba(2, 6, 23, 0.75);
            --hud-border: rgba(6, 182, 212, 0.3);
            
            font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
        }

        body, html {
            margin: 0;
            padding: 0;
            width: 100vw;
            height: 100vh;
            background-color: var(--bg-base);
            color: var(--text-main);
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
            background-image: 
                linear-gradient(var(--bg-grid) 1px, transparent 1px),
                linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px);
            background-size: 40px 40px;
            background-position: center center;
        }

        /* Subtle radial vignette to focus center */
        body::after {
            content: '';
            position: absolute;
            top: 0; left: 0; right: 0; bottom: 0;
            background: radial-gradient(circle at center, transparent 30%, var(--bg-base) 100%);
            pointer-events: none;
            z-index: 0;
        }

        #animation-container {
            position: relative;
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 1;
        }

        svg {
            width: 100%;
            height: 100%;
            max-width: 900px;
            max-height: 900px;
            filter: drop-shadow(0 0 20px rgba(6, 182, 212, 0.1));
        }

        /* UI HUD Elements - Strictly confined to edges, small font */
        .hud-panel {
            position: absolute;
            background: var(--hud-bg);
            border: 1px solid var(--hud-border);
            padding: 12px 16px;
            border-radius: 4px;
            backdrop-filter: blur(8px);
            font-size: 12px;
            z-index: 10;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .hud-top-left { top: 20px; left: 20px; }
        .hud-top-right { top: 20px; right: 20px; text-align: right; }
        .hud-bottom-left { bottom: 20px; left: 20px; width: 280px; }
        .hud-bottom-right { bottom: 20px; right: 20px; }

        .hud-title {
            color: var(--text-bright);
            font-size: 14px;
            font-weight: bold;
            letter-spacing: 2px;
            margin-bottom: 4px;
            border-bottom: 1px solid var(--hud-border);
            padding-bottom: 4px;
        }

        .data-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .data-label { color: var(--text-main); }
        .data-value { 
            color: var(--accent-cyan);
            font-weight: bold;
            font-variant-numeric: tabular-nums;
        }
        .data-value.amber { color: var(--accent-amber); }
        .data-value.rose { color: var(--accent-rose); }

        /* Custom Slider */
        input[type=range] {
            -webkit-appearance: none;
            width: 100%;
            background: transparent;
            margin-top: 8px;
        }
        input[type=range]::-webkit-slider-runnable-track {
            width: 100%;
            height: 4px;
            cursor: pointer;
            background: rgba(6, 182, 212, 0.2);
            border-radius: 2px;
        }
        input[type=range]::-webkit-slider-thumb {
            height: 14px;
            width: 8px;
            border-radius: 2px;
            background: var(--accent-cyan);
            cursor: pointer;
            -webkit-appearance: none;
            margin-top: -5px;
            box-shadow: 0 0 10px var(--accent-cyan);
        }

        /* Legend dots */
        .legend-item { display: flex; align-items: center; gap: 6px; }
        .dot { width: 8px; height: 8px; border-radius: 50%; }
        .dot.cyan { background: var(--accent-cyan); box-shadow: 0 0 8px var(--accent-cyan); }
        .dot.amber { background: var(--accent-amber); box-shadow: 0 0 8px var(--accent-amber); }
        .dot.rose { background: var(--accent-rose); box-shadow: 0 0 8px var(--accent-rose); }

    </style>
</head>
<body>

    <div id="animation-container">
        <!-- SVG Canvas (Center stage, unoccluded) -->
        <svg viewBox="-400 -400 800 800" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet">
            <defs>
                <!-- Glow Filters for Neon aesthetic -->
                <filter id="glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="6" result="blur" />
                    <feMerge>
                        <feMergeNode in="blur" />
                        <feMergeNode in="blur" />
                        <feMergeNode in="SourceGraphic" />
                    </feMerge>
                </filter>
                <filter id="glow-amber" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="8" result="blur" />
                    <feMerge>
                        <feMergeNode in="blur" />
                        <feMergeNode in="SourceGraphic" />
                    </feMerge>
                </filter>
                <filter id="glow-rose" x="-50%" y="-50%" width="200%" height="200%">
                    <feGaussianBlur stdDeviation="5" result="blur" />
                    <feMerge>
                        <feMergeNode in="blur" />
                        <feMergeNode in="SourceGraphic" />
                    </feMerge>
                </filter>
                
                <radialGradient id="sun-bg" cx="50%" cy="50%" r="50%">
                    <stop offset="60%" stop-color="#0f172a" />
                    <stop offset="100%" stop-color="#1e293b" />
                </radialGradient>
            </defs>

            <!-- Background subtle rings -->
            <circle cx="0" cy="0" r="280" fill="none" stroke="#1e293b" stroke-width="1" stroke-dasharray="4 8" />
            <circle cx="0" cy="0" r="160" fill="none" stroke="#1e293b" stroke-width="1" />

            <!-- Electromagnetic Stator Array (Outer) -->
            <g id="stator-group"></g>

            <!-- Magnetic Flux Lines (TRIZ Resource Utilization Visualization) -->
            <g id="flux-lines"></g>

            <!-- Flexible Ring Gear (Flexspline - Middle) -->
            <!-- The deformation is driven by magnetic pull, meshing at the minor axis -->
            <g id="flexspline-group">
                <!-- Inner teeth representation -->
                <path id="flexspline-teeth" fill="none" stroke="var(--accent-amber)" stroke-width="8" stroke-dasharray="4 6" opacity="0.6"/>
                <!-- Outer ring body -->
                <path id="flexspline-body" fill="none" stroke="var(--accent-amber)" stroke-width="4" filter="url(#glow-amber)"/>
            </g>

            <!-- Mesh Zone Highlights (Visual Guidance) -->
            <g id="mesh-highlights">
                <path id="mesh-top" d="M -20 -158 A 160 160 0 0 1 20 -158" fill="none" stroke="var(--accent-rose)" stroke-width="6" filter="url(#glow-rose)" stroke-linecap="round" opacity="0"/>
                <path id="mesh-bot" d="M -20 158 A 160 160 0 0 0 20 158" fill="none" stroke="var(--accent-rose)" stroke-width="6" filter="url(#glow-rose)" stroke-linecap="round" opacity="0"/>
            </g>

            <!-- Rigid Sun Gear (Inner Core) -->
            <g id="sun-gear-group">
                <circle cx="0" cy="0" r="150" fill="url(#sun-bg)" stroke="#334155" stroke-width="2"/>
                <path id="sun-gear-teeth" fill="none" stroke="var(--accent-rose)" stroke-width="6" />
                <!-- Core geometric design -->
                <circle cx="0" cy="0" r="30" fill="none" stroke="var(--accent-rose)" stroke-width="2" filter="url(#glow-rose)"/>
                <path d="M -150 0 L 150 0 M 0 -150 L 0 150" stroke="#334155" stroke-width="1" stroke-dasharray="10 10"/>
                <polygon points="0,-40 8,-10 40,0 8,10 0,40 -8,10 -40,0 -8,-10" fill="var(--accent-rose)" opacity="0.1"/>
            </g>

        </svg>

        <!-- HUD Elements -->
        <div class="hud-panel hud-top-left">
            <div class="hud-title">IFR: 电磁虚拟行星架</div>
            <div class="legend-item"><div class="dot cyan"></div>电磁定子阵列 (波发生器)</div>
            <div class="legend-item"><div class="dot amber"></div>柔性环形齿圈 (柔轮)</div>
            <div class="legend-item"><div class="dot rose"></div>刚性圆柱太阳轮 (输出)</div>
        </div>

        <div class="hud-panel hud-top-right">
            <div class="hud-title">系统状态监控</div>
            <div class="data-row">
                <span class="data-label">变形波转速 Nw:</span>
                <span class="data-value" id="val-wave-rpm">0 RPM</span>
            </div>
            <div class="data-row">
                <span class="data-label">柔轮转速 Nf:</span>
                <span class="data-value amber">0 RPM (固定)</span>
            </div>
            <div class="data-row">
                <span class="data-label">太阳轮输出 Ns:</span>
                <span class="data-value rose" id="val-sun-rpm">0 RPM</span>
            </div>
        </div>

        <div class="hud-panel hud-bottom-left">
            <div class="hud-title">交互控制 (相序换相频率)</div>
            <div class="data-row">
                <span class="data-label">磁场旋转频率:</span>
                <span class="data-value" id="val-freq">1.0 Hz</span>
            </div>
            <input type="range" id="freq-slider" min="-3" max="3" step="0.1" value="1">
            <div style="font-size: 10px; color: var(--text-main); margin-top: 4px;">*调节定子电流相序改变变形波公转方向与速度,实现无级调速及反转。</div>
        </div>

        <div class="hud-panel hud-bottom-right" style="max-width: 250px;">
            <div class="hud-title">TRIZ 创新原理解析</div>
            <div style="color: var(--text-main); line-height: 1.4;">
                <b style="color:var(--accent-cyan)">消除机械间隙:</b>无实体行星轮,由电磁径向拉力驱动柔轮形变生成虚拟行星架。<br>
                <b style="color:var(--accent-rose)">动态空间啮合:</b>长轴端受磁吸外凸,短轴端径向收缩与太阳轮无回差啮合。
            </div>
        </div>
    </div>

    <script>
        // System Constants & Geometries
        const R_SUN = 156;           // Outer radius of sun gear
        const R_FLEX_BASE = 190;     // Base radius of unstretched flexspline
        const DEFORMATION_AMP = 34;  // Radial deformation (R_FLEX_BASE - AMP = R_SUN) ensures meshing at minor axis
        const R_STATOR_INNER = 250;
        const R_STATOR_OUTER = 280;
        const STATOR_COUNT = 24;
        const GEAR_TEETH_SUN = 60;
        const GEAR_RATIO = -0.05;    // Simplified ratio: Sun gear moves opposite and slower than wave

        // State Variables
        let waveAngle = 0;           // Current angle of the magnetic wave (radians)
        let sunAngle = 0;            // Current angle of the sun gear (radians)
        let waveSpeed = 0.02;        // Base animation speed (controlled by slider)
        
        // DOM Elements
        const statorGroup = document.getElementById('stator-group');
        const fluxLinesGroup = document.getElementById('flux-lines');
        const flexBody = document.getElementById('flexspline-body');
        const flexTeeth = document.getElementById('flexspline-teeth');
        const sunGearGroup = document.getElementById('sun-gear-group');
        const sunGearTeeth = document.getElementById('sun-gear-teeth');
        const meshTop = document.getElementById('mesh-top');
        const meshBot = document.getElementById('mesh-bot');
        const slider = document.getElementById('freq-slider');

        // Initialization: Build Static Geometries
        function initGeometry() {
            // 1. Build Stators
            for (let i = 0; i < STATOR_COUNT; i++) {
                const angle = (i / STATOR_COUNT) * Math.PI * 2;
                const cx1 = Math.cos(angle) * R_STATOR_INNER;
                const cy1 = Math.sin(angle) * R_STATOR_INNER;
                const cx2 = Math.cos(angle) * R_STATOR_OUTER;
                const cy2 = Math.sin(angle) * R_STATOR_OUTER;
                
                // Stator coil block
                const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
                // Calculate corner points for the stator trapezoid
                const a1 = angle - 0.08;
                const a2 = angle + 0.08;
                const d = `M ${Math.cos(a1)*R_STATOR_INNER} ${Math.sin(a1)*R_STATOR_INNER} 
                           L ${Math.cos(a1)*R_STATOR_OUTER} ${Math.sin(a1)*R_STATOR_OUTER} 
                           A ${R_STATOR_OUTER} ${R_STATOR_OUTER} 0 0 1 ${Math.cos(a2)*R_STATOR_OUTER} ${Math.sin(a2)*R_STATOR_OUTER}
                           L ${Math.cos(a2)*R_STATOR_INNER} ${Math.sin(a2)*R_STATOR_INNER} Z`;
                
                path.setAttribute("d", d);
                path.setAttribute("fill", "var(--bg-grid)");
                path.setAttribute("stroke", "#334155");
                path.setAttribute("stroke-width", "1");
                path.id = `stator-${i}`;
                statorGroup.appendChild(path);

                // Flux line container
                const flux = document.createElementNS("http://www.w3.org/2000/svg", "path");
                flux.id = `flux-${i}`;
                flux.setAttribute("fill", "none");
                flux.setAttribute("stroke", "var(--accent-cyan)");
                flux.setAttribute("stroke-width", "2");
                flux.setAttribute("stroke-dasharray", "4 4");
                flux.style.opacity = 0;
                fluxLinesGroup.appendChild(flux);
            }

            // 2. Build Sun Gear Teeth (Static path, group rotates)
            let sunPath = "";
            for (let i = 0; i < GEAR_TEETH_SUN; i++) {
                const a1 = (i / GEAR_TEETH_SUN) * Math.PI * 2;
                const a2 = ((i + 0.4) / GEAR_TEETH_SUN) * Math.PI * 2;
                const a3 = ((i + 0.6) / GEAR_TEETH_SUN) * Math.PI * 2;
                const a4 = ((i + 1) / GEAR_TEETH_SUN) * Math.PI * 2;
                
                const rOut = R_SUN;
                const rIn = R_SUN - 8;
                
                sunPath += i === 0 ? `M ${Math.cos(a1)*rIn} ${Math.sin(a1)*rIn} ` : `L ${Math.cos(a1)*rIn} ${Math.sin(a1)*rIn} `;
                sunPath += `L ${Math.cos(a2)*rOut} ${Math.sin(a2)*rOut} `;
                sunPath += `L ${Math.cos(a3)*rOut} ${Math.sin(a3)*rOut} `;
                sunPath += `L ${Math.cos(a4)*rIn} ${Math.sin(a4)*rIn} `;
            }
            sunPath += "Z";
            sunGearTeeth.setAttribute("d", sunPath);
        }

        // Core Animation Loop
        function animate() {
            // Update Angles
            waveAngle += waveSpeed;
            sunAngle += waveSpeed * GEAR_RATIO;
            
            // Normalize angles for display
            if (waveAngle >= Math.PI * 2) waveAngle -= Math.PI * 2;
            if (waveAngle < 0) waveAngle += Math.PI * 2;

            // 1. Deform Flexspline
            // Generates an ellipse pulled OUTWARDS towards the active magnetic poles (waveAngle and waveAngle + PI)
            // Squeezed INWARDS at perpendicular axes (waveAngle + PI/2 and waveAngle - PI/2)
            let bodyPath = "";
            let teethPath = "";
            const points = 120;
            
            for (let i = 0; i <= points; i++) {
                const theta = (i / points) * Math.PI * 2;
                // Radial distance equation for elliptical deformation
                // cos(2 * (theta - waveAngle)): Max (+1) at waveAngle, Min (-1) at waveAngle + PI/2
                const r = R_FLEX_BASE + DEFORMATION_AMP * Math.cos(2 * (theta - waveAngle));
                
                const bx = Math.cos(theta) * r;
                const by = Math.sin(theta) * r;
                
                // Teeth track slightly inside
                const tx = Math.cos(theta) * (r - 6);
                const ty = Math.sin(theta) * (r - 6);

                if (i === 0) {
                    bodyPath += `M ${bx} ${by} `;
                    teethPath += `M ${tx} ${ty} `;
                } else {
                    bodyPath += `L ${bx} ${by} `;
                    teethPath += `L ${tx} ${ty} `;
                }
            }
            flexBody.setAttribute("d", bodyPath);
            flexTeeth.setAttribute("d", teethPath);

            // 2. Update Stator Magnets & Flux Lines
            for (let i = 0; i < STATOR_COUNT; i++) {
                const statorAngle = (i / STATOR_COUNT) * Math.PI * 2;
                // Calculate intensity based on alignment with the rotating wave field
                // Use power to sharpen the magnetic pole area
                let intensity = Math.pow(Math.cos(statorAngle - waveAngle), 6);
                
                const statorEl = document.getElementById(`stator-${i}`);
                const fluxEl = document.getElementById(`flux-${i}`);
                
                if (intensity > 0.1) {
                    statorEl.setAttribute("fill", "var(--accent-cyan)");
                    statorEl.setAttribute("filter", "url(#glow-cyan)");
                    
                    // Draw flux line pulling the flexspline
                    const rFlexCurrent = R_FLEX_BASE + DEFORMATION_AMP * Math.cos(2 * (statorAngle - waveAngle));
                    const d = `M ${Math.cos(statorAngle)*R_STATOR_INNER} ${Math.sin(statorAngle)*R_STATOR_INNER} 
                               L ${Math.cos(statorAngle)*(rFlexCurrent+5)} ${Math.sin(statorAngle)*(rFlexCurrent+5)}`;
                    fluxEl.setAttribute("d", d);
                    fluxEl.style.opacity = intensity;
                    
                    // Animate dashes
                    fluxEl.setAttribute("stroke-dashoffset", -(Date.now() / 20) % 8);
                } else {
                    statorEl.setAttribute("fill", "var(--bg-grid)");
                    statorEl.removeAttribute("filter");
                    fluxEl.style.opacity = 0;
                }
            }

            // 3. Rotate Sun Gear
            sunGearGroup.setAttribute("transform", `rotate(${(sunAngle * 180 / Math.PI)})`);

            // 4. Update Mesh Highlights (Minor axis of ellipse)
            const minorAxisAngle1 = waveAngle + Math.PI / 2;
            const minorAxisAngle2 = waveAngle - Math.PI / 2;
            
            // Function to generate short arc path for mesh highlight
            const getArc = (angle, r) => {
                const a1 = angle - 0.15;
                const a2 = angle + 0.15;
                return `M ${Math.cos(a1)*r} ${Math.sin(a1)*r} A ${r} ${r} 0 0 1 ${Math.cos(a2)*r} ${Math.sin(a2)*r}`;
            };
            
            meshTop.setAttribute("d", getArc(minorAxisAngle1, R_SUN + 2));
            meshBot.setAttribute("d", getArc(minorAxisAngle2, R_SUN + 2));
            
            // Show highlight only when moving, intensity based on speed
            const isMoving = Math.abs(waveSpeed) > 0.001;
            meshTop.style.opacity = isMoving ? 0.8 + 0.2*Math.sin(Date.now()/50) : 0;
            meshBot.style.opacity = isMoving ? 0.8 + 0.2*Math.sin(Date.now()/50) : 0;

            // 5. Update HUD Data
            const rpmWave = (waveSpeed * 60 * 60 / (Math.PI * 2)).toFixed(0);
            const rpmSun = (waveSpeed * GEAR_RATIO * 60 * 60 / (Math.PI * 2)).toFixed(1);
            
            document.getElementById('val-wave-rpm').textContent = rpmWave + ' RPM';
            document.getElementById('val-sun-rpm').textContent = rpmSun + ' RPM';

            requestAnimationFrame(animate);
        }

        // Interactivity
        slider.addEventListener('input', (e) => {
            const val = parseFloat(e.target.value);
            waveSpeed = val * 0.02; // Map slider -3~3 to actual radian speed
            document.getElementById('val-freq').textContent = val.toFixed(1) + ' Hz';
            
            // Visual feedback for negative/positive speed
            if(val < 0) {
                document.getElementById('val-wave-rpm').style.color = "var(--accent-rose)";
            } else {
                document.getElementById('val-wave-rpm').style.color = "var(--accent-cyan)";
            }
        });

        // Boot
        window.addEventListener('DOMContentLoaded', () => {
            initGeometry();
            requestAnimationFrame(animate);
        });

    </script>
</body>
</html>
积分规则:第一轮对话扣减8分,后续每轮扣6分