Polyspiral: Difference between revisions
Content added Content deleted
m (polyspirangle -> polyspiral) |
Thundergnat (talk | contribs) (Rename Perl 6 -> Raku, alphabetize, minor clean-up) |
||
Line 34: | Line 34: | ||
<br><br> |
<br><br> |
||
=={{header|C}}== |
=={{header|C}}== |
||
Straightforward implementation of the pseudocode, incr and angle are integers and incr is incremented by 5 instead of 0.05 as the % operation in C is not defined for non-integers. Requires the [http://www.cs.colorado.edu/~main/bgi/cs1300/ WinBGIm] library. |
Straightforward implementation of the pseudocode, incr and angle are integers and incr is incremented by 5 instead of 0.05 as the % operation in C is not defined for non-integers. Requires the [http://www.cs.colorado.edu/~main/bgi/cs1300/ WinBGIm] library. |
||
Line 84: | Line 85: | ||
} |
} |
||
</lang> |
</lang> |
||
=={{header|C sharp|C#}}== |
|||
{{trans|Java}} |
|||
<lang csharp>using System; |
|||
using System.Drawing; |
|||
using System.Drawing.Drawing2D; |
|||
using System.Windows.Forms; |
|||
using System.Windows.Threading; |
|||
namespace Polyspiral |
|||
{ |
|||
public partial class Form1 : Form |
|||
{ |
|||
private double inc; |
|||
public Form1() |
|||
{ |
|||
Width = Height = 640; |
|||
StartPosition = FormStartPosition.CenterScreen; |
|||
SetStyle( |
|||
ControlStyles.AllPaintingInWmPaint | |
|||
ControlStyles.UserPaint | |
|||
ControlStyles.DoubleBuffer, |
|||
true); |
|||
var timer = new DispatcherTimer(); |
|||
timer.Tick += (s, e) => { inc = (inc + 0.05) % 360; Refresh(); }; |
|||
timer.Interval = new TimeSpan(0, 0, 0, 0, 40); |
|||
timer.Start(); |
|||
} |
|||
private void DrawSpiral(Graphics g, int len, double angleIncrement) |
|||
{ |
|||
double x1 = Width / 2; |
|||
double y1 = Height / 2; |
|||
double angle = angleIncrement; |
|||
for (int i = 0; i < 150; i++) |
|||
{ |
|||
double x2 = x1 + Math.Cos(angle) * len; |
|||
double y2 = y1 - Math.Sin(angle) * len; |
|||
g.DrawLine(Pens.Blue, (int)x1, (int)y1, (int)x2, (int)y2); |
|||
x1 = x2; |
|||
y1 = y2; |
|||
len += 3; |
|||
angle = (angle + angleIncrement) % (Math.PI * 2); |
|||
} |
|||
} |
|||
protected override void OnPaint(PaintEventArgs args) |
|||
{ |
|||
var g = args.Graphics; |
|||
g.SmoothingMode = SmoothingMode.AntiAlias; |
|||
g.Clear(Color.White); |
|||
DrawSpiral(g, 5, ToRadians(inc)); |
|||
} |
|||
private double ToRadians(double angle) |
|||
{ |
|||
return Math.PI * angle / 180.0; |
|||
} |
|||
} |
|||
}</lang> |
|||
=={{header|C++}}== |
=={{header|C++}}== |
||
Line 232: | Line 299: | ||
} |
} |
||
</lang> |
</lang> |
||
=={{header|C#}}== |
|||
{{trans|Java}} |
|||
<lang csharp>using System; |
|||
using System.Drawing; |
|||
using System.Drawing.Drawing2D; |
|||
using System.Windows.Forms; |
|||
using System.Windows.Threading; |
|||
namespace Polyspiral |
|||
{ |
|||
public partial class Form1 : Form |
|||
{ |
|||
private double inc; |
|||
public Form1() |
|||
{ |
|||
Width = Height = 640; |
|||
StartPosition = FormStartPosition.CenterScreen; |
|||
SetStyle( |
|||
ControlStyles.AllPaintingInWmPaint | |
|||
ControlStyles.UserPaint | |
|||
ControlStyles.DoubleBuffer, |
|||
true); |
|||
var timer = new DispatcherTimer(); |
|||
timer.Tick += (s, e) => { inc = (inc + 0.05) % 360; Refresh(); }; |
|||
timer.Interval = new TimeSpan(0, 0, 0, 0, 40); |
|||
timer.Start(); |
|||
} |
|||
private void DrawSpiral(Graphics g, int len, double angleIncrement) |
|||
{ |
|||
double x1 = Width / 2; |
|||
double y1 = Height / 2; |
|||
double angle = angleIncrement; |
|||
for (int i = 0; i < 150; i++) |
|||
{ |
|||
double x2 = x1 + Math.Cos(angle) * len; |
|||
double y2 = y1 - Math.Sin(angle) * len; |
|||
g.DrawLine(Pens.Blue, (int)x1, (int)y1, (int)x2, (int)y2); |
|||
x1 = x2; |
|||
y1 = y2; |
|||
len += 3; |
|||
angle = (angle + angleIncrement) % (Math.PI * 2); |
|||
} |
|||
} |
|||
protected override void OnPaint(PaintEventArgs args) |
|||
{ |
|||
var g = args.Graphics; |
|||
g.SmoothingMode = SmoothingMode.AntiAlias; |
|||
g.Clear(Color.White); |
|||
DrawSpiral(g, 5, ToRadians(inc)); |
|||
} |
|||
private double ToRadians(double angle) |
|||
{ |
|||
return Math.PI * angle / 180.0; |
|||
} |
|||
} |
|||
}</lang> |
|||
=={{header|Ceylon}}== |
=={{header|Ceylon}}== |
||
Line 886: | Line 887: | ||
return val</lang> |
return val</lang> |
||
Link to live demo: https://dc25.github.io/rosettaCode__Polyspiral_haskell/ |
Link to live demo: https://dc25.github.io/rosettaCode__Polyspiral_haskell/ |
||
=={{header|IS-BASIC}}== |
=={{header|IS-BASIC}}== |
||
Line 1,200: | Line 1,201: | ||
</body> |
</body> |
||
</html></lang> |
</html></lang> |
||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
Line 1,492: | Line 1,492: | ||
*** Spiralz: size=640 lim=2 ai=3.000 di=3.000 lim2=128 |
*** Spiralz: size=640 lim=2 ai=3.000 di=3.000 lim2=128 |
||
</pre> |
</pre> |
||
=={{header|Perl 6}}== |
|||
{{works with|Rakudo|2018.09}} |
|||
===SVG "pseudo-animation"=== |
|||
Sort of an ersatz animation. Write updates to a svg file, most modern viewers will update as the content changes. |
|||
<lang perl6>use SVG; |
|||
my $w = 600; |
|||
my $h = 600; |
|||
for 3..33 -> $a { |
|||
my $angle = $a/τ; |
|||
my $x1 = $w/2; |
|||
my $y1 = $h/2; |
|||
my @lines; |
|||
for 1..144 { |
|||
my $length = 3 * $_; |
|||
my ($x2, $y2) = ($x1, $y1) «+« |cis($angle * $_).reals».round(.01) »*» $length ; |
|||
@lines.push: 'line' => [:x1($x1.clone), :y1($y1.clone), :x2($x2.clone), :y2($y2.clone), |
|||
:style("stroke:rgb({hsv2rgb(($_*5 % 360)/360,1,1).join: ','})")]; |
|||
($x1, $y1) = $x2, $y2; |
|||
} |
|||
my $fname = "./polyspiral-perl6.svg".IO.open(:w); |
|||
$fname.say( SVG.serialize( |
|||
svg => [ |
|||
width => $w, height => $h, style => 'stroke:rgb(0,0,0)', |
|||
:rect[:width<100%>, :height<100%>, :fill<black>], |
|||
|@lines, |
|||
],) |
|||
); |
|||
$fname.close; |
|||
sleep .15; |
|||
} |
|||
sub hsv2rgb ( $h, $s, $v ){ # inputs normalized 0-1 |
|||
my $c = $v * $s; |
|||
my $x = $c * (1 - abs( (($h*6) % 2) - 1 ) ); |
|||
my $m = $v - $c; |
|||
my ($r, $g, $b) = do given $h { |
|||
when 0..^(1/6) { $c, $x, 0 } |
|||
when 1/6..^(1/3) { $x, $c, 0 } |
|||
when 1/3..^(1/2) { 0, $c, $x } |
|||
when 1/2..^(2/3) { 0, $x, $c } |
|||
when 2/3..^(5/6) { $x, 0, $c } |
|||
when 5/6..1 { $c, 0, $x } |
|||
} |
|||
( $r, $g, $b ).map: ((*+$m) * 255).Int |
|||
}</lang> |
|||
{{out}} |
|||
See [https://github.com/thundergnat/rc/blob/master/img/polyspiral-perl6.gif polyspiral-perl6.gif] (offsite animated gif image) |
|||
===SDL full animation=== |
|||
Uses the same basic algorithm but fully animated. Use the up / down arrow keys to speed up / slow down the update speed. Use PgUp / PgDn keys to increment / decrement animation speed by large amounts. Use left / right arrow keys to reverse the "direction" of angle change. Press Space bar to toggle animation / reset to minimum speed. Left Control key to toggle stationary / rotating center. Use + / - keys to add remove line segments. |
|||
<lang perl6>use SDL2::Raw; |
|||
my $width = 900; |
|||
my $height = 900; |
|||
SDL_Init(VIDEO); |
|||
my $window = SDL_CreateWindow( |
|||
'Polyspiral', |
|||
SDL_WINDOWPOS_CENTERED_MASK, |
|||
SDL_WINDOWPOS_CENTERED_MASK, |
|||
$width, $height, |
|||
RESIZABLE |
|||
); |
|||
my $render = SDL_CreateRenderer($window, -1, ACCELERATED +| PRESENTVSYNC); |
|||
my $event = SDL_Event.new; |
|||
enum KEY_CODES ( |
|||
K_UP => 82, |
|||
K_DOWN => 81, |
|||
K_LEFT => 80, |
|||
K_RIGHT => 79, |
|||
K_SPACE => 44, |
|||
K_PGUP => 75, |
|||
K_PGDN => 78, |
|||
K_LCTRL => 224, |
|||
K_PLUS => 87, |
|||
K_MINUS => 86, |
|||
K_SPLUS => 46, |
|||
K_SMINUS => 45, |
|||
); |
|||
my $angle = 0; |
|||
my $lines = 240; |
|||
my @rgb = palette($lines); |
|||
my ($x1, $y1); |
|||
my $dir = 1; |
|||
my $rot = 0; |
|||
my $incr = .0001/π; |
|||
my $step = $incr*70; |
|||
main: loop { |
|||
while SDL_PollEvent($event) { |
|||
my $casted_event = SDL_CastEvent($event); |
|||
given $casted_event { |
|||
when *.type == QUIT { last main } |
|||
when *.type == KEYDOWN { |
|||
if KEY_CODES(.scancode) -> $comm { |
|||
given $comm { |
|||
when 'K_LEFT' { $dir = $rot ?? 1 !! -1 } |
|||
when 'K_RIGHT' { $dir = $rot ?? -1 !! 1 } |
|||
when 'K_UP' { $step += $incr } |
|||
when 'K_DOWN' { $step -= $incr if $step > $incr } |
|||
when 'K_PGUP' { $step += $incr*50 } |
|||
when 'K_PGDN' { $step -= $incr*50; $step = $step < $incr ?? $incr !! $step } |
|||
when 'K_SPACE' { $step = $step ?? 0 !! $incr } |
|||
when 'K_LCTRL' { $rot = $rot ?? 0 !! -1; $dir *= -1 } |
|||
when 'K_PLUS' { $lines = ($lines + 5) min 360; @rgb = palette($lines) } |
|||
when 'K_SPLUS' { $lines = ($lines + 5) min 360; @rgb = palette($lines) } |
|||
when 'K_MINUS' { $lines = ($lines - 5) max 60; @rgb = palette($lines) } |
|||
when 'K_SMINUS' { $lines = ($lines - 5) max 60; @rgb = palette($lines) } |
|||
} |
|||
} |
|||
#say .scancode; # unknown key pressed |
|||
} |
|||
when *.type == WINDOWEVENT { |
|||
if .event == 5 { |
|||
$width = .data1; |
|||
$height = .data2; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
$angle = ($angle + $dir * $step) % τ; |
|||
($x1, $y1) = $width div 2, $height div 2; |
|||
my $dim = $width min $height; |
|||
my $scale = (2 + .33 * abs(π - $angle)) * $dim / $lines; |
|||
$scale *= ($angle > π) ?? (1 - $angle/τ) !! $angle/τ; |
|||
$scale max= $dim/$lines/$lines; |
|||
for ^$lines { |
|||
my $length = $scale + $scale * $_; |
|||
my ($x2, $y2) = ($x1, $y1) «+« cis(($angle * $rot * $lines) + $angle * $_).reals »*» $length; |
|||
SDL_SetRenderDrawColor($render, |@rgb[$_], 255); |
|||
SDL_RenderDrawLine($render, |($x1, $y1, $x2, $y2)».round(1)); |
|||
($x1, $y1) = $x2, $y2; |
|||
} |
|||
@rgb.=rotate($lines/60); |
|||
SDL_RenderPresent($render); |
|||
SDL_SetRenderDrawColor($render, 0, 0, 0, 0); |
|||
SDL_RenderClear($render); |
|||
} |
|||
SDL_Quit(); |
|||
sub palette ($l) { (^$l).map: { hsv2rgb(($_ * 360/$l % 360)/360, 1, 1).list } }; |
|||
sub hsv2rgb ( $h, $s, $v ){ # inputs normalized 0-1 |
|||
my $c = $v * $s; |
|||
my $x = $c * (1 - abs( (($h*6) % 2) - 1 ) ); |
|||
my $m = $v - $c; |
|||
my ($r, $g, $b) = do given $h { |
|||
when 0..^(1/6) { $c, $x, 0 } |
|||
when 1/6..^(1/3) { $x, $c, 0 } |
|||
when 1/3..^(1/2) { 0, $c, $x } |
|||
when 1/2..^(2/3) { 0, $x, $c } |
|||
when 2/3..^(5/6) { $x, 0, $c } |
|||
when 5/6..1 { $c, 0, $x } |
|||
} |
|||
( $r, $g, $b ).map: ((*+$m) * 255).Int |
|||
}</lang> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Line 1,838: | Line 1,668: | ||
See the output for yourself! |
See the output for yourself! |
||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|2018.09}} |
|||
===SVG "pseudo-animation"=== |
|||
Sort of an ersatz animation. Write updates to a svg file, most modern viewers will update as the content changes. |
|||
<lang perl6>use SVG; |
|||
my $w = 600; |
|||
my $h = 600; |
|||
for 3..33 -> $a { |
|||
my $angle = $a/τ; |
|||
my $x1 = $w/2; |
|||
my $y1 = $h/2; |
|||
my @lines; |
|||
for 1..144 { |
|||
my $length = 3 * $_; |
|||
my ($x2, $y2) = ($x1, $y1) «+« |cis($angle * $_).reals».round(.01) »*» $length ; |
|||
@lines.push: 'line' => [:x1($x1.clone), :y1($y1.clone), :x2($x2.clone), :y2($y2.clone), |
|||
:style("stroke:rgb({hsv2rgb(($_*5 % 360)/360,1,1).join: ','})")]; |
|||
($x1, $y1) = $x2, $y2; |
|||
} |
|||
my $fname = "./polyspiral-perl6.svg".IO.open(:w); |
|||
$fname.say( SVG.serialize( |
|||
svg => [ |
|||
width => $w, height => $h, style => 'stroke:rgb(0,0,0)', |
|||
:rect[:width<100%>, :height<100%>, :fill<black>], |
|||
|@lines, |
|||
],) |
|||
); |
|||
$fname.close; |
|||
sleep .15; |
|||
} |
|||
sub hsv2rgb ( $h, $s, $v ){ # inputs normalized 0-1 |
|||
my $c = $v * $s; |
|||
my $x = $c * (1 - abs( (($h*6) % 2) - 1 ) ); |
|||
my $m = $v - $c; |
|||
my ($r, $g, $b) = do given $h { |
|||
when 0..^(1/6) { $c, $x, 0 } |
|||
when 1/6..^(1/3) { $x, $c, 0 } |
|||
when 1/3..^(1/2) { 0, $c, $x } |
|||
when 1/2..^(2/3) { 0, $x, $c } |
|||
when 2/3..^(5/6) { $x, 0, $c } |
|||
when 5/6..1 { $c, 0, $x } |
|||
} |
|||
( $r, $g, $b ).map: ((*+$m) * 255).Int |
|||
}</lang> |
|||
{{out}} |
|||
See [https://github.com/thundergnat/rc/blob/master/img/polyspiral-perl6.gif polyspiral-perl6.gif] (offsite animated gif image) |
|||
===SDL full animation=== |
|||
Uses the same basic algorithm but fully animated. Use the up / down arrow keys to speed up / slow down the update speed. Use PgUp / PgDn keys to increment / decrement animation speed by large amounts. Use left / right arrow keys to reverse the "direction" of angle change. Press Space bar to toggle animation / reset to minimum speed. Left Control key to toggle stationary / rotating center. Use + / - keys to add remove line segments. |
|||
<lang perl6>use SDL2::Raw; |
|||
my $width = 900; |
|||
my $height = 900; |
|||
SDL_Init(VIDEO); |
|||
my $window = SDL_CreateWindow( |
|||
'Polyspiral', |
|||
SDL_WINDOWPOS_CENTERED_MASK, |
|||
SDL_WINDOWPOS_CENTERED_MASK, |
|||
$width, $height, |
|||
RESIZABLE |
|||
); |
|||
my $render = SDL_CreateRenderer($window, -1, ACCELERATED +| PRESENTVSYNC); |
|||
my $event = SDL_Event.new; |
|||
enum KEY_CODES ( |
|||
K_UP => 82, |
|||
K_DOWN => 81, |
|||
K_LEFT => 80, |
|||
K_RIGHT => 79, |
|||
K_SPACE => 44, |
|||
K_PGUP => 75, |
|||
K_PGDN => 78, |
|||
K_LCTRL => 224, |
|||
K_PLUS => 87, |
|||
K_MINUS => 86, |
|||
K_SPLUS => 46, |
|||
K_SMINUS => 45, |
|||
); |
|||
my $angle = 0; |
|||
my $lines = 240; |
|||
my @rgb = palette($lines); |
|||
my ($x1, $y1); |
|||
my $dir = 1; |
|||
my $rot = 0; |
|||
my $incr = .0001/π; |
|||
my $step = $incr*70; |
|||
main: loop { |
|||
while SDL_PollEvent($event) { |
|||
my $casted_event = SDL_CastEvent($event); |
|||
given $casted_event { |
|||
when *.type == QUIT { last main } |
|||
when *.type == KEYDOWN { |
|||
if KEY_CODES(.scancode) -> $comm { |
|||
given $comm { |
|||
when 'K_LEFT' { $dir = $rot ?? 1 !! -1 } |
|||
when 'K_RIGHT' { $dir = $rot ?? -1 !! 1 } |
|||
when 'K_UP' { $step += $incr } |
|||
when 'K_DOWN' { $step -= $incr if $step > $incr } |
|||
when 'K_PGUP' { $step += $incr*50 } |
|||
when 'K_PGDN' { $step -= $incr*50; $step = $step < $incr ?? $incr !! $step } |
|||
when 'K_SPACE' { $step = $step ?? 0 !! $incr } |
|||
when 'K_LCTRL' { $rot = $rot ?? 0 !! -1; $dir *= -1 } |
|||
when 'K_PLUS' { $lines = ($lines + 5) min 360; @rgb = palette($lines) } |
|||
when 'K_SPLUS' { $lines = ($lines + 5) min 360; @rgb = palette($lines) } |
|||
when 'K_MINUS' { $lines = ($lines - 5) max 60; @rgb = palette($lines) } |
|||
when 'K_SMINUS' { $lines = ($lines - 5) max 60; @rgb = palette($lines) } |
|||
} |
|||
} |
|||
#say .scancode; # unknown key pressed |
|||
} |
|||
when *.type == WINDOWEVENT { |
|||
if .event == 5 { |
|||
$width = .data1; |
|||
$height = .data2; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
$angle = ($angle + $dir * $step) % τ; |
|||
($x1, $y1) = $width div 2, $height div 2; |
|||
my $dim = $width min $height; |
|||
my $scale = (2 + .33 * abs(π - $angle)) * $dim / $lines; |
|||
$scale *= ($angle > π) ?? (1 - $angle/τ) !! $angle/τ; |
|||
$scale max= $dim/$lines/$lines; |
|||
for ^$lines { |
|||
my $length = $scale + $scale * $_; |
|||
my ($x2, $y2) = ($x1, $y1) «+« cis(($angle * $rot * $lines) + $angle * $_).reals »*» $length; |
|||
SDL_SetRenderDrawColor($render, |@rgb[$_], 255); |
|||
SDL_RenderDrawLine($render, |($x1, $y1, $x2, $y2)».round(1)); |
|||
($x1, $y1) = $x2, $y2; |
|||
} |
|||
@rgb.=rotate($lines/60); |
|||
SDL_RenderPresent($render); |
|||
SDL_SetRenderDrawColor($render, 0, 0, 0, 0); |
|||
SDL_RenderClear($render); |
|||
} |
|||
SDL_Quit(); |
|||
sub palette ($l) { (^$l).map: { hsv2rgb(($_ * 360/$l % 360)/360, 1, 1).list } }; |
|||
sub hsv2rgb ( $h, $s, $v ){ # inputs normalized 0-1 |
|||
my $c = $v * $s; |
|||
my $x = $c * (1 - abs( (($h*6) % 2) - 1 ) ); |
|||
my $m = $v - $c; |
|||
my ($r, $g, $b) = do given $h { |
|||
when 0..^(1/6) { $c, $x, 0 } |
|||
when 1/6..^(1/3) { $x, $c, 0 } |
|||
when 1/3..^(1/2) { 0, $c, $x } |
|||
when 1/2..^(2/3) { 0, $x, $c } |
|||
when 2/3..^(5/6) { $x, 0, $c } |
|||
when 5/6..1 { $c, 0, $x } |
|||
} |
|||
( $r, $g, $b ).map: ((*+$m) * 255).Int |
|||
}</lang> |
|||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
Line 1,958: | Line 1,959: | ||
}</lang> |
}</lang> |
||
=={{header|SPL}}== |
=={{header|SPL}}== |
||
<lang spl>width,height = #.scrsize() |
<lang spl>width,height = #.scrsize() |