File Coverage

blib/lib/Math/Grid/Coordinates.pm
Criterion Covered Total %
statement 40 62 64.5
branch 2 4 50.0
condition n/a
subroutine 11 13 84.6
pod 6 9 66.6
total 59 88 67.0


line stmt bran cond sub pod time code
1             package Math::Grid::Coordinates;
2              
3 2     2   138044 use Moose;
  2         947576  
  2         14  
4 2     2   15375 use Moose::Util::TypeConstraints;
  2         4  
  2         18  
5              
6 2     2   6271 use List::AllUtils qw/max/;
  2         22933  
  2         179  
7 2     2   1110 use POSIX qw/ceil/;
  2         13486  
  2         14  
8              
9             # number of items
10             has [ qw/grid_width grid_height page_width page_height/ ] => ( is => 'rw', isa => 'Int' );
11              
12             has [ qw/page_width page_height/ ] => ( is => 'rw', isa => 'Num' );
13              
14             # item size
15             has [ qw/item_width item_height/ ] => ( is => 'rw', isa => 'Num' );
16              
17             # gutter border
18             has [ qw/gutter gutter_h gutter_v border border_l border_r border_t border_b/ ] => ( is => 'rw', isa => 'Num' );
19              
20             subtype 'Seq', as 'Str', where { /[h,v]/i };
21             has arrange => ( is => 'rw', isa => 'Seq', default => sub { 'h' } );
22              
23             # has item_sizes => ( is => 'rw', isa => 'ArrayRef[ArrayRef[Num]]' );
24              
25              
26             around BUILDARGS => sub {
27             my $orig = shift;
28             my $class = shift;
29             my $opts;
30              
31             if ( !ref $_[0] ) {
32             my %h;
33             @h{qw/grid_width grid_height item_width item_height gutter border/} = grep { /[^a-z]/i } @_;
34              
35             ($h{arrange}) = (grep { /^[h,v]i/ } @_) || ('h');
36             $h{gutter} ||= 0;
37             $h{border} ||= 0;
38             # return $class->$orig( \%h );
39             $opts = \%h;
40             } else {
41             $opts = shift;
42             }
43             $opts->{gutter_h} //= $opts->{gutter} // 0;
44             $opts->{gutter_v} //= $opts->{gutter} // $opts->{gutter_v} // 0;
45              
46             $opts->{border_t} //= $opts->{border} // $opts->{gutter_v} // 0;
47             $opts->{border_b} //= $opts->{border_t} // $opts->{border} // $opts->{gutter_v} // 0;
48              
49             $opts->{border_l} //= $opts->{border} // $opts->{gutter_h} // 0;
50             $opts->{border_r} //= $opts->{border_l};
51              
52             my $obj = $class->$orig($opts);
53             return $obj;
54             };
55              
56             sub total_height {
57 1     1 1 3 my $self = shift;
58 1         42 return $self->border_t + $self->item_height * $self->grid_height + $self->gutter_v * ($self->grid_height - 1) + $self->border_b;
59             };
60              
61             sub total_width {
62 1     1 1 2 my $self = shift;
63 1         38 return $self->border_l + $self->item_width * $self->grid_width + $self->gutter_h * ($self->grid_width - 1) + $self->border_r
64             };
65              
66             sub bbox {
67 1     1 1 8 my $self = shift;
68 1         4 my ($w, $h) = ($self->total_width, $self->total_height);
69 1 50       9 return wantarray ? ($w, $h) : [ $w, $h ];
70             }
71              
72             sub sequence {
73 2     2 1 5 my $self = shift;
74 2         17 my ($gw, $gh) = map { $self->$_ } qw/grid_width grid_height/;
  4         143  
75 2         5 my @sequence;
76              
77 2 50       57 if (lc($self->arrange) eq 'v') {
78 0         0 for my $x (0..$gw-1) { for my $y (0..$gh-1) { push @sequence, [$x, $y] } }
  0         0  
  0         0  
79             } else {
80 2         8 for my $y (0..$gh-1) { for my $x (0..$gw-1) { push @sequence, [$x, $y] } }
  8         16  
  24         58  
81             }
82 2         28 return @sequence;
83             }
84              
85             sub position {
86 12     12 0 19 my $self = shift;
87              
88 12         20 my ($x, $y) = @_;
89 12         19 my ($iw, $ih, $gt_h, $gt_v, $bl, $bt) = map { $self->$_ } qw/item_width item_height gutter_h gutter_v border_l border_t/;
  72         2017  
90              
91             return (
92 12         42 $bl + $iw * $x + $gt_h * $x,
93             $bt + $ih * $y + $gt_v * $y
94             )
95             }
96              
97             sub positions {
98 1     1 1 3 my $self = shift;
99             # my ($x1, $y1, $x2, $y2) = @_;
100              
101             # for ($x1, $y1) { $_ ||= 0 };
102              
103             # my ($gw, $gh, $iw, $ih, $gt_h, $gt_v, $bl, $br, $bt, $bb) = map { $self->$_ }
104             # qw/grid_width grid_height item_width item_height gutter_h gutter_v border_l border_r border_t border_b/;
105              
106             # first assign positions in terms of page coordinates
107 1         8 my @grid = $self->sequence;
108              
109             # then calculate and assign the actual position
110             my @pos = map {
111 1         3 [ $self->position(@$_) ]
  12         28  
112             } @grid;
113              
114 1         26 return @pos;
115             }
116              
117             sub guides {
118 0     0 0 0 my $self = shift;
119 0         0 my @guides;
120 0         0 my ($h, $w, $ih, $iw) = map { $self->$_ } qw/page_height page_width item_height item_width/;
  0         0  
121              
122 0         0 for (0..$self->grid_width-1) {
123 0         0 my $p = [ $self->position($_, 0) ]->[0];
124 0         0 push @guides, [ [ $p, 0 ], [ $p, $h ] ];
125 0         0 push @guides, [ [ $p + $iw, 0 ], [ $p + $iw, $h ] ];
126             }
127 0         0 for (0..$self->grid_height-1) {
128 0         0 my $p = [ $self->position(0, $_) ]->[1];
129 0         0 push @guides, [ [ 0, $p ], [ $w, $p ] ];
130 0         0 push @guides, [ [ 0, $p + $ih ], [ $w, $p + $ih ] ];
131             }
132 0         0 return @guides;
133             }
134              
135             sub calculate {
136 0     0 0 0 my $self = shift;
137              
138 0         0 my $avail_v = $self->page_height - ($self->border_t + $self->gutter_v * ($self->grid_height - 1) + $self->border_b);
139 0         0 my $avail_h = $self->page_width - ($self->border_l + $self->gutter_h * ($self->grid_width - 1) + $self->border_r);
140              
141             # print $avail_h, $avail_v;
142              
143 0         0 $self->item_width($avail_h / $self->grid_width);
144 0         0 $self->item_height($avail_v / $self->grid_height);
145              
146 0         0 return $self;
147             }
148              
149              
150             sub numbers {
151 1     1 1 3 my $self = shift;
152 1         38 return (1..($self->grid_width * $self->grid_height))
153             }
154              
155             __PACKAGE__->meta->make_immutable;
156              
157             1;
158              
159             #################### pod generated by Pod::Autopod - keep this line to make pod updates possible ####################
160              
161             =head1 NAME
162              
163             Grid - create geometric grids
164              
165             =head1 SYNOPSYS
166              
167             use Grid;
168              
169             my $grid = Grid->new($grid_width, $grid_height, $item_width, $item_height, $gutter, $border, $arrangement);
170              
171             =head1 DESCRIPTION
172              
173             Grid creates an array of x-y positions for items of a given height and width arranged in a grid. This is used to create grid layouts on a page, or repeate items on a number of pages of the same size.
174              
175             =head1 REQUIRES
176              
177             L<POSIX>
178              
179             L<List::AllUtils>
180              
181             L<Moose::Util::TypeConstraints>
182              
183             L<Moose>
184              
185              
186             =head1 METHODS
187              
188             =head2 bbox
189              
190             $grid->bbox();
191              
192             Returns the total bounding box of the grid
193              
194             =head2 numbers
195              
196             $grid->numbers();
197              
198             Returns the sequence item numbers, with the top left item as item 1.
199              
200             +---------+---------+---------+---------+
201             | | | | |
202             | 1 | 2 | 3 | 4 |
203             | | | | |
204             +---------+---------+---------+---------+
205             | | | | |
206             | 5 | 6 | 7 | 8 |
207             | | | | |
208             +---------+---------+---------+---------+
209             | | | | |
210             | 9 | 10 | 11 | 12 |
211             | | | | |
212             +---------+---------+---------+---------+
213              
214             =head2 sequence
215              
216             $grid->sequence();
217              
218             Returns the sequence of x-y grid item coordinates, with the top left item as item C<[0, 0]>, the next one (assuming a horizontal arrangement) being C<[1, 0]> etc.
219              
220             +---------+---------+---------+---------+
221             | | | | |
222             | [0, 0] | [0, 1] | [0, 2] | [0, 3] |
223             | | | | |
224             +---------+---------+---------+---------+
225             | | | | |
226             | [1, 0] | [1, 1] | [1, 2] | [1, 3] |
227             | | | | |
228             +---------+---------+---------+---------+
229             | | | | |
230             | [2, 0] | [2, 1] | [2, 2] | [2, 3] |
231             | | | | |
232             +---------+---------+---------+---------+
233              
234             =head2 positions
235              
236             $grid->positions();
237              
238             Returns the sequence of x-y grid coordinates.
239              
240             =head2 total_height
241              
242             $grid->total_height();
243              
244             The total height of the grid
245              
246             =head2 total_width
247              
248             $grid->total_width();
249              
250             The total width of the grid
251              
252             =head1 To do
253              
254             =over 4
255              
256             =item *
257              
258             Allow for different vertical and horizontal gutters
259              
260             =item *
261              
262             Allow for different top, bottom, left right borders
263              
264             =item *
265              
266             Allow for bottom or top start of grid
267              
268             =back
269              
270             =cut