Polyspiral
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
<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
<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
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
PARI/GP
In this version function plotpspiral() was translated from Java and J, plus my own plotline() function was used. Some tweaks and options were added to make it reusable and outputting differently looking polyspirals. There are no animation features in PARI/GP.
<lang parigp> \\Polyspiral (a spiral made of multiple line segments) \\ 4/15/16 aev \\ plotline(): Helper function - 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);}
\\ plotpspiral() - translated from Java and J using my own plotline() function. plotpspiral(size,lim,ai,d,di)={ 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;\\from J OK!! the best a=air; for(i=0, lim,
x2=x1+cos(a)*d; y2=y1-sin(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; other parameters are self explanative. \\ 4/15/16 aev polyspiral(size,lim,ai,d,di)={ plotinit(0); plotcolor(0,3); \\blue plotscale(0, -size,size, -size,size); plotmove(0, 0,0); plotpspiral(size,lim,ai,d,di); \\v#23 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(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(100000,100000,0.03,3,2); \\Polyspiral4.png *** Polyspiral, size=100000 lim=100000 ai=0.030 d=3 di=2
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>