【问题标题】:Error on drawing Fibonacci in web在网络中绘制斐波那契时出错
【发布时间】:2016-01-21 08:44:22
【问题描述】:

目前我有来自 Blindman67 的 fiddle,它绘制了 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(见下图)。

第一季度。 我怎样才能改变我的螺旋线,使线AB 将适合第一个和第二个螺丝之间,而A 是螺旋的开始?

您也可以参考我之前的question 以更好地了解我的问题。

【问题讨论】:

  • @Spektre 如果您将图 1 和图 2 进行比较,那么您可以找出问题所在。
  • A 和 B 是创建螺旋所依赖的线的点
  • 这并不能解释任何事情。 1.左图与您的输出不对应。 2. 你想要有|AB| 距离的螺旋螺丝,这很明显,但是|AB| 是什么?它不是恒定的(至少不是在图像中,因为您只显示 2 个螺钉,所以无论如何我可能是错的,您应该指定这个......)那么它到底是什么?它如何取决于从螺旋开始的角度或距离等......如果没有这个,你的问题就无法回答
  • @Spektre 抱歉不清楚。 A点也将是螺旋的起点。基本上我唯一的问题是如何使螺旋图从点 A 开始,这样线 |AB|只会在螺旋处相交两次。
  • 螺旋和|AB| 是否相互关联?例如AB 是否正常在A 处螺旋?什么是螺旋方程?如果你改变AB 的大小,螺旋的形状会改变还是只是旋转?

标签: javascript math geometry 2d computational-geometry


【解决方案1】:

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

  1. 选择直线AB的右角位置

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

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

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

  3. 重新调整螺旋线以匹配AB 大小

    因此计算螺旋上角点A,B 位置的半径,然后计算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-&gt; 的图纸更改为您的gfx API。这只是 GDI Canvas

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

【讨论】:

  • 经过一番思考,黄色和浅绿色螺旋之间的不一致很可能是由于浮点舍入错误。随着我的黄金矩形从小尺寸变大,仅使用 11 位比率常数,错误越来越多地传播……可见差异是在 7 次递归之后。所以可能收缩/切割会更好......
【解决方案2】:

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

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|对线。

【讨论】:

  • 移动时出现过渡问题
猜你喜欢
  • 1970-01-01
  • 2020-01-10
  • 2013-03-04
  • 1970-01-01
  • 1970-01-01
  • 2012-12-29
  • 1970-01-01
  • 2017-04-03
  • 1970-01-01
相关资源
最近更新 更多