#*** Calculation.pm ***#
# Copyright (C) 2006 by Torsten Knorr
# create-soft@tiscali.de
# All rights reserved!
#-------------------------------------------------
 package Tk::Image::Calculation;
#-------------------------------------------------
 use strict;
 use warnings;
#-------------------------------------------------
 $Tk::Image::Calculation::VERSION = '0.04';
#-------------------------------------------------
 sub new
 	{
 	my ($class, @args) = @_;
 	my $self = {@args};
 	bless($self, $class || ref($class));
=head1
 -form	=> circle oval polygon
 -points	=> [x1, y1, x2, y2]
 -subset	=> all points_outside points_inside lines_outside lines_inside
=cut
#-------------------------------------------------
 if(defined($self->{-points}) && defined($self->{-form}))
 {
 FORM:
 	{
 	$self->{-subset} = "all" if(!(defined($self->{-subset})));
 	($self->{-form} eq "oval")		&& do
 		{
 		OVAL:
 			{
 			($self->{-subset} eq "lines_outside")	&& do
 				{
 				$self->GetLinesOutOval(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "points_outside")	&& do 
 				{
 				$self->GetPointsOutOval(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "points_inside")	&& do
 				{
 				$self->GetPointsInOval(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "lines_inside")	&& do
 				{
 				$self->GetLinesInOval(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "all")		&& do
 				{
 				$self->GetPointsOval(@{$self->{-points}});
 				last(FORM);
 				};
 			}
 		};
 	($self->{-form} eq "circle")		&& do
 		{
 		CIRCLE:
 			{
			($self->{-subset} eq "lines_outside")	&& do
 				{
 				$self->GetLinesOutCircle(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "points_outside")	&& do
 				{
 				$self->GetPointsOutCircle(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "points_inside")	&& do
 				{
 				$self->GetPointsInCircle(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "lines_inside")	&& do
 				{
 				$self->GetLinesInCircle(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "all")		&& do
 				{
 				$self->GetPointsCircle(@{$self->{-points}});
 				last(FORM);
 				};
 			}
 		};
 	($self->{-form} eq "polygon")	&& do
 		{
 		POLYGON:
 			{
 			($self->{-subset} eq "lines_outside")	&& do
 				{
 				$self->GetLinesOutPolygon(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "points_outside") && do
 				{
 				$self->GetPointsOutPolygon(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "lines_inside")	&& do
 				{
 				$self->GetLinesInPolygon(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "points_inside")	&& do
 				{
 				$self->GetPointsInPolygon(@{$self->{-points}});
 				last(FORM);
 				};
 			($self->{-subset} eq "all")		&& do
 				{
 				$self->GetPointsPolygon(@{$self->{-points}});
 				last(FORM);
 				};
 			}
 		};
 	warn("wrong args in call to Tk::Image::Calculation::new()\n");
 	} 		
 }
#-------------------------------------------------
 	return($self);
 	}
#-------------------------------------------------
# OVAL
#-------------------------------------------------
 sub GetPointsOval
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my (@points_out, @points_in, @lines_out, @lines_in);
 	my ($pos_x_p, $pos_x_n, $pos_y1, $pos_y2);
 	my ($y, $y1, $y2);
 	my $diff;
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2);
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{points_outside}	= [];
 		$self->{points_inside}	= [];
 		$self->{lines_outside}	= [];
 		$self->{lines_inside}	= [];
 		return({
 			points_outside	=> [],
 			points_inside	=> [],
 			lines_outside	=> [],
 			lines_inside	=> []
 			});
 		}
 	my $a = ($width / 2);
 	my $a2  = $a ** 2;
 	my $b = ($height / 2);
 	my $c = ($b / $a);
 	my $pos_x = ($a + $p_x1);
 	for(my $x = 0; $x <= $a; $x++)
 		{
 		$diff = int($c * sqrt($a2 - ($x ** 2)));
 		$y1 = ($b - $diff);
 		$y2 = ($b + $diff);
 		$pos_y1 = ($y1 + $p_y1);
 		$pos_y2 = ($y2 + $p_y1);
		$pos_x_p = int($x + $pos_x);
 		$pos_x_n = int(-$x + $pos_x);
 		push(@lines_out, [$pos_x_p, $p_y1, $pos_x_p, $pos_y1]);
 		push(@lines_out, [$pos_x_n, $p_y1, $pos_x_n, $pos_y1]);
		push(@lines_in, [$pos_x_p, $pos_y1, $pos_x_p, $pos_y2]);
 		push(@lines_in, [$pos_x_n, $pos_y1, $pos_x_n, $pos_y2]);
 		push(@lines_out, [$pos_x_p, $pos_y2, $pos_x_p, $p_y2]);
 		push(@lines_out, [$pos_x_n, $pos_y2, $pos_x_n, $p_y2]);
 		for($y = 0; $y <= $y1; $y++)
 			{
 			$pos_y1 = ($y + $p_y1);
			push(@points_out, [$pos_x_p, $pos_y1]);
			push(@points_out, [$pos_x_n, $pos_y1]);
 			} 
 		for($y = $y1; $y <= $y2; $y++)
 			{
 			$pos_y1 = ($y + $p_y1);
 			push(@points_in, [$pos_x_p, $pos_y1]);
 			push(@points_in, [$pos_x_n, $pos_y1]);
 			}
 		for($y = $y2; $y <= $height; $y++)
 			{
 			$pos_y1 = ($y + $p_y1);
 			push(@points_out, [$pos_x_p, $pos_y1]);
 			push(@points_out, [$pos_x_n, $pos_y1]);
 			}
 		}
 	$self->{points_outside}	= \@points_out;
 	$self->{points_inside}	= \@points_in;
 	$self->{lines_outside}	= \@lines_out;
 	$self->{lines_inside}	= \@lines_in;
 	return({
 		points_outside	=> \@points_out, 
 		points_inside	=> \@points_in, 
 		lines_outside	=> \@lines_out, 
 		lines_inside	=> \@lines_in
 		});
 	}
#-------------------------------------------------
 sub GetPointsInOval
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my ($pos_x_p, $pos_x_n, $pos_y1);
 	my ($y, $y1, $y2);
 	my $diff;
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2);
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{points_inside} = [];
 		return([]);
 		}
 	my $a = ($width / 2);
 	my $a2  = ($a**2);
 	my $b = ($height / 2);
 	my $c = ($b / $a);
 	my $pos_x = ($a + $p_x1);
 	my @points_in;
 	for(my $x = 0; $x <= $a; $x++)
 		{
 		$diff = int($c * sqrt($a2 - ($x**2)));
 		$y1 = ($b - $diff);
 		$y2 = ($b + $diff);
		$pos_x_p = int($x + $pos_x);
 		$pos_x_n = int(-$x + $pos_x);
 		for($y = $y1; $y <= $y2; $y++)
 			{
 			$pos_y1 = ($y + $p_y1);
 			push(@points_in, [$pos_x_p, $pos_y1]);
 			push(@points_in, [$pos_x_n, $pos_y1]);
 			}
 		}
 	$self->{points_inside} = \@points_in;
 	return(\@points_in);
 	}
#-------------------------------------------------
 sub GetPointsOutOval
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my ($pos_x_p, $pos_x_n, $pos_y1);
 	my ($y, $y1, $y2);
 	my $diff;
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2);
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{points_outside} = [];
 		return([]);
 		}
 	my $a = ($width / 2);
 	my $a2  = ($a**2);
 	my $b = ($height / 2);
 	my $c = ($b / $a);
 	my $pos_x = ($a + $p_x1);
 	my @points_out;
 	for(my $x = 0; $x <= $a; $x++)
 		{
 		$diff = int($c * sqrt($a2 - ($x**2)));
 		$y1 = ($b - $diff);
 		$y2 = ($b + $diff);
		$pos_x_p = int($x + $pos_x);
 		$pos_x_n = int(-$x + $pos_x);
 		for($y = 0; $y <= $y1; $y++)
 			{
 			$pos_y1 = ($y + $p_y1);
			push(@points_out, [$pos_x_p, $pos_y1]);
			push(@points_out, [$pos_x_n, $pos_y1]);
 			} 
 		for($y = $y2; $y <= $height; $y++)
 			{
 			$pos_y1 = ($y + $p_y1);
 			push(@points_out, [$pos_x_p, $pos_y1]);
 			push(@points_out, [$pos_x_n, $pos_y1]);
 			}
 		}
 	$self->{points_outside} = \@points_out;
 	return(\@points_out);
 	}
#-------------------------------------------------
 sub GetLinesInOval
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my ($pos_x_p, $pos_x_n, $pos_y1, $pos_y2);
 	my ($y, $y1, $y2);
 	my $diff;
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2);
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{lines_inside} = [];
 		return([]);
 		}
 	my $a = ($width / 2);
 	my $a2  = ($a**2);
 	my $b = ($height / 2);
 	my $c = ($b / $a);
 	my $pos_x = ($a + $p_x1);
 	my @lines_in;
 	for(my $x = 0; $x <= $a; $x++)
 		{
 		$diff = int($c * sqrt($a2 - ($x**2)));
 		$y1 = ($b - $diff);
 		$y2 = ($b + $diff);
		$pos_x_p = int($x + $pos_x);
 		$pos_x_n = int(-$x + $pos_x);
 		$pos_y1 = ($y1 + $p_y1);
 		$pos_y2 = ($y2 + $p_y1);
 		push(@lines_in, [$pos_x_p, $pos_y1, $pos_x_p, $pos_y2]);
 		push(@lines_in, [$pos_x_n, $pos_y1, $pos_x_n, $pos_y2]);
 		}
 	$self->{lines_inside} = \@lines_in;
 	return(\@lines_in);
 	}
