line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Math::Grid::Coordinates; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
135174
|
use Moose; |
|
2
|
|
|
|
|
936488
|
|
|
2
|
|
|
|
|
12
|
|
4
|
2
|
|
|
2
|
|
15468
|
use Moose::Util::TypeConstraints; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
18
|
|
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
6085
|
use List::AllUtils qw/max/; |
|
2
|
|
|
|
|
22693
|
|
|
2
|
|
|
|
|
176
|
|
7
|
2
|
|
|
2
|
|
1120
|
use POSIX qw/ceil/; |
|
2
|
|
|
|
|
13862
|
|
|
2
|
|
|
|
|
11
|
|
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
|
|
|
|
|
31
|
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
|
3
|
my $self = shift; |
63
|
1
|
|
|
|
|
37
|
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
|
7
|
my $self = shift; |
68
|
1
|
|
|
|
|
4
|
my ($w, $h) = ($self->total_width, $self->total_height); |
69
|
1
|
50
|
|
|
|
8
|
return wantarray ? ($w, $h) : [ $w, $h ]; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub sequence { |
73
|
2
|
|
|
2
|
1
|
5
|
my $self = shift; |
74
|
2
|
|
|
|
|
5
|
my ($gw, $gh) = map { $self->$_ } qw/grid_width grid_height/; |
|
4
|
|
|
|
|
135
|
|
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
|
|
|
|
|
18
|
for my $y (0..$gh-1) { for my $x (0..$gw-1) { push @sequence, [$x, $y] } } |
|
8
|
|
|
|
|
16
|
|
|
24
|
|
|
|
|
48
|
|
81
|
|
|
|
|
|
|
} |
82
|
2
|
|
|
|
|
30
|
return @sequence; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub position { |
86
|
12
|
|
|
12
|
0
|
19
|
my $self = shift; |
87
|
|
|
|
|
|
|
|
88
|
12
|
|
|
|
|
19
|
my ($x, $y) = @_; |
89
|
12
|
|
|
|
|
20
|
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
|
|
|
|
|
43
|
$bl + $iw * $x + $gt_h * $x, |
93
|
|
|
|
|
|
|
$bt + $ih * $y + $gt_v * $y |
94
|
|
|
|
|
|
|
) |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub positions { |
98
|
1
|
|
|
1
|
1
|
4
|
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
|
|
|
|
|
4
|
my @grid = $self->sequence; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# then calculate and assign the actual position |
110
|
|
|
|
|
|
|
my @pos = map { |
111
|
1
|
|
|
|
|
13
|
[ $self->position(@$_) ] |
|
12
|
|
|
|
|
34
|
|
112
|
|
|
|
|
|
|
} @grid; |
113
|
|
|
|
|
|
|
|
114
|
1
|
|
|
|
|
13
|
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
|
4
|
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 |