File Coverage

blib/lib/Math/Polygon.pm
Criterion Covered Total %
statement 70 122 57.3
branch 17 38 44.7
condition 8 21 38.1
subroutine 19 35 54.2
pod 28 29 96.5
total 142 245 57.9


line stmt bran cond sub pod time code
1             # This code is part of Perl distribution Math-Polygon version 2.00.
2             # The POD got stripped from this file by OODoc version 3.03.
3             # For contributors see file ChangeLog.
4              
5             # This software is copyright (c) 2004-2025 by Mark Overmeer.
6              
7             # This is free software; you can redistribute it and/or modify it under
8             # the same terms as the Perl 5 programming language system itself.
9             # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
10              
11             #oodist: *** DO NOT USE THIS VERSION FOR PRODUCTION ***
12             #oodist: This file contains OODoc-style documentation which will get stripped
13             #oodist: during its release in the distribution. You can use this file for
14             #oodist: testing, however the code of this development version may be broken!
15              
16             package Math::Polygon;{
17             our $VERSION = '2.00';
18             }
19              
20              
21 3     3   139347 use strict;
  3         9  
  3         142  
22 3     3   28 use warnings;
  3         7  
  3         221  
23              
24 3     3   693 use Log::Report 'math-polygon';
  3         116776  
  3         31  
25              
26             # Include all implementations
27 3     3   2919 use Math::Polygon::Calc;
  3         21  
  3         400  
28 3     3   1768 use Math::Polygon::Clip;
  3         12  
  3         228  
29 3     3   1833 use Math::Polygon::Transform;
  3         14  
  3         6405  
30              
31             #--------------------
32              
33             sub new(@)
34 12     12 1 203163 { my $thing = shift;
35 12   66     61 my $class = ref $thing || $thing;
36              
37 12         24 my @points;
38             my %options;
39 12 100       36 if(ref $thing)
40 3         9 { $options{clockwise} = $thing->{MP_clockwise};
41             }
42              
43 12         35 while(@_)
44 35 100       81 { if(ref $_[0] eq 'ARRAY') { push @points, shift }
  29         60  
45 6         13 else { my $k = shift; $options{$k} = shift }
  6         23  
46             }
47 12         32 $options{_points} = \@points;
48              
49 12         106 (bless {}, $class)->init(\%options);
50             }
51              
52             sub init($$)
53 12     12 0 29 { my ($self, $args) = @_;
54 12   66     73 $self->{MP_points} = $args->{points} || $args->{_points};
55 12         35 $self->{MP_clockwise} = $args->{clockwise};
56 12         26 $self->{MP_bbox} = $args->{bbox};
57 12         56 $self;
58             }
59              
60             #--------------------
61              
62 7     7 1 5312 sub nrPoints() { scalar @{ $_[0]->{MP_points}} }
  7         52  
63              
64              
65 1     1 1 2 sub order() { @{ $_[0]->{MP_points}} -1 }
  1         7  