#-------------------------------------------------
 sub GetLinesOutOval
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my ($pos_x_p, $pos_x_n, $pos_y1, $pos_y2);
 	my ($y, $y1, $y2);
 	my $diff;
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2);
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{lines_outside} = [];
 		return([]);
 		}
 	my $a = ($width / 2);
 	my $a2  = ($a**2);
 	my $b = ($height / 2);
 	my $c = ($b / $a);
 	my $pos_x = ($a + $p_x1);
 	my @lines_out;
 	for(my $x = 0; $x <= $a; $x++)
 		{
 		$diff = int($c * sqrt($a2 - ($x**2)));
 		$y1 = ($b - $diff);
 		$y2 = ($b + $diff);
		$pos_x_p = int($x + $pos_x);
 		$pos_x_n = int(-$x + $pos_x);
 		$pos_y1 = ($y1 + $p_y1);
 		$pos_y2 = ($y2 + $p_y1);
 		push(@lines_out, [$pos_x_p, $p_y1, $pos_x_p, $pos_y1]);
 		push(@lines_out, [$pos_x_n, $p_y1, $pos_x_n, $pos_y1]); 
 		push(@lines_out, [$pos_x_p, $pos_y2, $pos_x_p, $p_y2]);
 		push(@lines_out, [$pos_x_n, $pos_y2, $pos_x_n, $p_y2]);
 		}
 	$self->{lines_outside} = \@lines_out;
 	return(\@lines_out);
 	}
