You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

电场矢量可视化求助:合成矢量箭头方向异常排查

电场合成矢量箭头方向问题排查

我已调整过电场可视化项目,目前包含三个canvas:canvas1(绿色电荷)、canvas2(蓝色电荷)、canvas3(合力),核心问题是部分箭头的方向表现不符合预期。以下是计算合成矢量方向的关键代码及完整函数:

合成矢量方向计算代码片段

let angleBetween;
let anguloResultante;

let alpha;
let cosAlpha;
let sinAlpha;
let eR;


//if the 2 charges are positve do all of this
if(q1Value && q2Value > 0){
    //rotation of the canvas(electric arrows) 
    canvas1.style.transform = `rotate(${positivo1}deg)`;
    canvas2.style.transform = `rotate(${positivo2}deg)`;

    //Here im getting the angleBetween
    if(positivo1 > positivo2){
        angleBetween = positivo1 - positivo2;
        if(angleBetween > 180){
            angleBetween = 360 - angleBetween ;
        }

        alpha = 180 - angleBetween;
        cosAlpha = Math.cos(alpha*Math.PI/180);
        sinAlpha = Math.sin(alpha*Math.PI/180);
        eR = Math.sqrt(Math.pow(e1,2) + Math.pow(e2,2) - 2*e1*e2*cosAlpha)
        anguloResultante = (Math.asin(sinAlpha/eR)*e1) * 180 / Math.PI;

        if(positivo1 > 0 && positivo1 < 90){
            canvas3.style.transform = `rotate(${anguloResultante}deg)`;
        }
        if(positivo1 > 90 && positivo1 < 180){
            canvas3.style.transform = `rotate(${anguloResultante+90}deg)`;
        }
        if(positivo1 > 180 && positivo1 < 270){
            canvas3.style.transform = `rotate(${anguloResultante+180}deg)`;
        }
        if(positivo1 > 270){
            canvas3.style.transform = `rotate(${anguloResultante+270}deg)`;
        }
    }
    
    //Here im getting the angleBetween
    if(positivo2 > positivo1){
        angleBetween = positivo2 - positivo1;
        if(angleBetween > 180){
            angleBetween = 360 - angleBetween ;
        }


        alpha = 180 - angleBetween;
        cosAlpha = Math.cos(alpha*Math.PI/180);
        sinAlpha = Math.sin(alpha*Math.PI/180);
        eR = Math.sqrt(Math.pow(e1,2) + Math.pow(e2,2) - 2*e1*e2*cosAlpha)
        anguloResultante = (Math.asin(sinAlpha/eR)*e2) * 180 / Math.PI;

        if(positivo2 > 0 && positivo2 < 90){
            canvas3.style.transform = `rotate(${anguloResultante}deg)`;
        }
        if(positivo2 > 90 && positivo2 < 180){
            canvas3.style.transform = `rotate(${anguloResultante+90}deg)`;
        }
        if(positivo2 > 180 && positivo2 < 270){
            canvas3.style.transform = `rotate(${anguloResultante+180}deg)`;
        }
        if(positivo2 > 270){
            canvas3.style.transform = `rotate(${anguloResultante+270}deg)`;
        }
    }

完整事件处理函数

document.addEventListener('mousemove', ()=> {
        
    let distanceX = getDistanceBetweenElements(canvas1, x)/100;
    let distanceY = getDistanceBetweenElements(canvas1, y)/100;
    
    let e1 = (k*q1)/Math.pow(distanceX,2);
    let e2 = (k*q2)/Math.pow(distanceY,2);

    let Q1x = getPositionAtCenter(document.getElementById('x')).x;
    let Q1y = getPositionAtCenter(document.getElementById('x')).y;
    let Q2x = getPositionAtCenter(document.getElementById('y')).x;
    let Q2y = getPositionAtCenter(document.getElementById('y')).y;
    
    const rekt = canvas1.getBoundingClientRect();
    const anchorX= rekt.left + rekt.width / 2;
    const anchorY= rekt.top + rekt.height / 2; 
    
    let angleDeg1 = angle(Q1x, Q1y, anchorX, anchorY);
    let angleDeg2 = angle(Q2x, Q2y, anchorX, anchorY);
        
    let positivo1 = angleDeg1+180;
    let negativo1 = angleDeg1;

    let positivo2 = angleDeg2 + 180;
    let negativo2 = angleDeg2;
    
    let angleBetween;
    let anguloResultante;

    let alpha;
    let cosAlpha;
    let sinAlpha;
    let eR;
    
    if(q1Value && q2Value > 0){
        canvas1.style.transform = `rotate(${positivo1}deg)`;
        canvas2.style.transform = `rotate(${positivo2}deg)`;

        if(positivo1 > positivo2){
            angleBetween = positivo1 - positivo2;
            if(angleBetween > 180){
                angleBetween = 360 - angleBetween ;
            }

            alpha = 180 - angleBetween;
            cosAlpha = Math.cos(alpha*Math.PI/180);
            sinAlpha = Math.sin(alpha*Math.PI/180);
            eR = Math.sqrt(Math.pow(e1,2) + Math.pow(e2,2) - 2*e1*e2*cosAlpha)
            anguloResultante = (Math.asin(sinAlpha/eR)*e1) * 180 / Math.PI;

            if(positivo1 > 0 && positivo1 < 90){
                canvas3.style.transform = `rotate(${anguloResultante}deg)`;
            }
            if(positivo1 > 90 && positivo1 < 180){
                canvas3.style.transform = `rotate(${anguloResultante+90}deg)`;
            }
            if(positivo1 > 180 && positivo1 < 270){
                canvas3.style.transform = `rotate(${anguloResultante+180}deg)`;
            }
            if(positivo1 > 270){
                canvas3.style.transform = `rotate(${anguloResultante+270}deg)`;
            }
        }
        
        if(positivo2 > positivo1){
            angleBetween = positivo2 - positivo1;
            if(angleBetween > 180){
                angleBetween = 360 - angleBetween ;
            }

            alpha = 180 - angleBetween;
            cosAlpha = Math.cos(alpha*Math.PI/180);
            sinAlpha = Math.sin(alpha*Math.PI/180);
            eR = Math.sqrt(Math.pow(e1,2) + Math.pow(e2,2) - 2*e1*e2*cosAlpha)
            anguloResultante = (Math.asin(sinAlpha/eR)*e2) * 180 / Math.PI;

            if(positivo2 > 0 && positivo2 < 90){
                canvas3.style.transform = `rotate(${anguloResultante}deg)`;
            }
            if(positivo2 > 90 && positivo2 < 180){
                canvas3.style.transform = `rotate(${anguloResultante+90}deg)`;
            }
            if(positivo2 > 180 && positivo2 < 270){
                canvas3.style.transform = `rotate(${anguloResultante+180}deg)`;
            }
            if(positivo2 > 270){
                canvas3.style.transform = `rotate(${anguloResultante+270}deg)`;
            }
        }


    }
    if(q1Value && q2Value < 0){
        canvas1.style.transform = `rotate(${negativo1}deg)`;
        canvas2.style.transform = `rotate(${negativo2}deg)`;
    }
    if(q1Value > 0 && q2Value < 0){
        canvas1.style.transform = `rotate(${positivo1}deg)`;
        canvas2.style.transform = `rotate(${negativo2}deg)`;
    }
    if(q1Value < 0 && q2Value > 0){
        canvas1.style.transform = `rotate(${negativo1}deg)`;
        canvas2.style.transform = `rotate(${positivo2}deg)`;
    }
    
});



btnSubmit.addEventListener('click', () =>{
    q1Value = document.getElementById('valor1').value;
    q1Potencia = document.getElementById('potencia1').value;
    q1Prefijo = document.getElementById('prefijo1').value;

    q2Value = document.getElementById('valor2').value;
    q2Potencia = document.getElementById('potencia2').value;
    q2Prefijo = document.getElementById('prefijo2').value;

    if(q1Value > 0 || q1Value < 0){
        if(q1Prefijo == '1'){
            q1 = q1Value * Math.pow(10, q1Potencia);
        }else if(q1Prefijo == '2'){
            q1 = (q1Value * Math.pow(10, q1Potencia)) / 1e+6;
        }else if(q1Prefijo == '3'){
            q1 = (q1Value * Math.pow(10, q1Potencia)) / 1e+12;
        }else if(q1Prefijo == '4'){
            q1 = (q1Value * Math.pow(10, q1Potencia)) / 1e+9;
        }
    }

    if(q2Value > 0 || q2Value < 0){
        if(q2Prefijo == '1'){
            q2 = q2Value * Math.pow(10, q2Potencia);
        }else if(q2Prefijo == '2'){
            q2 = (q2Value * Math.pow(10, q2Potencia)) / 1e+6;
        }else if(q2Prefijo == '3'){
            q2 = (q2Value * Math.pow(10, q2Potencia)) / 1e+12;
        }else if(q2Prefijo == '4'){
            q2 = (q2Value * Math.pow(10, q2Potencia)) / 1e+9;
        }
    }


    //makes q1 and q2 dragabbles
    const dragX = (e) =>{
        x.style.left = e.pageX + 'px';
        x.style.top = e.pageY + 'px';  
    }

    x.addEventListener('mousedown', () => {
        window.addEventListener("mousemove", dragX);
    });
        
    window.addEventListener("mouseup", () => {
        window.removeEventListener("mousemove", dragX);
    });

    const dragY = (e) =>{
        y.style.left = e.pageX + 'px';
        y.style.top = e.pageY + 'px';  
    }

    y.addEventListener('mousedown', () => {
        window.addEventListener("mousemove", dragY);
    });
        
    window.addEventListener("mouseup", () => {
        window.removeEventListener("mousemove", dragY);
    });

    //Accion createArrow
    for(let i = 0; i < 104; i++) {
        createArrow();
    }


});

关键问题分析及修复建议

  • Math.asin的取值范围限制:Math.asin()的返回值范围是[-π/2, π/2],仅能表示第一、四象限的角度,无法覆盖所有方向,这会导致计算出的anguloResultante存在方向歧义,进而错误设置canvas3的旋转角度。建议改用矢量分量合成法计算合力方向:
    // 计算两个电场的x、y分量(基于positivo1/positivo2的弧度值)
    const rad1 = positivo1 * Math.PI / 180;
    const rad2 = positivo2 * Math.PI / 180;
    const e1x = e1 * Math.cos(rad1);
    const e1y = e1 * Math.sin(rad1);
    const e2x = e2 * Math.cos(rad2);
    const e2y = e2 * Math.sin(rad2);
    
    // 合成合力的分量
    const eRx = e1x + e2x;
    const eRy = e1y + e2y;
    
    // 计算合力的角度(使用Math.atan2覆盖所有象限)
    const anguloResultanteRad = Math.atan2(eRy, eRx);
    const anguloResultanteDeg = anguloResultanteRad * 180 / Math.PI;
    
    // 直接设置canvas3的旋转角度,无需分象限加偏移
    canvas3.style.transform = `rotate(${anguloResultanteDeg}deg)`;
    
  • 分象限偏移逻辑错误:原代码中根据positivo1/positivo2的区间手动添加90/180/270度偏移的逻辑完全依赖角度比较,没有考虑矢量的实际方向,容易出现错误偏移。使用矢量分量合成后,无需手动分象限调整,Math.atan2会自动返回正确的全象限角度。
  • 角度计算冗余:原代码中计算angleBetween和alpha的步骤可以简化,直接使用矢量分量法更直观且不易出错。

内容的提问来源于stack exchange,提问作者Nashe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 09:15:35