Polyspiral

From Rosetta Code
Revision as of 13:21, 13 July 2016 by rosettacode>Fwend (formatting of task description)
Polyspiral is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

A Polyspiral is a spiral made of multiple line segments, whereby each segment is larger (or smaller) than the previous one by a given amount. Each segment also changes direction at a given angle.

The task: animate a series of polyspirals, by drawing a complete spiral then incrementing the angle, and (after clearing the background) drawing the next, and so on. Every spiral will be a frame of the animation. The animation may stop as it goes full circle or continue indefinitely. The given input values may be varied.

    set incr to 0.0

    // animation loop
    WHILE true 

        incr = (incr + 0.05) MOD 360
        x = width / 2
        y = height / 2
        length = 5
        angle = incr

        // spiral loop
        FOR 1 TO 150
            drawline
            change direction by angle
            length = length + 3
            angle = (angle + incr) MOD 360
        ENDFOR
    

If animation is not practical in your programming environment, you may show a single frame instead.

J

Translation of: java

<lang J>require 'gl2 trig media/imagekit' coinsert 'jgl2'

DT =: %30 NB. seconds ANGLE =: 0.025p1 NB. radians DIRECTION=: 0 NB. radians

POLY=: noun define

 pc poly;pn "Poly Spiral";
 minwh 320 320; cc isi isigraph;

)

poly_run=: verb define

 wd POLY,'pshow'
 wd 'timer ',":DT * 1000

)

poly_close=: verb define

 wd 'timer 0; pclose'

)

sys_timer_z_=: verb define

 recalcAngle_base_ 
 wd 'psel poly; set isi invalid'

)

poly_isi_paint=: verb define

 drawPolyspiral DIRECTION

)

recalcAngle=: verb define

 DIRECTION=: 2p1 | DIRECTION + ANGLE

)

drawPolyspiral=: verb define

 glclear
 x1y1 =. (glqwh)%2
 a=. -DIRECTION
 len=. 5
 for_i. i.150 do.
   glpen glrgb Hue a % 2p1
   x2y2=. x1y1 + len*(cos,sin) a
   gllines <.x1y1,x2y2
   x1y1=. x2y2
   len=. len+3
   a=. 2p1 | a - DIRECTION
 end.

)

poly_run</lang>

Note that we're using a lot of wd commands here. You'll need to be running jqt for this to work.

Java

Works with: Java version 8

<lang java>import java.awt.*; import java.awt.event.ActionEvent; import javax.swing.*;

public class PolySpiral extends JPanel {

   double inc = 0;
   public PolySpiral() {
       setPreferredSize(new Dimension(640, 640));
       setBackground(Color.white);
       new Timer(40, (ActionEvent e) -> {
           inc = (inc + 0.05) % 360;
           repaint();
       }).start();
   }
   void drawSpiral(Graphics2D g, int len, double angleIncrement) {
       double x1 = getWidth() / 2;
       double y1 = getHeight() / 2;
       double angle = angleIncrement;
       for (int i = 0; i < 150; i++) {
           g.setColor(Color.getHSBColor(i / 150f, 1.0f, 1.0f));
           double x2 = x1 + Math.cos(angle) * len;
           double y2 = y1 - Math.sin(angle) * len;
           g.drawLine((int) x1, (int) y1, (int) x2, (int) y2);
           x1 = x2;
           y1 = y2;
           len += 3;
           angle = (angle + angleIncrement) % (Math.PI * 2);
       }
   }
   @Override
   public void paintComponent(Graphics gg) {
       super.paintComponent(gg);
       Graphics2D g = (Graphics2D) gg;
       g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
               RenderingHints.VALUE_ANTIALIAS_ON);
       drawSpiral(g, 5, Math.toRadians(inc));
   }
   public static void main(String[] args) {
       SwingUtilities.invokeLater(() -> {
           JFrame f = new JFrame();
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           f.setTitle("PolySpiral");
           f.setResizable(true);
           f.add(new PolySpiral(), BorderLayout.CENTER);
           f.pack();
           f.setLocationRelativeTo(null);
           f.setVisible(true);
       });
   }

}</lang>