#-------------------------------------------------
# CIRCLE
#-------------------------------------------------
 sub GetPointsCircle
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my (@points_out, @points_in, @lines_out, @lines_in);
 	my ($x2py2, $pos_x, $pos_y1, $pos_y2);
 	my ($i_x2, $i_y);
 	my $diff_y;
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2); 
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{points_outside}	= [];
 		$self->{points_inside}	= [];
 		$self->{lines_outside}	= [];
 		$self->{lines_inside}	= [];
 		return({
 			points_outside	=> [],
 			points_inside	=> [],
 			lines_outside	=> [],
 			lines_inside	=> []
 			});
 		}
 	my $r = int($width / 2);
 	my $r2 = ($r**2);  
 	my $coord_x = ($p_x1 + $r);
 	my $coord_y = ($p_y1 + $r);
 	for(my $i_x = -$r; $i_x <= $r; $i_x++)
 		{
 		$i_x2 = ($i_x ** 2);
 		$diff_y = int(sqrt($r2 - $i_x2));
		$pos_x = ($coord_x + $i_x);
 		$pos_y1 = ($coord_y + $diff_y);
 		$pos_y2 = ($coord_y - $diff_y);
 		push(@lines_out, [$pos_x, $p_y1, $pos_x, $pos_y2]);
 		push(@lines_out, [$pos_x, $pos_y1, $pos_x, $p_y2]);
 		push(@lines_in, [$pos_x, $pos_y2, $pos_x, $pos_y1]);
 		for($i_y = $r; $i_y >= -$r; $i_y--)
 			{
 			$pos_y1 = ($coord_y + $i_y);
 			$x2py2 = ($i_x2 + ($i_y ** 2));
 			if($x2py2 < $r2)
 				{
 				push(@points_in, [$pos_x, $pos_y1]);
 				}
 			elsif($x2py2 > $r2)
 				{
 				push(@points_out, [$pos_x, $pos_y1]);
 				}
 			} 
 		}
 	$self->{points_outside}	= \@points_out;
 	$self->{points_inside}	= \@points_in;
 	$self->{lines_outside}	= \@lines_out;
 	$self->{lines_inside}	= \@lines_in;
 	return({
 		points_outside	=> \@points_out,
 		points_inside	=>  \@points_in, 
 		lines_outside	=> \@lines_out, 
 		lines_inside	=> \@lines_in
 		});
 	}
