Algorithm for solving points of uniformly distributed / even discontinuities?

Firstly, just to get a visual idea of ​​what I need, here is the closest result (but not quite what I need) that I found:

enter image description here

Here's the whole website link: http://www.mathematische-basteleien.de/spiral.htm

BUT, this does not exactly solve the problem I'm working for. I would like to save an array of points of a very specific spiral algorithm.

  • Points are distributed evenly
  • 360 degree cycles have an even gap.

If I am not mistaken, the first two points:

  • point [0] = new point (0,0);
  • point [1] = new point (1,0);

But where to go from here?

The only arguments I would like to provide are:

  • the number of points I want to solve (array length).
  • the distance between each point (pixel spacing).
  • distance between cycles.

It seems to me that I have to calculate the "spiral circle" (if there is such a term) in order to build evenly distributed points in a spiral.

Is it possible to reliably use 2 * PI * radius for this calculation?

If this has been done before, please show a sample code!

+7
math algorithm actionscript-3 pseudocode spiral
source share
2 answers

Interesting little problem :)

If you look at the chart closer, the sequence is clearly indicated:

spiral diagram

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:

spiral 1

spiral 2

spiral 3

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> 
+18
source share

George answered perfectly! I have been looking for a solution for a long time.

Here is the same code adjusted for PHP if it helps someone. I use a script to draw points (= cities) for a map with X, Y coordinates. X starts on the left, Y starts on the bottom left.

 <? /** * Initialize variables **/ // MAXIMUM width & height of canvas (X: 0->400, Y: 0->400) $width = 400; // For loop iteration amount, adjust this manually $segments = 10000; // Scale for radius $radiusScale = 2; // Draw dot (eg a city in a game) for every N'th drawn point $cityForEveryNthDot = 14; /** * Private variables **/ $radius = 0; $angle = 0; $centerPoint = $width/2; /** * Container print **/ print("<div style=\"width: ${width}px; height: ${width}px; background: #cdcdcd; z-index: 1; position: absolute; left: 0; top: 0;\"></div>"); /** * Looper **/ for($i=0;$i<$segments;$i++) { // calculate radius and angle $radius = sqrt($i+1) * $radiusScale; $angle += asin(1/$radius); // skip this point, if city won't be created here if($i % $cityForEveryNthDot != 0) { continue; } // calculate X & Y (from top left) for this point $x = cos($angle) * $radius; $y = sin($angle) * $radius; // print dot print("<div style=\"width: 1px; height: 1px; background: black; position: absolute; z-index: 2; left: " . round($x+$centerPoint) . "; top: " . round($y+$centerPoint) . ";\"></div>"); // calculate rounded X & Y (from bottom left) $xNew = round($x+$centerPoint); $yNew = round($width - ($y+$centerPoint)); // just some internal checks if($xNew > 1 && $yNew > 1 && $xNew < $width && $yNew < $width) { /** * do something (eg store to database). Use xNew and yNew **/ } } 
+3
source share

All Articles