模拟旋转angular速度

Simulation of the rotation angular speed

我希望能够在物理学方面模拟 body 在“旋转木马”上的运动。 (向心力,离心力,angular速度)。下面是一些示例代码。

<!DOCTYPE html>
<html>
    <head>
        <script>
            
            var rotate = Math.PI / 180;
            var ballRotation = 1;
        
            function drawthis() {
    
                var friction = 0.5;

                context.setTransform(1, 0, 0, 1, 0, 0);
                context.clearRect(0, 0, cvs.width, cvs.height);
                context.translate(350, 350);
                context.rotate(rotate);
                context.beginPath();
                context.arc(1, 1, 12, 0, 2 * Math.PI, false);
                context.fill();
                context.beginPath();
                context.arc(0, 0, 150, 0, Math.PI * 2, false);
                context.lineWidth = 6;
                context.stroke();
                
                motion = ballRotation - friction;
                rotate += motion;
                requestAnimationFrame(drawthis);
}
            function init() {
                cvs = document.getElementById("canvas");
                context = cvs.getContext("2d");
                context.clearRect(0, 0, context.width, context.height);
                context.fillStyle = "#ff0000";
                requestAnimationFrame(drawthis);
}
        </script>
    </head>
    <body onload="init()">
            <canvas id="canvas" width="800" height="800"></canvas>
    </body>
</html>

I mean something like this

球转一圈table

下面是一个点在转轮上滑动的简单模拟。该点表示球的接触点。

模拟忽略了球可以滚动或有质量的事实。

球通过一个简单的摩擦模型滑动,其中摩擦是一个标量值,应用于球速度矢量与球下方点处的轮子速度之间的差异。

只涉及1个势力。它是与球到轮心的矢量相切的力减去球运动矢量再乘以摩擦系数。

有关如何计算的详细信息,请参阅函数 ball.update()

中的注释

备注

  • 如果球从车轮的死点开始,则不会发生任何事情。

  • 如果是你要的球的路径或者只是模拟球我都无法锻炼,所以我把两者都加了。

  • 球离开轮子后会复位

  • 轮子标有文字和中心十字,因此可以看到它的旋转。

const ROTATE = Math.PI / 50;
const WHEEL_SIZE = 0.6;
Math.rand = (min, max) => Math.random() * (max - min) + min;
Math.randPow = (min, max, p) => Math.random() ** p * (max - min) + min;

var friction = 0.35;
const ctx = canvas.getContext("2d");
requestAnimationFrame(mainLoop);
ctx.font = "30px arial";
ctx.textAlign = "center";
scrollBy(0, canvas.height / 2 - canvas.height / 2 * WHEEL_SIZE);

function mainLoop() {
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    wheel.update();
    ball.update(wheel, arrow);
    wheel.draw();
    path.draw();
    ball.draw();
    arrow.draw(ball);
    requestAnimationFrame(mainLoop);
}