#-------------------------------------------------
 sub GetPointsInCircle
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my ($x2py2, $i_y);
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2); 
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{points_inside} = [];
 		return([]);
 		}
 	my $r = int($width / 2);
 	my $r2 = ($r ** 2);  
 	my $coord_x = ($p_x1 + $r);
 	my $coord_y = ($p_y1 + $r);
 	my @points_in;
 	for(my $i_x = -$r; $i_x <= $r; $i_x++)
 		{
 		for($i_y = $r; $i_y >= -$r; $i_y--)
 			{
 			$x2py2 = (($i_x ** 2) + ($i_y ** 2));
 			if($x2py2 < $r2)
 				{
 				push(@points_in, [($coord_x + $i_x), ($coord_y + $i_y)]);
 				} 			
 			} 
 		}
 	$self->{points_inside} = \@points_in;
 	return(\@points_in);
 	}
#-------------------------------------------------
 sub GetPointsOutCircle
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my ($x2py2, $i_y);
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2); 
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{points_outside} = [];
 		return([]);
 		}
 	my $r = int($width / 2);
 	my $r2 = ($r ** 2);  
 	my $coord_x = ($p_x1 + $r);
 	my $coord_y = ($p_y1 + $r);
 	my @points_out;
 	for(my $i_x = -$r; $i_x <= $r; $i_x++)
 		{
 		for($i_y = $r; $i_y >= -$r; $i_y--)
 			{
 			$x2py2 = (($i_x ** 2) + ($i_y ** 2));
 			if($x2py2 > $r2)
 				{
 				push(@points_out, [($coord_x + $i_x), ($coord_y + $i_y)]);
 				}
 			} 
 		}
 	$self->{points_outside} = \@points_out;
 	return(\@points_out);
 	}
#-------------------------------------------------
 sub GetLinesInCircle
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my ($x2py2, $pos_x, $diff_y);
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2); 
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{lines_inside} = [];
 		return([]);
 		}
 	my $r = int($width / 2);
 	my $r2 = ($r ** 2);  
 	my $coord_x = ($p_x1 + $r);
 	my $coord_y = ($p_y1 + $r);
 	my @lines_in;
 	for(my $i_x = -$r; $i_x <= $r; $i_x++)
 		{
 		$pos_x = ($coord_x + $i_x);
 		$diff_y = int(sqrt($r2 - ($i_x ** 2)));
 		push(@lines_in, [$pos_x, ($coord_y - $diff_y), $pos_x, ($coord_y + $diff_y)]);
 		}
 	$self->{lines_inside} = \@lines_in;
 	return(\@lines_in);
 	}
#-------------------------------------------------
 sub GetLinesOutCircle
 	{
 	my ($self, $p_x1, $p_y1, $p_x2, $p_y2) = @_;
 	my ($x2py2, $pos_x, $diff_y);
 	($p_x1, $p_x2) = ($p_x2, $p_x1) if($p_x1 > $p_x2); 
 	($p_y1, $p_y2) = ($p_y2, $p_y1) if($p_y1 > $p_y2);
 	my $width = ($p_x2 - $p_x1);
 	my $height= ($p_y2 - $p_y1);
 	if(($width < 5) || ($height < 5))
 		{
 		$self->{lines_outside} = [];
 		return([]);
 		}
 	my $r = int($width / 2);
 	my $r2 = ($r ** 2);  
 	my $coord_x = ($p_x1 + $r);
 	my $coord_y = ($p_y1 + $r);
 	my @lines_out;
 	for(my $i_x = -$r; $i_x <= $r; $i_x++)
 		{
 		$pos_x = ($coord_x + $i_x);
 		$diff_y = int(sqrt($r2 - ($i_x ** 2)));
 		push(@lines_out, [$pos_x, $p_y1, $pos_x, ($coord_y - $diff_y)]);
 		push(@lines_out, [$pos_x, ($coord_y + $diff_y), $pos_x, $p_y2]);
 		}
 	$self->{lines_outside} = \@lines_out;
 	return(\@lines_out);
 	}
