在网络中绘制斐波那契时出错
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|行匹配。
要实现您需要的属性,您需要像下面这样调整螺旋:
选择行的右边angular位置AB
我为 A
选择 1.5*M_PI [rad]
,为 B
选择 3.5*M_PI [rad]
(在未旋转的螺旋上)
按 AB
线的角度旋转螺旋线
这很简单,只需将角度添加到最终的极坐标 ->
笛卡尔坐标转换中,这将旋转整个螺旋,因此计算出的 A,B
在螺旋上的 angular 位置将与实际匹配点AB
方向
重新缩放螺旋以匹配 AB
尺寸
因此计算螺旋上 angular 点 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->
的图纸更改为您的 gfx API。就是 GDI Canvas
很难说你的螺旋线是否正确......你可以检查黄金比例矩形(就像我一样)。如果你得到正确的螺旋,那么只需将子弹 #1,#2,#3 应用到它,你应该没问题。
目前我有这个 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|行匹配。
要实现您需要的属性,您需要像下面这样调整螺旋:
选择行的右边angular位置
AB
我为
A
选择1.5*M_PI [rad]
,为B
选择3.5*M_PI [rad]
(在未旋转的螺旋上)按
AB
线的角度旋转螺旋线这很简单,只需将角度添加到最终的极坐标
->
笛卡尔坐标转换中,这将旋转整个螺旋,因此计算出的A,B
在螺旋上的 angular 位置将与实际匹配点AB
方向重新缩放螺旋以匹配
AB
尺寸因此计算螺旋上 angular 点
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->
的图纸更改为您的 gfx API。就是 GDICanvas
很难说你的螺旋线是否正确......你可以检查黄金比例矩形(就像我一样)。如果你得到正确的螺旋,那么只需将子弹 #1,#2,#3 应用到它,你应该没问题。