Interesting little problem :)
If you look at the chart closer, the sequence is clearly indicated:

There are probably many solutions for drawing them, perhaps more elegantly, but here are mine:
You know that the hypotenuse is the square root of the current segment count + 1 and the opposite side of the triangle is always 1.
You also know that the sine (Math.sin) of the angle is equal to the opposite side divided by the hypotenuse. from the old mennonic SOH (sinus, opposite, hypotenuse) - CAH-TOA.
Math.sin(angle) = opp/hyp
You know the sine value for an angle, you know two sides, but you don’t know the angle yet, but you can use the arc sine function (Math.asin) to do this
angle = Math.asin(opp/hyp)
Now you know the angle for each segment and notice that it increases with each row.
Now that you have the angle and radius (hypotenuse), you can use for the polar to Cartesian formula to convert this angle, the radius of the pair with the pair x, y .
x = Math.cos(angle) * radius; y = Math.sin(angle) * radius;
Since you requested a solution for ActionScript, the Point class already provides this function for you using the polar () method. You pass it the radius and angle, and it returns your x and y in the Point object.
Here is a small fragment that depicts a spiral. You can control the number of segments by moving the mouse along the y axis.
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); } //draw points 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);//move to centre graphics.lineTo(points[i].x,points[i].y);//draw hypotenuse graphics.lineStyle(1+(i*(i/segments)*.05),0,(.05+i/segments)); if(i > 0) graphics.lineTo(points[i-1].x,points[i-1].y);//draw opposite } } //calculate points 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);//sin(angle) = opposite/hypothenuse => used asin to get angle result[i] = Point.polar(radius*scale,angle);//same as new Point(Math.cos(angle)*radius.scale,Math.sin(angle)*radius.scale) } return result; }
It could be written in smaller lines, but I wanted to break it down into two functions: one that deals only with calculating numbers, and the other with drawing lines.
Here are some screenshots:



For fun, I added this version using ProcessingJS here . The launch is a bit slow, so I would recommend Chromium / Chrome for this.
Now you can run this code right here (move the mouse up and down):
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(); //println("move cursor vertically"); } 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(1+(i*(i/segments)*.01)); 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>