#-------------------------------------------------
# POLYGON
#-------------------------------------------------
 sub GetPointsPolygon
 	{
 	my ($self) = @_;
 	my $ref_p_x = _CalculatePolygon(@_);
 	my (@points_out, @points_in, @lines_out, @lines_in);
 	my $i_1 = my $i_2 = my $i_3 = 0;
 	my $p_x_temp;
 	for(my $p_y = $self->{min_y}; $p_y <= $self->{max_y}; $p_y++)
 		{
 		$p_x_temp = $self->{min_x};
 		for($i_2 = 0; $i_2 <= $#{$ref_p_x->[$i_1]}; $i_2 += 2)
 			{
 			push(@lines_in, [$ref_p_x->[$i_1][$i_2], $p_y, $ref_p_x->[$i_1][$i_2 + 1], $p_y]);
			for($i_3 = $ref_p_x->[$i_1][$i_2]; $i_3 <= $ref_p_x->[$i_1][$i_2 + 1]; $i_3++)
 				{
 				push(@points_in, [$i_3, $p_y]);
 				}
			push(@lines_out, [$p_x_temp, $p_y, $ref_p_x->[$i_1][$i_2], $p_y]);
 			for($i_3 = $p_x_temp; $i_3 <= $ref_p_x->[$i_1][$i_2]; $i_3++)
 				{
 				push(@points_out, [$i_3, $p_y]);
 				}
 			$p_x_temp = $ref_p_x->[$i_1][$i_2 + 1];
 			}
 		push(@lines_out, [$p_x_temp, $p_y, $self->{max_x}, $p_y]);
 		for($i_3 = $p_x_temp; $i_3 <= $self->{max_x}; $i_3++)
 			{
 			push(@points_out, [$i_3, $p_y]);
 			}
 		$i_1++;
 		}
 	$self->{lines_outside}	= \@lines_out;
 	$self->{lines_inside}	= \@lines_in;
 	$self->{points_outside}	= \@points_out;
 	$self->{points_inside}	= \@points_in;
 	return({
 		lines_outside	=> \@lines_out,
 		lines_inside	=> \@lines_in,
 		points_outside	=> \@points_out,
 		points_inside	=> \@points_in,
 		});
 	}
#-------------------------------------------------
 sub GetPointsInPolygon
 	{
 	my ($self) = @_;
 	my $ref_p_x = _CalculatePolygon(@_);
 	my @points_in = ();
 	my $i_1 = my $i_2 = my $i_3 = 0;
 	for(my $p_y = $self->{min_y}; $p_y <= $self->{max_y}; $p_y++)
 		{
 		for($i_2 = 0; $i_2 <= $#{$ref_p_x->[$i_1]}; $i_2 += 2)
 			{
 			for($i_3 = $ref_p_x->[$i_1][$i_2]; $i_3 <= $ref_p_x->[$i_1][$i_2 + 1]; $i_3++)
 				{
 				push(@points_in, [$i_3, $p_y]);
 				}
 			}
 		$i_1++;
 		}
 	$self->{points_inside} = \@points_in;
 	return(\@points_in);
 	}
#-------------------------------------------------
 sub GetPointsOutPolygon
 	{
 	my ($self) = @_;
 	my $ref_p_x = _CalculatePolygon(@_);
 	my @points_out = ();
 	my $i_1 = my $i_2 = my $i_3 = 0;
 	my $p_x_temp;
 	for(my $p_y = $self->{min_y}; $p_y <= $self->{max_y}; $p_y++)
 		{
 		$p_x_temp = $self->{min_x};
 		for($i_2 = 0; $i_2 <= $#{$ref_p_x->[$i_1]}; $i_2 += 2)
 			{
 			for($i_3 = $p_x_temp; $i_3 <= $ref_p_x->[$i_1][$i_2]; $i_3++)
 				{
 				push(@points_out, [$i_3, $p_y]);
 				}
 			$p_x_temp = $ref_p_x->[$i_1][$i_2 + 1];
 			}
 		for($i_3 = $p_x_temp; $i_3 <= $self->{max_x}; $i_3++)
 			{
 			push(@points_out, [$i_3, $p_y]);
 			}
 		$i_1++;
 		}
 	$self->{points_outside} = \@points_out;
 	return(\@points_out);
 	}
#-------------------------------------------------
 sub GetLinesInPolygon
 	{
 	my ($self) = @_;
 	my $ref_p_x = _CalculatePolygon(@_);
 	my @lines_in = ();
 	my $i_1 = my $i_2 = 0;
 	for(my $p_y = $self->{min_y}; $p_y <= $self->{max_y}; $p_y++)
 		{
 		for($i_2 = 0; $i_2 <= $#{$ref_p_x->[$i_1]}; $i_2 += 2)
 			{
 			push(@lines_in, [$ref_p_x->[$i_1][$i_2], $p_y, $ref_p_x->[$i_1][$i_2 + 1], $p_y]);
 			}
 		$i_1++;
 		}
 	$self->{lines_inside} = \@lines_in;
 	return(\@lines_in);
 	}
#-------------------------------------------------
 sub GetLinesOutPolygon
 	{
 	my ($self) = @_;
 	my $ref_p_x = _CalculatePolygon(@_);
 	my @lines_out = ();
 	my $i_1 = my $i_2 = 0;
 	my $p_x_temp;
 	for(my $p_y = $self->{min_y}; $p_y <= $self->{max_y}; $p_y++)
 		{
 		$p_x_temp = $self->{min_x};
 		for($i_2 = 0; $i_2 <= $#{$ref_p_x->[$i_1]}; $i_2 += 2)
 			{
 			push(@lines_out, [$p_x_temp, $p_y, $ref_p_x->[$i_1][$i_2], $p_y]);
 			$p_x_temp = $ref_p_x->[$i_1][$i_2 + 1];
 			}
 		push(@lines_out, [$p_x_temp, $p_y, $self->{max_x}, $p_y]);
 		$i_1++;
 		}
 	$self->{lines_outside} = \@lines_out;
 	return(\@lines_out);
 	}
#-------------------------------------------------
 sub _CalculatePolygon
 	{
 	my ($self, @points) = @_;
 	my @p;
 	for(my $i = 0; $i <= $#points; $i += 2)
 		{
 		push(@p, { x => $points[$i], y => $points[$i + 1]});
 		}
 	push(@p, {x => $points[0], y => $points[1]});
 	my $points_count = $#p;
 	return([]) if($points_count < 3);
 	my ($index_1, $index_2,  $index_count); 
 	my ($p_y, $p_y1, $p_y2, $p_x1, $p_x2, $p_x_temp);
 	my @points_outline_x = ();
 	my @all_points_outline_x = ();
 	my ($i, $j);
 	$self->{min_y} = $self->{max_y} = $p[0]{y};
 	$self->{min_x} = $self->{max_x} = $p[0]{x};
 	for(0..$#p)
 		{
 		$self->{min_y} = $p[$_]{y} if($self->{min_y} > $p[$_]{y});
 		$self->{max_y} = $p[$_]{y} if($self->{max_y} < $p[$_]{y});
 		$self->{min_x} = $p[$_]{x} if($self->{min_x} > $p[$_]{x});
 		$self->{max_x} = $p[$_]{x} if($self->{max_x} < $p[$_]{x});
 		}
 	for($p_y = $self->{min_y}; $p_y <= $self->{max_y}; $p_y++)
 		{
 		$index_count = 0;
 		@points_outline_x = ();
 		for($i = 0; $i < $points_count; $i++)
 			{
 			if(!$i)
 				{
 				$index_1 = $points_count - 1;	
 				$index_2 = 0;		
 				}
 			else
 				{
 				$index_1 = $i - 1;			
 				$index_2 = $i;	
 				}
 			$p_y1 = $p[$index_1]{y};
 			$p_y2 = $p[$index_2]{y};
 			if($p_y1 < $p_y2)
 				{
 				$p_x1 = $p[$index_1]{x};
 				$p_x2 = $p[$index_2]{x};
 				}
 			elsif ($p_y1 > $p_y2)
 				{
 				$p_y2 = $p[$index_1]{y};
 				$p_y1 = $p[$index_2]{y};
 				$p_x2 = $p[$index_1]{x};
 				$p_x1 = $p[$index_2]{x};
 				}
 			else
 				{
 				next;
 				}
 			if(($p_y >= $p_y1) && ($p_y < $p_y2))
 				{
 $points_outline_x[$index_count++] = int((($p_y - $p_y1) * ($p_x2 - $p_x1)) /  ($p_y2 - $p_y1) + 0.5 + $p_x1);
 				}
 			elsif(($p_y == $self->{max_y}) && ($p_y > $p_y1) && ($p_y <= $p_y2))
 				{
 $points_outline_x[$index_count++] = int((($p_y - $p_y1) * ($p_x2 - $p_x1)) / ($p_y2 - $p_y1) + 0.5 + $p_x1);
 				}
 			}
 		for($i = 1; $i < $index_count; $i++) 
 			{
 			$p_x_temp = $points_outline_x[$i];
 			$j = $i;
 			while(($j > 0) && ($points_outline_x[$j - 1] > $p_x_temp)) 
 				{
 				$points_outline_x[$j] = $points_outline_x[$j - 1];
 				$j--;
 				}
 			$points_outline_x[$j] = $p_x_temp;
 			}
 		push(@all_points_outline_x, [@points_outline_x]);
 		}
 	return(\@all_points_outline_x);
 	}
#-------------------------------------------------
1;
#-------------------------------------------------
__END__

=head1 NAME

Tk::Image::Calculation - Perl extension for graphic calculations

=head1 SYNOPSIS

#-------------------------------------------------
 use Tk::Image::Calculation;
 my @points_oval = (10, 10, 30, 50);
 my @points_circle = (20, 20, 60, 60);
 my @points_polygon = (136, 23, 231, 55, 463, 390, 338, 448, 182, 401, 148, 503, 15, 496, 9, 87);
# polygon = (x1, y1, x2, y2, x3, y3, x4, y4, ... and so on)
#-------------------------------------------------
 my $cal = Tk::Image::Calculation->new();	
 my $ref_array = $cal->GetPointsInOval(@points_oval);
# my $ref_array = $cal->GetPointsOutOval(@points_oval);
# my $ref_array = $cal->GetPointsInCircle(@points_circle);
# my $ref_array = $cal->GetPointsOutCircle(@points_circle);
# my $ref_array = $cal->GetPointsInPolygon(@points_polygon);
# my $ref_array = $cal->GetPointsOutPolygon(@points_polygon);
 for(@{$ref_array})
 	{
 	print("x:$_->[0]	y:$_->[1]\n");
 	}
 my $ref_array1 = $cal->GetLinesInOval(@points_oval);
# my $ref_array1 = $cal->GetLinesOutOval(@points_oval);
# my $ref_array1 = $cal->GetLinesInCircle(@points_circle);
# my $ref_array1 = $cal->GetLinesOutCircle(@points_circle);
# my $ref_array1 = $cal->GetLinesInPolygon(@points_polygon);
# my $ref_array1 = $cal->GetLinesOutPolygon(@points_polygon);
 for(@{$ref_array1})
 	{
 	print("x1:$_->[0]	y1:$_->[1]	x2:$_->[2]	y2:$_->[3]\n");
 	}
#-------------------------------------------------
 my $cal1 = Tk::Image::Calculation->new(
 	-points	=> \@points_circle,
 	-form	=> "circle", # or "oval" or "polygon"
 	);
 for my $subset ("points_inside", "points_outside")
 	{
 	print("\n$subset circle : \n");
 	for(@{$cal1->{$subset}})
 		{
 		print("x:$_->[0]	y:$_->[1]\n");
 		}
 	}
 for my $subset ("lines_inside", "lines_outside")
 	{
 	print("\n$subset circle : \n");
 	for(@{$cal1->{$subset}})
 		{
 		print("x1:$_->[0]	y1:$_->[1]	x2:$_->[2]	y2:$_->[3]\n");
 		}
 	}
#-------------------------------------------------
 my $cal2 = Tk::Image::Calculation->new(
 	-points => \@points_polygon, # need three points at least
 	-form	=> "polygon", 
 	-subset	=> "lines_outside", # defaults to "all"
 	);
 use Tk;
 my $mw = MainWindow->new();
 my $canvas = $mw->Canvas(
 	-width	=> 800,
 	-height	=> 600,
 	)->pack();
 for(@{$cal2->{lines_outside}})
 	{
 	$canvas->createLine(@{$_});
 	}
 MainLoop();
#-------------------------------------------------
 use Tk;
 use Tk::JPEG;
 my $mw = MainWindow->new();
 my $image = $mw->Photo(-file => "test.jpg");
 my $cal3 = Tk::Image::Calculation->new();
 my $ref_points = $cal3->GetPointsOutCircle(50, 50, 150,  150);
 $image->put("#FFFFFF", -to => $_->[0], $_->[1]) for(@{$ref_points});
 $image->write("new.jpg", -from => 50, 50, 150, 150);
#-------------------------------------------------

=head1 DESCRIPTION

 This module calculates points and lines inside or outside from simple graphic objects.
 At this time possible objects:
 	"oval",
 	"circle",
 	"polygon"

=head1 CONSTRUCTOR

=item my $object = Tk::Image::Calculation->new();

 Returns an empty object just for calling the methods.

=item my $object = Tk::Image::Calculation->new(
 	-points	=> [$x1, $y1, $x2, $y2],	# required
 	-form	=> "oval",		# required
 	-subset	=> "points_outside,	# optional
 	);
 -points	takes a arrayreference with points  required
 -form	takes one of the forms "oval", "circle" or "polygon" required
 -subset	takes one of the strings "points_outside", "points_inside", "lines_inside" or "lines_outside" 
 	optional defaults to "all"

 Returns a hashreference blessed as object with a key that was defined with the options -subset.
 The value of the key is an arrayreferences with points or lines.
 Points [x, y]
 Lines [x1, y1, x2, y2]
 Is the option -subset set to "all" the returned hash have the following keys.
 	"points_outside",
 	"points_inside",
 	"lines_outside",
 	"lines_inside"

=head1 METHODS

 Two points are handed over to the functions for Oval or Circle. 
 In the following form ($x1, $y1, $x2, $y2).
 The first point to the left up and the second point to the right below of a thought rectangle,
 in that the graphic object does fitting.
 The returned values are array references of points or lines.
 Points [x, y]
 Lines [x1, y1, x2, y2]

=item GetPointsOval

 Takes over two points as parameters.
 Returns a hashreferences with the following keys.
 	"points_outside", 
 	"points_inside",
 	"lines_outside", 
 	"lines_inside"
 The values of the keys are arrayreferences with points or lines. 

=item GetPointsInOval, GetPointsOutOval, GetLinesInOval, GetLinesOutOval

 Takes over two points as parameters.
 Returns a array reference of Points or Lines inside or outside of the Oval. 

=item GetPointsCircle

 Just the same as GetPointsOval.

=item GetPointsInCircle, GetPointsOutCircle, GetLinesInCircle, GetLinesOutCircle

 Takes over two points as parameters.
 Returns a array reference of Points or Lines inside or outside of the Circle. 

=item GetPointsPolygon

 Takes over a list of points in the following way.
 my @polygon = (x1, y1, x2, y2, x3, y3, x4, y4, ... and so on)
 my $ref_hash = $object->GetPointsPolygon(@polygon);
 Need at least three points.
 Returns a hashreferences with the following keys.
 	"points_outside", 
 	"points_inside",
 	"lines_outside", 
 	"lines_inside"
 The values of the keys are arrayreferences with points or lines. 

=item GetPointsInPolygon, GetPointsOutPolygon, GetLinesInPolygon, GetLinesOutPolygon

 Takes over a list with at least three points.
 Returns a array reference of Points or Lines inside or outside of the Circle.

=head2 EXPORT

 None by default.

=head1 SEE ALSO

 Tk::Image::Cut
 http://www.planet-interkom.de/t.knorr/index.html

=head1 KEYWORDS

 graphic, calculation 

=head1 	BUGS

 Maybe you'll find some. Please let me know.

=head1 AUTHOR

Torsten Knorr, E<lt>torstenknorr@tiscali.deE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2006 by Torsten Knorr

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.9.2 or,
at your option, any later version of Perl 5 you may have available.

=cut

