> For the complete documentation index, see [llms.txt](https://trizen.gitbook.io/perl6-rosettacode/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://trizen.gitbook.io/perl6-rosettacode/programming_tasks/p/polyspiral.md).

# Polyspiral

### SVG "pseudo-animation"

Sort of an ersatz animation. Write updates to a svg file, most modern viewers will update as the content changes.

```perl
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
}
```

See [polyspiral-perl6.gif](https://github.com/thundergnat/rc/blob/master/img/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.

```perl
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
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://trizen.gitbook.io/perl6-rosettacode/programming_tasks/p/polyspiral.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
