有趣的小问题 :)
如果您仔细查看图表,序列就会清楚地显示出来:
![spiral diagram](https://istack.dev59.com/eIzQh.gif)
可能有许多解决方案可以绘制这些图形,也许更加简洁,但这是我的方法:
您知道斜边等于当前段数加1的平方根,并且三角形的对边始终为1。
此外,您知道角度的正弦(Math.sin)等于对边除以斜边。从旧的记忆法 SOH(正弦、对边、斜边),CAH-TOA 中可以得到。
Math.sin(angle) = opp/hyp
你已知一个角度的正弦值和两条边的长度,但还不知道这个角度本身,此时可以使用反正弦函数(Math.asin)来求解。
angle = Math.asin(opp/hyp)
现在你知道了每个线段的角度,并且注意到它随着每条线递增。
既然你有了一个角度和半径(斜边),你可以使用极坐标转换为直角坐标公式,将这个角度和半径对转换为x,y坐标对。
x = Math.cos(angle) * radius;
y = Math.sin(angle) * radius;
由于您要求使用 actionscript 解决问题,Point 类已经通过 polar() 方法为您提供了此功能。您可以传递半径和角度,它将在 Point 对象中返回 x 和 y 值。(点击此处查看文档)
以下是一个小片段,用于绘制螺旋线。您可以通过在 Y 轴上移动鼠标来控制线段的数量。
var sw:Number = stage.stageWidth,sh:Number = stage.stageHeight;
this.addEventListener(Event.ENTER_FRAME,update);
function update(event:Event):void{
drawTheodorus(144*(mouseY/sh),sw*.5,sh*.5,20);
}
function drawTheodorus(segments:int,x:Number,y:Number,scale:Number):void{
graphics.clear();
var points:Array = getTheodorus(segments,scale);
for(var i:int = 0 ; i < segments; i++){
points[i].offset(x,y);
graphics.lineStyle(1,0x990000,1.05-(.05+i/segments));
graphics.moveTo(x,y);
graphics.lineTo(points[i].x,points[i].y);
graphics.lineStyle(1+(i*(i/segments)*.05),0,(.05+i/segments));
if(i > 0) graphics.lineTo(points[i-1].x,points[i-1].y);
}
}
function getTheodorus(segments:int = 1,scale:Number = 10):Array{
var result = [];
var radius:Number = 0;
var angle:Number = 0;
for(var i:int = 0 ; i < segments ; i++){
radius = Math.sqrt(i+1);
angle += Math.asin(1/radius);
result[i] = Point.polar(radius*scale,angle);
}
return result;
}
这段代码可以用更少的行数编写,但我想将其拆分为两个函数:
一个仅处理计算数字的函数,另一个则处理绘制线条。
以下是一些屏幕截图:
![spiral 3](https://istack.dev59.com/ARlvR.webp)
为了好玩,在这里添加了使用ProcessingJS的版本
(点击
这里查看)。
运行速度有点慢,建议在Chromium / Chrome中运行。
现在你可以在此处运行此代码(将鼠标上下移动):
var totalSegments = 850,hw = 320,hh = 240,segments;
var len = 10;
points = [];
function setup(){
createCanvas(640,480);
smooth();
colorMode(HSB,255,100,100);
stroke(0);
noFill();
}
function draw(){
background(0);
translate(hw,hh);
segments = floor(totalSegments*(mouseY/height));
points = getTheodorus(segments,len);
for(var i = 0 ; i < segments ; i++){
strokeWeight(1);
stroke(255-((i/segments) * 255),100,100,260-((i/segments) * 255));
line(0,0,points[i].x,points[i].y);
strokeWeight(2);
stroke(0,0,100,(20+i/segments));
if(i > 0) line(points[i].x,points[i].y,points[i-1].x,points[i-1].y);
}
}
function getTheodorus(segments,len){
var result = [];
var radius = 0;
var angle = 0;
for(var i = 0 ; i < segments ; i++){
radius = sqrt(i+1);
angle += asin(1/radius);
result[i] = new p5.Vector(cos(angle) * radius*len,sin(angle) * radius*len);
}
return result;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.4.4/p5.min.js"></script>