Lua

Library: LÖVE

LÖVE defaults to animating at sixty frames per second, so the patterns become very complex very quickly. <lang Lua>function love.load ()

   love.window.setTitle("Polyspiral")
   incr = 0

end

function love.update (dt)

   incr = (incr + 0.05) % 360
   x1 = love.graphics.getWidth() / 2
   y1 = love.graphics.getHeight() / 2
   length = 5
   angle = incr

end

function love.draw ()

   for i = 1, 150 do
       x2 = x1 + math.cos(angle) * length
       y2 = y1 + math.sin(angle) * length
       love.graphics.line(x1, y1, x2, y2)
       x1, y1 = x2, y2
       length = length + 3
       angle = (angle + incr) % 360
   end

end</lang>

PARI/GP

Works with: PARI/GP version 2.7.4 and above

Plotting helper functions

Both versions #1 and #2 are based on using my own small plotting helper functions. You can find a few others on OEIS Wiki and here on RC Wiki.

<lang parigp> \\ Plot the line from x1,y1 to x2,y2. plotline(x1,y1,x2,y2,w=0)={plotmove(w, x1,y1);plotrline(w,x2-x1,y2-y1);} \\ Convert degrees to radians. rad2(degs)={return(degs*Pi/180.0)} \\ Convert Polar coordinates to Cartesian. cartes2(r,a,rndf=0)={my(v,x,y); x=r*cos(a); y=r*sin(a);

 if(rndf==0, return([x,y]), return(round([x,y])))}

</lang>

Version #1. Polyspiral (a spiral made of multiple line segments).

In this version function plotpspiral() was translated from Java and J. Some tweaks and options were added to make it reusable and outputting differently looking polyspirals. There are no animation features in PARI/GP.

Output Polyspiral1.png
Output Polyspiral2.png
Output Polyspiral3.png
Output Polyspiral3b.png
Output Polyspiral4.png

<lang parigp> \\Polyspiral (a spiral made of multiple line segments) \\ 4/15/16 aev plotpspiral(size,lim,ai,d,di,c)={ my(x1,y1,x2,y2,air=ai*Pi,a,sai=Strprintf("%.3f",ai)); print(" *** Polyspiral, size=",size," lim=",lim," ai=",sai," d=",d," di=",di); x1=0; y1=0; a=air; for(i=0, lim,

   if(c==0, x2=x1+cos(a)*d; y2=y1-sin(a)*d,
            x2=x1-sin(a)*d; y2=y1+cos(a)*d;);
   plotline(x1,y1,x2,y2);
   x1=x2; y1=y2; d+=di; a+=air;
  );\\fend i

}

\\ Polyspiral() - Where: ai is an angle increment (in radians), d is a distance/length, \\ c is a direction 0/1 (clockwise/counter-clockwise); other parameters are self explanative. \\ 4/15/16 aev Last updated: 4/18/16 polyspiral(size,lim,ai,d,di,c=0)={ plotinit(0); plotcolor(0,3); \\blue plotscale(0, -size,size, -size,size); plotmove(0, 0,0); plotpspiral(size,lim,ai,d,di,c); plotdraw([0,size,size]); }

{\\ Executing: polyspiral(1500,1500,0.25,9,5); \\Polyspiral1.png polyspiral(1500,1500,0.25,3,2); \\Polyspiral2.png polyspiral(10000,10000,0.03,3,2); \\Polyspiral3.png polyspiral(10000,10000,0.03,3,2,1); \\Polyspiral3b.png polyspiral(100000,100000,0.03,3,2);\\Polyspiral4.png } </lang>

Output:

> polyspiral(1500,1500,0.25,9,5);  \\Polyspiral1.png
*** Polyspiral, size=1500 lim=1500 ai=0.250 d=9 di=5
 
