AJB - 1 year ago 112

jQuery Question

Currently I'm looking at this code but can't figure out what's wrong.

`function fibNumbers() {`

return [0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

}

function continiusFib(a) {

var b = fibNumbers(),

c = Math.floor(a),

d = Math.ceil(a);

if (d >= b.length)

return null;

a = Math.pow(a - c, 1.15);

return b[c] + (b[d] - b[c]) * a

}

function drawSpiral(pointA, pointB) {

var b = pointA;

var c = pointB;

ctx.translate(b.x, b.y);

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

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

c = Math.acos(c.x - b.x);

0 > Math.asin(c.y - b.y) && (c = 2 * Math.PI - c);

ctx.rotate(c);

ctx.scale(b / 5, b / 5);

var d = Math.PI / 100;

ctx.moveTo(0, 0);

for (var e = 0; e < 50 * (fibNumbers().length - 1) ; e++) {

var f = e * d, g = continiusFib(e / 50),

h = Math.cos(f) * g,

f = Math.sin(f) * g;

ctx.lineTo(h, f);

}

ctx.scale(5 / b, 5 / b);

ctx.rotate(-c);

//ctx.stroke();

}

What I want is to draw Fibonacci Spiral which is different from Golden Spiral

I also have this question for other reference.

Answer Source

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)));
```

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)));
```

This happens again with `c`

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

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.

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.

**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;
};
```

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 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);
};
```

The whole thing: JSFiddle and Updated-to-address-comment JSFiddle