66              
67              
68             sub points(;$)
69 15     15 1 36 { my ($self, $format) = @_;
70 15         35 my $points = $self->{MP_points};
71 15 100       52 $points = [ polygon_format $format, @$points ] if $format;
72 15 100       97 wantarray ? @$points : $points;
73             }
74              
75              
76             sub point(@)
77 3     3 1 2033 { my $points = shift->{MP_points};
78 3 100       13 wantarray ? @{$points}[@_] : $points->[shift];
  1         6  
79             }
80              
81             #--------------------
82              
83             sub bbox()
84 0     0 1 0 { my $self = shift;
85 0 0       0 return @{$self->{MP_bbox}} if $self->{MP_bbox};
  0         0  
86              
87 0         0 my @bbox = polygon_bbox $self->points;
88 0         0 $self->{MP_bbox} = \@bbox;
89 0         0 @bbox;
90             }
91              
92              
93             sub area()
94 1     1 1 2 { my $self = shift;
95 1 50       6 return $self->{MP_area} if defined $self->{MP_area};
96 1         5 $self->{MP_area} = polygon_area $self->points;
97             }
98              
99              
100             sub centroid(%)
101 0     0 1 0 { my ($self, %args) = @_;
102 0   0     0 $self->{MP_centroid} //= polygon_centroid \%args, $self->points;
103             }
104              
105              
106             sub isClockwise()
107 3     3 1 9 { my $self = shift;
108 3 100       19 return $self->{MP_clockwise} if defined $self->{MP_clockwise}; # undef == unknown here
109 1   50     4 $self->{MP_clockwise} = (polygon_is_clockwise $self->points) || 0;
110             }
111              
112              
113             sub clockwise()
114 0     0 1 0 { my $self = shift;
115 0 0       0 return $self if $self->isClockwise;
116              
117 0         0 $self->{MP_points} = [ reverse $self->points ];
118 0         0 $self->{MP_clockwise} = 1;
119 0         0 $self;
120             }
121              
122              
123             sub counterClockwise()
124 0     0 1 0 { my $self = shift;
125 0 0       0 $self->isClockwise or return $self;
126              
127 0         0 $self->{MP_points} = [ reverse $self->points ];
128 0         0 $self->{MP_clockwise} = 0;
129 0         0 $self;
130             }
131              
132              
133 0     0 1 0 sub perimeter() { polygon_perimeter $_[0]->points }
134              
135              
136             sub startMinXY()
137 2     2 1 8 { my $self = shift;
138 2         7 $self->new(polygon_start_minxy $self->points);
139             }
140              
141              
142             sub beautify(@)
143 0     0 1 0 { my ($self, %args) = @_;
144 0         0 my @beauty = polygon_beautify \%args, $self->points;
145 0 0       0 @beauty > 2 ? $self->new(points => \@beauty) : ();
146             }
147              
148              
149             sub equal($;@)
150 3     3 1 2000 { my $self = shift;
151 3         8 my ($other, $tolerance);
152 3 100 66     14 if(@_ > 2 || ref $_[1] eq 'ARRAY') { $other = \@_ }
  2         6  
153             else
154 1 50       7 { $other = ref $_[0] eq 'ARRAY' ? shift : shift->points;
155 1         3 $tolerance = shift;
156             }
157 3         10 polygon_equal scalar($self->points), $other, $tolerance;
158             }
159              
160              
161             sub same($;@)
162 2     2 1 5 { my $self = shift;
163 2         5 my ($other, $tolerance);
164 2 50 33     11 if(@_ > 2 || ref $_[1] eq 'ARRAY') { $other = \@_ }
  2         5  
165             else
166 0 0       0 { $other = ref $_[0] eq 'ARRAY' ? shift : shift->points;
167 0         0 $tolerance = shift;
168             }
169 2         7 polygon_same scalar($self->points), $other, $tolerance;
170             }
171              
172              
173             sub contains($)
174 0     0 1 0 { my ($self, $point) = @_;
175 0         0 polygon_contains_point($point, $self->points);
176             }
177              
178              
179             sub distance($)
180 0     0 1 0 { my ($self, $point) = @_;
181 0         0 polygon_distance($point, $self->points);
182             }
183              
184              
185 0     0 1 0 sub isClosed() { polygon_is_closed($_[0]->points) }
186              
187             #--------------------
188              
189             sub resize(@)
190 0     0 1 0 { my ($self, %args) = @_;
191              
192 0         0 my $clockwise = $self->{MP_clockwise};
193 0 0       0 if(defined $clockwise)
194 0         0 { my %args = @_;
195 0   0     0 my $xscale = $args{xscale} || $args{scale} || 1;
196 0   0     0 my $yscale = $args{yscale} || $args{scale} || 1;
197 0 0       0 $clockwise = not $clockwise if $xscale * $yscale < 0;
198             }
199              
200 0         0 (ref $self)->new(
201             points => [ polygon_resize \%args, $self->points ],
202             clockwise => $clockwise,
203             # we could save the bbox calculation as well
204             );
205             }
206              
207              
208             sub move(%)
209 0     0 1 0 { my ($self, %args) = @_;
210              
211             (ref $self)->new(
212             points => [ polygon_move \%args, $self->points ],
213             clockwise => $self->{MP_clockwise},
214             bbox => $self->{MP_bbox},
215 0         0 );
216             }
217              
218              
219             sub rotate(%)
220 0     0 1 0 { my ($self, %args) = @_;
221              
222             (ref $self)->new(
223             points => [ polygon_rotate \%args, $self->points ],
224             clockwise => $self->{MP_clockwise},
225             # we could save the bbox calculation as well
226 0         0 );
227             }
228              
229              
230             sub grid(%)
231 0     0 1 0 { my ($self, %args) = @_;
232              
233             (ref $self)->new(
234             points => [ polygon_grid \%args, $self->points ],
235             clockwise => $self->{MP_clockwise},
236             # probably we could save the bbox calculation as well
237 0         0 );
238             }
239              
240              
241             sub mirror(@)
242 0     0 1 0 { my ($self, %args) = @_;
243              
244 0         0 my $clockwise = $self->{MP_clockwise};
245 0 0       0 $clockwise = not $clockwise if defined $clockwise;
246              
247 0         0 (ref $self)->new(
248             points => [ polygon_mirror \%args, $self->points ],
249             clockwise => $clockwise,
250             # we could save the bbox calculation as well
251             );
252             }
253              
254              
255             sub simplify(@)
256 0     0 1 0 { my ($self, %args) = @_;
257              
258             (ref $self)->new(
259             points => [ polygon_simplify \%args, $self->points ],
260             clockwise => $self->{MP_clockwise},
261             bbox => $self->{MP_bbox}, # protect bounds
262 0         0 );
263             }
264              
265             #--------------------
266              
267             sub lineClip($$$$)
268 1     1 1 5 { my ($self, @bbox) = @_;
269 1         6 polygon_line_clip \@bbox, $self->points;
270             }
271              
272              
273             sub fillClip1($$$$)
274 0     0 1 0 { my ($self, @bbox) = @_;
275 0         0 my @clip = polygon_fill_clip1 \@bbox, $self->points;
276 0 0       0 @clip ? $self->new(points => \@clip) : undef;
277             }
278              
279             #--------------------
280              
281             sub string(;$)
282 3     3 1 6984 { my ($self, $format) = @_;
283 3         13 polygon_string $self->points($format);
284             }
285              
286             1;