且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

HTML5 Canvas Fibonacci螺旋

更新时间:2022-04-26 21:59:16

在你的函数 drawSpir​​al 中,你在第四行:

In your function drawSpiral, in the fourth line you do:

b = Math.sqrt(((c.x - b.x) * (c.x - b.x)) + ((c.y - b.y) * (c.y - b.y)));

所以, b 现在应该是一个标量,但是你试着在下一行中访问 bx ,这不再存在了:

So, b should be a scalar now, but then you try to access b.x and b.y in the next line, which don't exist anymore:

d = 1 / Math.sqrt(((c.x - b.x) * (c.x - b.x)) + ((c.y - b.y) * (c.y - b.y)));

这种情况再次发生在6中的 c -7行。这可能就是您的代码无法正常工作的原因。

This happens again with c in the 6-7th lines. This might be why your code isn't working.

我尝试使用我自己的代码。我完全不确定数学,但是我根据你在@ Blindman67的答案中使用的一些鼠标跟踪代码将我的算法基于你在问题上发布的片段。

I tried to make it work with my own code. I'm not sure at all about the math, but I based my algorithm on the snippet you posted on the question, using some of the mouse-tracking code from @Blindman67's answer.

这是重要的部分。它返回一个带有螺旋点的数组(我使用另一个函数来实际渲染它们)。我们的想法是使用您提供的连续斐波纳契函数绘制螺旋线。它从A点开始并强制缩放,使得一圈的半径是A点和B点之间的距离。它还增加了一个角度偏移,因此一圈的角度是A点和B点之间的角度。

This is the important part. It returns an array with the spiral's points (I use another function to actually render them). The idea is to draw a spiral using the continuous-fibonacci function you provided. It starts at point A and forces the scaling so that the radius at one turn is the distance between point A and point B. It also adds an angle offset so the angle at one turn is the angle between point A and B.

编辑以发表评论:我将 for 循环更改为循环继续绘制,直到螺旋达到最大半径。我还更改了一些名称并添加了注释以尝试使算法更清晰。

Edited to address comment: I changed the for loop to a while loop that continues drawing until the spiral reaches a maximum radius. I also changed some names and added comments to try to make the algorithm clearer.

var getSpiral = function(pA, pB, maxRadius){
    // 1 step = 1/4 turn or 90º    
    var precision = 50; // Lines to draw in each 1/4 turn
    var stepB = 4; // Steps to get to point B

    var angleToPointB = getAngle(pA,pB); // Angle between pA and pB
    var distToPointB = getDistance(pA,pB); // Distance between pA and pB

    var fibonacci = new FibonacciGenerator();

    // Find scale so that the last point of the curve is at distance to pB
    var radiusB = fibonacci.getNumber(stepB);
    var scale = distToPointB / radiusB;

    // Find angle offset so that last point of the curve is at angle to pB
    var angleOffset = angleToPointB - stepB * Math.PI / 2;

    var path = [];    
    var i, step , radius, angle;

    // Start at the center
    i = step = radius = angle = 0;

    // Continue drawing until reaching maximum radius
    while (radius * scale <= maxRadius){

        path.push({
            x: scale * radius * Math.cos(angle + angleOffset) + pA.x,
            y: scale * radius * Math.sin(angle + angleOffset) + pA.y
        });

        i++; // Next point
        step = i / precision; // 1/4 turns at point    
        radius = fibonacci.getNumber(step); // Radius of Fibonacci spiral
        angle = step * Math.PI / 2; // Radians at point
    }    
    return path;
};



Fibonacci序列



要生成的代码连续的斐波那契数字基本上是你的,但我改了一些名字来帮助我理解它。我还添加了一个生成器函数,因此它可以处理任何数字:

Fibonacci sequence

The code to generate the continuous fibonacci numbers is basically yours, but I changed some names to help me understand it. I also added a generator function so it could work up to any number:

var FibonacciGenerator = function(){
    var thisFibonacci = this;

    // Start with 0 1 2... instead of the real sequence 0 1 1 2...
    thisFibonacci.array = [0, 1, 2];

    thisFibonacci.getDiscrete = function(n){

        // If the Fibonacci number is not in the array, calculate it
        while (n >= thisFibonacci.array.length){
            var length = thisFibonacci.array.length;
            var nextFibonacci = thisFibonacci.array[length - 1] + thisFibonacci.array[length - 2];
            thisFibonacci.array.push(nextFibonacci);
        }

        return thisFibonacci.array[n];
    };

    thisFibonacci.getNumber = function(n){
        var floor = Math.floor(n);
        var ceil = Math.ceil(n);

        if (Math.floor(n) == n){
            return thisFibonacci.getDiscrete(n);
        }

        var a = Math.pow(n - floor, 1.15);

        var fibFloor = thisFibonacci.getDiscrete(floor);
        var fibCeil = thisFibonacci.getDiscrete(ceil);

        return fibFloor + a * (fibCeil - fibFloor);
    };

    return thisFibonacci;
};



点之间的距离和角度



To使代码更清晰,我使用了几个辅助函数来处理2D点:

Distance and angle between points

To make code clearer, I used a couple helper functions to work with 2D points:

var getDistance = function(p1, p2){
    return Math.sqrt(Math.pow(p1.x-p2.x, 2) + Math.pow(p1.y-p2.y, 2));
};

var getAngle = function(p1, p2){
    return Math.atan2(p2.y-p1.y, p2.x-p1.x);
};

整件事: JSFiddle 更新到地址 - 评论JSFiddle