> polyspiral(1500,1500,0.25,3,2);  \\Polyspiral2.png
*** Polyspiral, size=1500 lim=1500 ai=0.250 d=3 di=2
 
> polyspiral(10000,10000,0.03,3,2);  \\Polyspiral3.png
*** Polyspiral, size=100000 lim=100000 ai=0.030 d=3 di=2

> polyspiral(10000,10000,0.03,3,2,1);  \\Polyspiral3b.png
*** Polyspiral, size=100000 lim=100000 ai=0.030 d=3 di=2

> polyspiral(100000,100000,0.03,3,2);  \\Polyspiral4.png
*** Polyspiral, size=100000 lim=100000 ai=0.030 d=3 di=2

Version #2. Multi-spiral figure translated from zkl.

This is definitely not a polyspiral, but a very nice "multi-spiral" figure similar to shown in zkl and in a few other languages. Also, there is a very nice and impressive animation created in zkl, but not possible in PARI/GP.

Translation of: zkl
Output Spiralz.png

<lang parigp> \\ plotpspiralz() Multi-spiral figure translated from zkl using my own ploting functions. \\ 4/15/16 aev plotpspiralz(size,lim,ai,di,lim2)={ my(x1,y1,u1,v1,air=rad2(ai),a,sai=Strprintf("%.3f",ai),sdi=Strprintf("%.3f",di),

  sz2=size\2,aj,inc,ao,x,y,u,v,vc,r2i=rad2(130.0),d=0.0);

print(" *** Spiralz: size=",size," lim=",lim," ai=",sai," di=",sdi," lim2=",lim2); x1=0; y1=0; u1=0; v1=0; for(i=1, lim,

 r=0.0; a=0.0;ao=0.0;
 if(i>1, inc=air+r2i, inc=air);
 for(j=1, lim2,
   d=r+di; aj=a+inc;
   vc=cartes2(r,a); x=vc[1]; y=vc[2];
   vc=cartes2(r,aj); u=vc[1]; v=vc[2];
   plotline(ao+x,ao+y,ao+u,ao+v);
   r=d; a=aj;
 );\\fend j
 air+=0.05;

);\\fend i }

\\ Spiralz() - Where: ai is an angle increment (in radians), di is a distance/length \\ increment, other parameters are self explanative. \\ 4/15/16 aev Spiralz(size,lim,ai,di,lim2)={ plotinit(0); plotcolor(0,3); \\blue plotscale(0, -size,size, -size,size); \\plotscale(0, 0,size, 0,size); plotmove(0, 0,0); plotpspiralz(size,lim,ai,di,lim2); plotdraw([0,size,size]); }

{\\ Executing: Spiralz(640,2,3.0,3.0,128); \\Spiralz1.png } </lang>

Output:
> Spiralz(640,2,3.0,3.0,128);  \\Spiralz1.png
 *** Spiralz: size=640 lim=2 ai=3.000 di=3.000 lim2=128

zkl

If you click on the image, it is animated.

Uses the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl <lang zkl>w,h:=640,640; bitmap:=PPM(w,h,0xFF|FF|FF); // White background angleIncrement:=(3.0).toRad(); while(True){

  r,angle:=0.0, 0.0;
  ao,len,inc:=w/2, 2.5, angleIncrement+(130.0).toRad();
  foreach c in (128){
     s,a:=r + len, angle + inc;
     x,y:=r.toRectangular(angle);
     u,v:=r.toRectangular(a);
     c=c.shiftLeft(21) + c.shiftLeft(10) + c*8;  // convert c to a RGB
     bitmap.line(ao+x,ao+y, ao+u,ao+v, c);
     r,angle=s,a;
  }
  bitmap.writeJPGFile("polyspiral.zkl.jpg");
  bitmap.fill(0xFF|FF|FF);  // White background
  angleIncrement=(angleIncrement + 0.05);
  Atomic.sleep(3);

}</lang>