File Coverage

blib/lib/Math/Spiral.pm
Criterion Covered Total %
statement 47 67 70.1
branch 19 32 59.3
condition 11 21 52.3
subroutine 4 4 100.0
pod 2 2 100.0
total 83 126 65.8


line stmt bran cond sub pod time code
1             package Math::Spiral;
2              
3 1     1   105716 use strict;
  1         3  
  1         41  
4 1     1   5 use warnings;
  1         2  
  1         910  
5              
6             # perl -MPod::Markdown -e 'Pod::Markdown->new->filter(@ARGV)' lib/Math/Spiral.pm > README.md
7              
8             =head1 NAME
9              
10             Math::Spiral - Perl extension to return an endless stream of X, Y offset coordinates which represent a spiral shape
11              
12              
13             =head1 SYNOPSIS
14              
15              
16             #!/usr/bin/perl -w
17            
18             use Math::Spiral;
19              
20             my $s = new Math::Spiral();
21             my($xo,$yo)=$s->Next();
22              
23              
24             # perl -MMath::Spiral -e '$s=new Math::Spiral(); foreach(0..9) { ($xo,$yo)=$s->Next(); $chart[2+$xo][2+$yo]=$_; } foreach $y (0..4){foreach $x(0..4){if(defined($chart[$x][$y])){print $chart[$x][$y]} else {print " ";} } print "\n"}'
25              
26              
27             =head1 DESCRIPTION
28              
29             This module outputs an infinite sequence of coordinate offsets, which you can use to plot things in a spiral shape.
30             The numbers return "clockwise"; negate one if you want to go anti-clockwise instead.
31              
32             It is useful for charting things where you need to concentrate something around the center of the chart.
33              
34              
35             =head2 METHODS
36              
37             =head2 new
38              
39             Usage is
40              
41             my $s = new Math::Spiral();
42              
43              
44             =head2 Next
45              
46             Returns the next x and y offsets (note that these start at 0,0 and will go negative to circle around this origin)
47              
48             Usage is
49              
50             my($xo,$yo)=$s->Next();
51             # Returns a sequence like (0,0) (1,0) (1,1) (0,1) (-1,1) (-1,0) (-1,-1) (0,-1) (1,-1) (2,-1) ... etc (i.e. the x,y coordinates for a spiral)
52              
53              
54             =head2 EXAMPLE
55              
56             #!/usr/bin/perl -w
57            
58             use Math::Spiral;
59              
60             my $s = new Math::Spiral(); # Optional - for non-square output, add an aspect ration here. e.g. new Math::Spiral(1024/768);
61              
62             foreach(0..9) {
63             ($xo,$yo)=$s->Next(); # Returns a sequence like (0,0) (1,0) (1,1) (0,1) (-1,1) (-1,0) (-1,-1) (0,-1) (1,-1) (2,-1) ... etc
64             $chart[2+$xo][2+$yo]=$_;
65             }
66              
67             foreach $y (0..4) {
68             foreach $x(0..4) {
69             if(defined($chart[$x][$y])) {
70             print $chart[$x][$y]
71             } else {
72             print " ";
73             }
74             }
75             print "\n"
76             }
77              
78             =head3 Prints
79              
80             6789
81             501
82             432
83              
84             =head3 Aspect Ratio feature
85              
86             perl -MMath::Spiral -e '$mx=30;@c=("a".."z","0".."9","A".."Z");$s=new Math::Spiral(220/1024); foreach(0..162) { $c=$c[$_%62]; ($xo,$yo)=$s->Next($c); warn "\033[31;1m Overwrite \033[0m ",$chart[$mx/2+$xo][$mx/2+$yo],"(",$xo,",",$yo,")" if(defined $chart[$mx/2+$xo][$mx/2+$yo]); $chart[$mx/2+$xo][$mx/2+$yo]=$c; &prt() if 0; } sub prt{foreach $y (0..$mx){foreach $x(0..$mx){if(defined($chart[$x][$y])){print $chart[$x][$y]} else {print " ";} } print "\n"}} &prt();'
87              
88             Math::Spiral() Spiral(220/1024) Spiral(1024/480)
89              
90             6789ABC 6789AB mnopqrstuvwxyz0123
91             5MNOPQRSTUVWX uvwxyz lGqrstuvwxyz0123H4
92             4LklmnopqrstY ijklmn kFpSABCDEFGHIJT4I5
93             3KjGHIJKLMNuZ CDEFGH jEoR9uoghijpvKU5J6
94             2JiFuvwxyzOva BklmnI iDnQ8tnfabkqwLV6K7
95             1IhEtghij0Pwb AcdefJ hCmP7smedclrxMW7L8
96             0HgDsfabk1Qxc 9UVWXK gBlO6543210zyNX8M9
97             zGfCredcl2Ryd 8ABCDL fAkjihgfedcbaZY9NA
98             yFeBqponm3Sze 79uvEM CedcbaZYXWVUTSRQPOB
99             xEdA987654T0f 68qrFN
100             wDcbaZYXWVU1g 57mnGO
101             vCBA98765432h 46ijHP
102             utsrqponmlkji 35efIQ
103             24abJR
104             13dcKS
105             02hgLT
106             z1lkMU
107             y0poNV
108             xztsOW
109             wyxwPX
110             vTSRQY
111             ubaZYZ
112             tjihga
113             srqpob
114             hgfedc
115             tsrqpo
116             543210
117             C
118            
119            
120             perl -MMath::Spiral -e '$s=new Math::Spiral(); foreach(0..25) { ($xo,$yo)=$s->Next(); $chart[3+$xo][3+$yo]=$_; } foreach $y (0..6){foreach $x(0..6){if(defined($chart[$x][$y])){print chr(97+$chart[$x][$y])} else {print " ";} } print "\n"}'
121              
122             uvwxyz
123             tghij
124             sfabk
125             redcl
126             qponm
127              
128             =head2 EXPORT
129              
130             None by default.
131              
132             =cut
133              
134             require Exporter;
135              
136             our @ISA = qw(Exporter);
137             our($VERSION)='1.02';
138             our($UntarError) = '';
139              
140             our %EXPORT_TAGS = ( 'all' => [ qw( ) ] );
141              
142             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
143              
144             our @EXPORT = qw( );
145              
146              
147             sub new {
148 1     1 1 158053 my $class = shift;
149 1         2 my $this={};
150 1 50       3 $this->{aspect} = shift; $this->{aspect}=1 unless($this->{aspect});
  1         5  
151              
152 1         3 foreach(qw(xmin x y xdir ydir xmax ymin ymax forcex forcey skipy skipx)){ $this->{$_}=0; }
  12         19  
153 1         2 $this->{ydir} = -1; # Initial case, so first result is (0,0)
154 1         2 $this->{y} = 1; # Initial case, so first result is (0,0)
155              
156 1         2 bless $this,$class;
157 1         5 return $this;
158             } # new
159              
160              
161             sub Next {
162 10     10 1 36 my $this = shift;
163              
164 10         13 $this->{x}+=$this->{xdir};
165 10         9 $this->{y}+=$this->{ydir};
166              
167 10         10 my($nx,$ny);
168              
169 10 100 100     57 if( ($this->{x}>=$this->{xmax})&&($this->{xdir})) { # Hit max-right, and going sideways; change direction to down
    100 66        
    100 66        
    100 66        
170 2         2 $this->{xdir}=0; $this->{ydir}=1; # Change direction
  2         3  
171 2         2 $this->{ymax}++; # Go one more than last time
172 2         7 my $aspect=($this->{xmax}-$this->{xmin})/($this->{ymax}-$this->{ymin});
173 2 0 33     5 if($this->{aspect}>1 && $this->{ymin} && $aspect<$this->{aspect}) { # skip first row
      0        
174 0         0 $this->{forcey} ^=1; # clear if it was set, otherwise, set it.
175 0         0 $this->{ymax}--; $this->{skipy}++;
  0         0  
176             }
177 2 50       4 if($this->{skipx}) { $this->{skipx}--; $ny=$this->{ymax}-1; }
  0         0  
  0         0  
178              
179             } elsif(($this->{y}<=$this->{ymin})&&($this->{ydir})) { # Hit max top, and going vertically; change direction to right
180 2         3 $this->{xdir}=1; $this->{ydir}=0;
  2         3  
181 2         3 $this->{xmax}++;
182 2 50       3 if($this->{forcex}) {
183 0         0 $this->{forcex} ^=1; # clear if it was set, otherwise, set it.
184 0         0 $this->{xmax}--; $this->{skipx}=1;
  0         0  
185             }
186 2 50       5 if($this->{skipy}) { $this->{skipy}--; $nx=$this->{xmax}-1; }
  0         0  
  0         0  
187            
188             } elsif(($this->{x}<=$this->{xmin})&&($this->{xdir})) { # Hit max-left, and going sideways; change direction to up
189 1         1 $this->{xdir}=0; $this->{ydir}=-1;
  1         2  
190 1         2 $this->{ymin}--;
191 1 50       3 if($this->{forcey}) {
192 0         0 $this->{forcey} ^=1; # clear if it was set, otherwise, set it.
193 0         0 $this->{ymin}++; $this->{skipy}++;
  0         0  
194             }
195 1 50       3 if($this->{skipx}) { $this->{skipx}--; $ny=$this->{ymin}+1; }
  0         0  
  0         0  
196              
197             } elsif(($this->{y}>=$this->{ymax})&&($this->{ydir})) { # Hit max bottom, and going vertically; change direction to left
198 1         5 $this->{xdir}=-1; $this->{ydir}=0;
  1         2  
199 1         2 $this->{xmin}--;
200 1 50       5 my $aspect=$this->{ymax} ? ($this->{xmax}-$this->{xmin})/($this->{ymax}-$this->{ymin}) : 0;
201 1 50 33     9 if( $this->{aspect}<1 && $aspect>$this->{aspect} ) {
202 0         0 $this->{forcex} ^=1; # clear if it was set, otherwise, set it.
203 0         0 $this->{xmin}++; $this->{skipx}=1;
  0         0  
204             }
205 1 50       2 if($this->{skipy}) { $this->{skipy}--; $nx=$this->{xmin}+1; }
  0         0  
  0         0  
206              
207             }
208              
209 10         14 my @ret=($this->{x},$this->{y});
210 10 50       13 $this->{x}=$nx if(defined($nx));
211 10 50       11 $this->{y}=$ny if(defined($ny));
212 10         15 return @ret;
213             } # Next
214              
215             1;
216              
217             __END__