const path = Object.assign([],{
    draw() {
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.strokeStyle = "#F00";
        ctx.lineWidth = 1;
        ctx.beginPath();
        for (const p of this) { ctx.lineTo(p.x, p.y) }
        ctx.stroke();
    },
    reset() { this.length = 0 },
    add(point) {
        this.push({x: point.x, y: point.y});
        if (this.length > 1000) {  // prevent long lines from slowing render
            this.shift()
        }
    }
});  
const arrow = {
    dx: 0,dy: 0,
    draw(ball) {
        if (this.dx || this.dy) {
            const dir = Math.atan2(this.dy, this.dx);
            
            // len is converted from frame 1/60th second to seconds
            const len = Math.hypot(this.dy, this.dx) * 60; 
            const aXx = Math.cos(dir);
            const aXy = Math.sin(dir);        
            ctx.setTransform(aXx, aXy, -aXy, aXx, ball.x, ball.y);
            ctx.beginPath();
            ctx.lineTo(0,0);
            ctx.lineTo(len, 0);
            ctx.moveTo(len - 4, -2);
            ctx.lineTo(len, 0);
            ctx.lineTo(len - 4, 2);
            ctx.strokeStyle = "#FFF";
            ctx.lineWidth = 2;     
            ctx.stroke();
        }
    }
};
const ball = {
    x: canvas.width / 2 + 4,
    y: canvas.height / 2,
    dx: 0,  // delta pos Movement vector
    dy: 0,
    update(wheel, arrow) {
        // get distance from center
        const dist = Math.hypot(wheel.x - this.x, wheel.y - this.y);
        
        // zero force arrow
        arrow.dx = 0;
        arrow.dy = 0;
         
        // check if on wheel
        if (dist < wheel.radius) {
            // get tangent vector direction
            const tangent = Math.atan2(this.y - wheel.y, this.x - wheel.x) + Math.PI * 0.5 * Math.sign(wheel.dr);
            // get tangent as vector
            // which is distance times wheel rotation in radians.
            const tx = Math.cos(tangent) * dist * wheel.dr;
            const ty = Math.sin(tangent) * dist * wheel.dr;

            // get difference between ball vector and tangent vector scaling by friction
            const fx = arrow.dx = (tx - this.dx) * friction;
            const fy = arrow.dy = (ty - this.dy) * friction;

            // Add the force vector 
            this.dx += fx;
            this.dy += fy;
        } else if (dist > wheel.radius * 1.7) { // reset ball

            // to ensure ball is off center use random polar coord
            const dir = Math.rand(0, Math.PI * 2);
            const dist = Math.randPow(1, 20, 2);  // add bias to be close to center
            this.x = canvas.width / 2 + Math.cos(dir) * dist;
            this.y = canvas.height / 2 + Math.sin(dir) * dist;
            this.dx = 0;  
            this.dy = 0;        
            path.reset();
        }
        // move the ball
        this.x += this.dx;
        this.y += this.dy;      
        path.add(ball);
    },    
    draw() {
        ctx.fillStyle = "#0004";
        ctx.setTransform(1, 0, 0, 1, this.x + 5, this.y + 5);
        ctx.beginPath();
        ctx.arc(0, 0, 10, 0, 2 * Math.PI);
        ctx.fill();    
        ctx.fillStyle = "#f00";
        ctx.setTransform(1, 0, 0, 1, this.x, this.y);
        ctx.beginPath();
        ctx.arc(0, 0, 12, 0, 2 * Math.PI);
        ctx.fill();    
        ctx.fillStyle = "#FFF8";
        ctx.setTransform(1, 0, 0, 1, this.x - 5, this.y - 5);
        ctx.beginPath();
        ctx.ellipse(0, 0, 2, 3, -Math.PI * 0.75, 0, 2 * Math.PI);
        ctx.fill();  
    },
}
const wheel = {
    x: canvas.width / 2, y: canvas.height / 2, r: 0,
    dr: ROTATE, // delta rotate
    radius: Math.min(canvas.height, canvas.width) / 2 * WHEEL_SIZE,
    text: "wheel",
    update() { this.r += this.dr },
    draw() {
        const aXx = Math.cos(this.r);
        const aXy = Math.sin(this.r);
        ctx.setTransform(aXx, aXy, -aXy, aXx, this.x, this.y);
        ctx.fillStyle = "#CCC";
        ctx.strokeStyle = "#000";
        ctx.lineWidth = 6;
        ctx.beginPath();
        ctx.arc(0, 0, this.radius, 0, 2 * Math.PI);
        ctx.stroke();
        ctx.fill();    
        ctx.strokeStyle = ctx.fillStyle = "#aaa";
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.lineTo(-20,0);
        ctx.lineTo(20,0);
        ctx.moveTo(0,-20);
        ctx.lineTo(0,20);
        ctx.stroke();
        ctx.fillText(this.text, 0, this.radius - 16);
    },    
}
<canvas id="canvas" width="300" height="300"></canvas>

向心力

向心力是指向转动轮中心的力。但是因为球在滑动,所以计算出的力不是向心力。

您可以通过“向量到中心”点“力向量”的点积缩放从球到中心的向量来计算向心力

球上的力矢量显示为白色箭头。箭头大小是力作为每秒像素的加速度。

矢量指向中心,但永远不会直接指向轮子的中心。

近似值

这个模拟是一个近似值。您需要了解微积分和微分方程才能更接近现实。

使用更复杂的模拟只有在摩擦力非常接近或为 1 时才会引人注目,然后将球固定到轮子上更容易,通过摩擦系数的倒数从中心缩放位置.