``````# Copyrights 2004-2018 by [Mark Overmeer].
#  For other contributors see ChangeLog.
# See the manual pages for details on the licensing terms.
# Pod stripped from pm file by OODoc 2.02.
# This code is part of distribution Math::Polygon.  Meta-POD processed with
# OODoc into POD and HTML manual-pages.  See README.md
# Copyright Mark Overmeer.  Licensed under the same terms as Perl itself.

package Math::Polygon;
use vars '\$VERSION';
\$VERSION = '1.10';

use strict;
use warnings;

use Math::Polygon::Calc;
use Math::Polygon::Clip;
use Math::Polygon::Transform;

sub new(@)
{   my \$thing = shift;
my \$class = ref \$thing || \$thing;

my @points;
my %options;
if(ref \$thing)
{   \$options{clockwise} = \$thing->{MP_clockwise};
}

while(@_)
{   if(ref \$_ eq 'ARRAY') {push @points, shift}
else { my \$k = shift; \$options{\$k} = shift }
}
\$options{_points} = \@points;

(bless {}, \$class)->init(\%options);
}

sub init(\$\$)
{   my (\$self, \$args) = @_;
\$self->{MP_points}    = \$args->{points} || \$args->{_points};
\$self->{MP_clockwise} = \$args->{clockwise};
\$self->{MP_bbox}      = \$args->{bbox};
\$self;
}

#------------------

sub nrPoints() { scalar @{shift->{MP_points}} }

sub order() { @{shift->{MP_points}} -1 }

sub points(;\$)
{   my (\$self, \$format) = @_;
my \$points = \$self->{MP_points};
\$points    = [ polygon_format \$format, @\$points ] if \$format;
wantarray ? @\$points : \$points;
}

sub point(@)
{   my \$points = shift->{MP_points};
wantarray ? @{\$points}[@_] : \$points->[shift];
}

#------------------

sub bbox()
{   my \$self = shift;
return @{\$self->{MP_bbox}} if \$self->{MP_bbox};

my @bbox = polygon_bbox \$self->points;
\$self->{MP_bbox} = \@bbox;
@bbox;
}

sub area()
{   my \$self = shift;
return \$self->{MP_area} if defined \$self->{MP_area};
\$self->{MP_area} = polygon_area \$self->points;
}

sub centroid()
{   my \$self = shift;
return \$self->{MP_centroid} if \$self->{MP_centroid};
\$self->{MP_centroid} = polygon_centroid \$self->points;
}

sub isClockwise()
{   my \$self = shift;
return \$self->{MP_clockwise} if defined \$self->{MP_clockwise};
\$self->{MP_clockwise} = polygon_is_clockwise \$self->points;
}

sub clockwise()
{   my \$self = shift;
return \$self if \$self->isClockwise;

\$self->{MP_points}    = [ reverse \$self->points ];
\$self->{MP_clockwise} = 1;
\$self;
}

sub counterClockwise()
{   my \$self = shift;
return \$self unless \$self->isClockwise;

\$self->{MP_points}    = [ reverse \$self->points ];
\$self->{MP_clockwise} = 0;
\$self;
}

sub perimeter() { polygon_perimeter shift->points }

sub startMinXY()
{   my \$self = shift;
\$self->new(polygon_start_minxy \$self->points);
}

sub beautify(@)
{   my (\$self, %opts) = @_;
my @beauty = polygon_beautify \%opts, \$self->points;
@beauty > 2 ? \$self->new(points => \@beauty) : ();
}

sub equal(\$;@)
{   my \$self  = shift;
my (\$other, \$tolerance);
if(@_ > 2 || ref \$_ eq 'ARRAY') { \$other = \@_ }
else
{   \$other     = ref \$_ eq 'ARRAY' ? shift : shift->points;
\$tolerance = shift;
}
polygon_equal scalar(\$self->points), \$other, \$tolerance;
}

sub same(\$;@)
{   my \$self = shift;
my (\$other, \$tolerance);
if(@_ > 2 || ref \$_ eq 'ARRAY') { \$other = \@_ }
else
{   \$other     = ref \$_ eq 'ARRAY' ? shift : shift->points;
\$tolerance = shift;
}
polygon_same scalar(\$self->points), \$other, \$tolerance;
}

sub contains(\$)
{   my (\$self, \$point) = @_;
polygon_contains_point(\$point, \$self->points);
}

sub distance(\$)
{   my (\$self, \$point) = @_;
polygon_distance(\$point, \$self->points);
}

sub isClosed() { polygon_is_closed(shift->points) }

#------------------

sub resize(@)
{   my \$self = shift;

my \$clockwise = \$self->{MP_clockwise};
if(defined \$clockwise)
{   my %args   = @_;
my \$xscale = \$args{xscale} || \$args{scale} || 1;
my \$yscale = \$args{yscale} || \$args{scale} || 1;
\$clockwise = not \$clockwise if \$xscale * \$yscale < 0;
}

(ref \$self)->new
( points    => [ polygon_resize @_, \$self->points ]
, clockwise => \$clockwise
# we could save the bbox calculation as well
);
}

sub move(@)
{   my \$self = shift;

(ref \$self)->new
( points    => [ polygon_move @_, \$self->points ]
, clockwise => \$self->{MP_clockwise}
, bbox      => \$self->{MP_bbox}
);
}

sub rotate(@)
{   my \$self = shift;

(ref \$self)->new
( points    => [ polygon_rotate @_, \$self->points ]
, clockwise => \$self->{MP_clockwise}
# we could save the bbox calculation as well
);
}

sub grid(@)
{   my \$self = shift;

(ref \$self)->new
( points    => [ polygon_grid @_, \$self->points ]
, clockwise => \$self->{MP_clockwise}  # probably
# we could save the bbox calculation as well
);
}

sub mirror(@)
{   my \$self = shift;

my \$clockwise = \$self->{MP_clockwise};
\$clockwise    = not \$clockwise if defined \$clockwise;

(ref \$self)->new
( points    => [ polygon_mirror @_, \$self->points ]
, clockwise => \$clockwise
# we could save the bbox calculation as well
);
}

sub simplify(@)
{   my \$self = shift;

(ref \$self)->new
( points    => [ polygon_simplify @_, \$self->points ]
, clockwise => \$self->{MP_clockwise}  # probably
, bbox      => \$self->{MP_bbox}       # protect bounds
);
}

#------------------

sub lineClip(\$\$\$\$)
{   my (\$self, @bbox) = @_;
polygon_line_clip \@bbox, \$self->points;
}

sub fillClip1(\$\$\$\$)
{   my (\$self, @bbox) = @_;
my @clip = polygon_fill_clip1 \@bbox, \$self->points;
@clip or return undef;
\$self->new(points => \@clip);
}

#-------------

sub string(;\$)
{   my (\$self, \$format) = @_;
polygon_string(\$self->points(\$format));
}

1;
``````