在网络中绘制斐波那契时出错

Error on drawing Fibonacci in web

目前我有这个 fiddle from Blindman67 which draws Golden spiral 图 1(见下图)。

function renderSpiral(pointA, pointB, turns){
var dx, dy, rad, i, ang, cx, cy, dist, a, c, angleStep, numberTurns, nTFPB, scale, styles;
// clear the canvas
ctx.clearRect(0, 0, ctx.canvas.width,ctx.canvas.height)

// spiral stuff
a = 1;         // the larger this number the larger the spiral
c = 1.358456;   // constant See https://en.wikipedia.org/wiki/Golden_spiral
angleStep = Math.PI/20;  // set the angular resultion for drawing
numberTurns = 6;  // total half turns drawn
nTFPB = 2;   //  numberOfTurnsForPointB is the number of turns to point
                 // B should be integer and describes the number off
                 // turns made befor reaching point B

// get the ang from pointA to B
ang = Math.atan2(pointB.y-pointA.y,pointB.x-pointA.x);
// get the distance from A to B
dist = Math.sqrt(Math.pow(pointB.y-pointA.y,2)+Math.pow(pointB.x-pointA.x,2));
if(dist === 0){
    return;  // this makes no sense so exit as nothing to draw
}
// get the spiral radius at point B
rad = Math.pow(c,ang + nTFPB * 2 * Math.PI); // spiral radius at point2

// now just need to get the correct scale so the spiral fist to the
// constraints requiered.
scale = dist / rad;


// ajust the number of turns so that the spiral fills the canvas
while(Math.pow(c,Math.PI*numberTurns)*scale < ctx.canvas.width){
    numberTurns += 2;
}

// set the scale, and origin to centre
ctx.setTransform(scale, 0, 0, scale, pointA.x, pointA.y)

// make it look nice create some line styles


// first just draw the line A-B
ctx.strokeStyle = "black";
ctx.lineWidth = 2 * ( 1 / scale); // because it is scaled invert the scale
                                  // can calculate the width requiered
// ready to draw                               
ctx.beginPath();
ctx.moveTo(0, 0)        // start at center
ctx.lineTo((pointB.x-pointA.x)*(1/scale),(pointB.y-pointA.y)*(1/scale) );  // add line
ctx.stroke();  // draw it all

// Now draw the sporal. draw it for each style 
styles.forEach( function(style) {
    ctx.strokeStyle = style.colour;
    ctx.lineWidth = style.width * ( 1 / scale); // because it is scaled invert the scale
                                                // can calculate the width requiered
    // ready to draw                               
    ctx.beginPath();
    for( i = 0; i <= Math.PI *numberTurns; i+= angleStep){
        dx = Math.cos(i);  // get the vector for angle i
        dy = Math.sin(i);
        var rad = Math.pow(c, i);  // calculate the radius
        if(i === 0) {                
            ctx.moveTo(0, 0)        // start at center
        }else{
            ctx.lineTo(dx * rad, dy * rad );  // add line
        }
    }
    ctx.stroke();  // draw it all
});
ctx.setTransform(1,0,0,1,0,0); // reset tranfrom to default;
}

我要得到的是图2(见下图)。

Q1。 我怎样才能改变我的螺旋,使线 AB 适合第一个和第二个螺钉,而 A 是螺旋的起点?

你也可以参考我之前的来更好地理解我的问题

这是一个 fiddle,我相信它可以为您提供所需的输出。

https://jsfiddle.net/8a7fdg3d/4/

主要问题是从 0 开始螺旋会导致初始直线。

从 1 开始螺旋会删除图形的这一部分,然后您只需调整黑色 |AB| 的起点行。

这是通过调整

完成的
for( i = 0; i <= Math.PI *numberTurns; i+= angleStep)

for( i = 1; i <= Math.PI *numberTurns; i+= angleStep)

改变螺旋的起点,然后改变

// ready to draw                               
ctx.beginPath();
ctx.moveTo(0, 0)        // start at center

  // ready to draw                               
  ctx.beginPath();        
  dx = Math.cos(1);  // get the vector for angle i
  dy = Math.sin(1);
  var rad = Math.pow(c, 1);  // calculate the radius
  ctx.moveTo(dx * rad, dy * rad )        // start at center

让你的|AB|行匹配。

要实现您需要的属性,您需要像下面这样调整螺旋:

  1. 选择行的右边angular位置AB

    我为 A 选择 1.5*M_PI [rad],为 B 选择 3.5*M_PI [rad](在未旋转的螺旋上)

  2. AB 线的角度旋转螺旋线

    这很简单,只需将角度添加到最终的极坐标 -> 笛卡尔坐标转换中,这将旋转整个螺旋,因此计算出的 A,B 在螺旋上的 angular 位置将与实际匹配点AB方向

  3. 重新缩放螺旋以匹配 AB 尺寸

    因此计算螺旋上 angular 点 AB 位置的半径,然后计算 scale=|AB|-(r(b)-r(a))。现在只需将其乘以计算每个渲染点的半径 ...

我玩了一下黄金比例,稍微螺旋了一下,这是结果

  • Yellow螺旋线近似为四分之一圆弧
  • Aqua是黄金螺旋

如你所见,它们不太匹配(这是 ratio*0.75 使它们更相似,但它应该只是 ratio)要么我在某处有错误,要么来源螺旋的偏移(但看起来不像)或者我有错误的比率常数 ratio = 0.3063489 或者黄金矩形引入了比我教的更高的浮动圆误差或者我遗漏了一些愚蠢的东西。

这里是 C++ 源代码,因此您可以提取所需的内容:

//---------------------------------------------------------------------------
#include <Math.h>
//---------------------------------------------------------------------------
bool _redraw=false;                     // just signal to repaint window after spiral change
double Ax,Ay,Bx,By;                     // mouse eddited points
double gr=0.75;                         // golden spiral ratio scale should be 1 !!!

void GoldenSpiral_draw(TCanvas *can)    // GDI draw
    {
    double a0,a,b,l,x,y,r=5,ratio;

    // draw AB line
    can->Pen->Color=clWhite;
    can->MoveTo(Ax,Ay);
    can->LineTo(Bx,By);
    // draw A,B points
    can->Pen->Color=clBlue;
    can->Brush->Color=clAqua;
    can->Ellipse(Ax-r,Ay-r,Ax+r,Ay+r);
    can->Ellipse(Bx-r,By-r,Bx+r,By+r);
    // draw golden ratio rectangles
    can->Pen->Color=clDkGray;
    can->Brush->Style=bsClear;
    ratio=1.6180339887;
    a=5.0; b=a/ratio; x=Ax; y=Ay;
    y-=0.5*b; x-=0.5*b; // bias to match real golden spiral
    can->Rectangle(x,y,x+a,y+b); y-=a;
    for (int i=0;i<5;i++)
        {
        can->Rectangle(x,y,x+a,y+a);             b=a; a*=ratio; x-=a;
        can->Rectangle(x,y,x+a,y+a); y+=a;       b=a; a*=ratio;
        can->Rectangle(x,y,x+a,y+a); x+=a; y-=b; b=a; a*=ratio;
        can->Rectangle(x,y,x+a,y+a); x-=b;       b=a; a*=ratio; y-=a;
        }
    // draw circle arc approximation of golden spiral
    ratio=1.6180339887;
    a=5.0; b=a/ratio; x=Ax; y=Ay; r=10000; y-=a;
    y-=0.5*b; x-=0.5*b; // bias to match real golden spiral
    can->Pen->Color=clYellow;
    for (int i=0;i<5;i++)
        {
        can->Arc(x-a,y,x+a,y+a+a,+r, 0, 0,-r);             b=a; a*=ratio; x-=a;
        can->Arc(x,y,x+a+a,y+a+a, 0,-r,-r, 0); y+=a;       b=a; a*=ratio;
        can->Arc(x,y-a,x+a+a,y+a,-r, 0, 0,+r); x+=a; y-=b; b=a; a*=ratio;
        can->Arc(x-a,y-a,x+a,y+a, 0,+r,+r, 0); x-=b;       b=a; a*=ratio; y-=a;
        }
    can->Brush->Style=bsSolid;

    // compute golden spiral parameters
    ratio=0.3063489*gr;
    x=Bx-Ax;
    y=By-Ay;
    l=sqrt(x*x+y*y);    // l=|AB|
    if (l<1.0) return;  // prevent domain errors
    a0=atan2(-y,x);     // a=atan2(AB)
    a0+=0.5*M_PI;       // offset so direction of AB matches the normal
    a=1.5*M_PI; r=a*exp(ratio*a); b=r;
    a+=2.0*M_PI; r=a*exp(ratio*a); b=r-b;
    b=l/r;              // b=zoom of spiral to match AB screw distance
    // draw golden spiral
    can->Pen->Color=clAqua;
    can->MoveTo(Ax,Ay);
    for (a=0.0;a<100.0*M_PI;a+=0.001)
        {
        r=a*b*exp(ratio*a); if (r>512.0) break;
        x=Ax+r*cos(a0+a);
        y=Ay-r*sin(a0+a);
        can->LineTo(x,y);
        }
    }
//---------------------------------------------------------------------------
  • 可以忽略黄金比例矩形和圆弧...
  • 将基于 can-> 的图纸更改为您的 gfx API。就是 GDI Canvas

很难说你的螺旋线是否正确......你可以检查黄金比例矩形(就像我一样)。如果你得到正确的螺旋,那么只需将子弹 #1,#2,#3 应用到它,你应该没问题。