#
# Name: Polygon.pm
# Purpose: Manipulate and draw polygons on wxPerl
# Author: Hans Oesterholt-Dijkema
# Modified by:
# Created: 19-4-2004
# RCS-ID: $Id: Polygon.pm,v 1.3 2004/04/20 08:59:36 cvs Exp $
# Copyright: (c) 2004 Hans Oesterholt-Dijkema
# Licence: This program is free software; you can redistribute it and/or
# modify it under Artistic license
#
package Wx::Polygon;
use Wx qw(:everything);
use strict;
our $VERSION='0.06';
my $pi2_360=(2.0*3.1459265)/360.0;
##############################################################
# Boot the C part
##############################################################
#use Wx::PolygonCalc;
Wx::wx_boot( 'Wx::Polygon', $VERSION );
##############################################################
# Construction
##############################################################
sub new {
my $class=shift;
my $args = {
POLYGON => undef,
ELLIPSE => undef,
@_
};
my $self;
my $def=0;
$self->{'defined'}=0;
bless $self,$class;
if (defined $args->{'POLYGON'}) {
$self->{'polygon'}=$args->{'POLYGON'};
$def=1;
}
if (defined $args->{'ELLIPSE'}) {
$self->{'polygon'}=$self->generate_ellipse(@{$args->{'ELLIPSE'}});
$def=1;
}
if (not $def) {
die "You need to specify one of the possible initializations (POLYGON, ELLIPSE, etc)";
}
$self->{'degrees'}=0;
$self->{'x-off'}=0;
$self->{'y-off'}=0;
$self->{'scale'}=1.0;
my @save;
for my $p (@{$self->{'polygon'}}) {
my $s=new Wx::Point($p->x,$p->y);
push @save,$s;
}
$self->{'saved'}=\@save;
$self->{'points'}=scalar @save;
$self->{'color'}=new Wx::Brush(new Wx::Colour(255,255,255),wxSOLID);
return $self;
}
sub copy {
my ($self)=@_;
my $pol=$self->{'polygon'};
my @p;
for my $point (@{$pol}) {
push @p,$point;
}
my $npol=new Wx::Graphics( 'POLYGON' => \@p );
$npol->recalc();
if (defined $self->{'rgb.r'}) {
$npol->set_color($self->{'rgb.r'},
$self->{'rgb.g'},
$self->{'rgb.b'}
);
}
return $npol;
}
sub generate_ellipse {
my ($self,$x,$y,$w,$h)=@_;
my $r=0;
my $step=1;
my $d;
my @pol;
for($d=0;$d<360;$d+=$step) {
my $px=$w*cos($pi2_360*$d);
my $py=$h*sin($pi2_360*$d);
my $p=new Wx::Point($x+$px,$y+$py);
push @pol,$p;
}
return \@pol;
}
sub add_point {
my ($self,$x,$y,$recalc)=@_;
if (not defined $recalc) { $recalc=1; }
my $p=new Wx::Point($x,$y);
push @{$self->{'polygon'}},$p;
push @{$self->{'saved'}},$p;
$self->{'points'}+=1;
if ($recalc) { $self->recalc(); }
}
##############################################################
# Drawing
##############################################################
sub draw {
my ($self,$dc)=@_;
my $xoff=$self->{'x-off'};
my $yoff=$self->{'y-off'};
$dc->SetBrush($self->{'color'});
$dc->DrawPolygon($self->{'polygon'},$xoff,$yoff);
$dc->SetBrush(wxNullBrush);
}
##############################################################
# Setting properties
##############################################################
sub scale {
my ($self,$scale)=@_;
$self->{'scale'}=$scale;
$self->recalc();
}
# for my $p (@{$self->{'saved'}}) {
# my $np=new Wx::Point($p->x*$scale,$p->y*$scale);
# push @n,$np;
# }
# $self->{'polygon'}=\@n;
# }
sub rotate {
my ($self,$deg)=@_;
$self->{'degrees'}=$deg;
$self->recalc();
}
# c_calculate($self->{'points'},$deg,$self->{'saved'},$self->{'polygon'});
# my $C=cos($pi2_360*$deg);
# my $S=sin($pi2_360*$deg);
# my @n;
# $self->{'rotate'}=$deg;
# for my $p (@{$self->{'saved'}}) {
# my $x=$p->x;
# my $y=$p->y;
# my $np=new Wx::Point($x*$C-$y*$S,$x*$S+$y*$C);
# push @n,$np;
# }
# $self->{'polygon'}=\@n;
# }
sub offset {
my ($self,$x,$y)=@_;
$self->{'x-off'}=$x;
$self->{'y-off'}=$y;
}
sub set_color {
my ($self,$r,$g,$b)=@_;
$self->{'rbg.r'}=$r;
$self->{'rgb.g'}=$g;
$self->{'rgb.b'}=$b;
$self->{'color'}=new Wx::Brush(new Wx::Colour($r,$g,$b),wxSOLID);
}
##############################################################
# Calculations (the C part)
##############################################################
sub recalc {
my $self=shift;
# Wx::PolygonCalc::C_RotateAndScale(
Wx::Polygon::C_RotateAndScale(
$self->{'points'},
$self->{'scale'},
$self->{'scale'},
$self->{'degrees'},
$self->{'saved'},
$self->{'polygon'}
);
}
sub mid {
my ($self)=@_;
my $midx;
my $midy;
my @M;
Wx::Polygon::C_FindMid(
$self->{'points'},
$self->{'polygon'},
$self->{'x-off'},$self->{'y-off'},
\@M
);
return @M;
# my ($minx,$miny,$maxx,$maxy)=(30000,30000,-30000,-30000);
# for my $p (@{$self->{'polygon'}}) {
# if ($minx>$p->x) { $minx=$p->x; }
# if ($maxx<$p->x) { $maxx=$p->x; }
# if ($miny>$p->y) { $miny=$p->y; }
# if ($maxy<$p->y) { $maxy=$p->y; }
# }
# return ( $self->{'x-off'}+(($maxx-$minx)/2+$minx), $self->{'y-off'}+(($maxy-$miny)/2+$miny) );
}
sub in {
my ($self,$x,$y)=@_;
# return Wx::PolygonCalc::C_In(
return Wx::Polygon::C_In(
$self->{'points'},
$self->{'polygon'},
$x,$y,
$self->{'x-off'},$self->{'y-off'}
);
# my $yes=0;
# my $i;
# my $j;
# $x-=$self->{'x-off'};
# $y-=$self->{'y-off'};
# my $N=scalar @{$self->{'polygon'}};
# my $pol=$self->{'polygon'};
# for ($i=0,$j=$N-1;$i<$N;$j=$i++) {
# my $ypi=$pol->[$i]->y;
# my $ypj=$pol->[$j]->y;
# my $xpi=$pol->[$i]->x;
# my $xpj=$pol->[$j]->x;
# if (((($ypi<=$y) and ($y<$ypj)) or
# (($ypj<=$y) and ($y<$ypi))) and
# ($x<($xpj-$xpi)*($y-$ypi)/($ypj-$ypi)+$xpi)) {
# $yes=!$yes;
# }
# }
# if ($yes) {
# return 1;
# }
# else {
# return 0;
# }
}
1;
__END__
=head1 NAME
Wx::Polygon - Draw and manipulate polygons for wxPerl
=head1 ABSTRACT
This module provides functions for manipulating polygons
in wxPerl.
=head1 Description
=head2 C<new( POLYGON => \(Wx::Point,...) | ELLIPSE => \(x_offset,y_offset,width,heigth) ) --E<gt> Wx::Polygon>
Instantiates a new Wx::Polygon with an array of Wx::Points for a given
C<POLYGON> or an ellipse with given parameters.
=head2 C<add_point(x,y,recalc=1) --E<gt> void>
Adds a point to the polygon. If scale and rotation have
been used, rescales and rerotates the polygon after adding
the point. If C<recalc> is set to C<0>, this will not
be done, which is better when a lot of points need added.
=head2 C<recalc() --E<gt> void>
Rescales and rerotates the polygon. This method should be
used when a lot of points need to be added. Recalculation
can than be done after adding the points.
=head2 C<set_color(r,g,b) --E<gt> void>
Sets the fill color to wxSOLID with the given C<r>, C<g>
and C<b> values.
=head2 C<mid() --E<gt> (midx:integer,midy:integer)>
Calculates the middle of the polygon (not point 'z') and
returns a list with x and y position.
=head2 C<in(x,y) --E<gt> boolean>
Calculates if (x,y) falls within the edges of the polygon.
Returns true if so. Uses algorithm of Randolph Franklin,
L<http://astronomy.swin.edu.au/~pbourke/geometry/insidepoly>.
=head2 C<draw( dc:Wx::DC ) --E<gt> void>
Draws the polygon at given offsets and with given colour(s) to
the current DC.
=head2 C<copy() --E<gt> Wx::Polygon>
Returns a copy of the object.
=head2 C<scale(scale-factor) --E<gt> void>
Scales the polygon with C<scale-factor>.
=head2 C<rotate(degrees) --E<gt> void>
Rotates the polygon by C<degrees> degrees (0-360).
=head2 C<offset(x,y) --E<gt> void>
Sets the offset for drawing. This can be used to
transpose the polygon.
=head1 AUTHOR
Hans Oesterholt-Dijkema <oesterhol@cpan.org>
=head1 COPYRIGHT & LICENSE
(c)2004 Hans Oesterholt-Dijkema. This module can be
redistributed under artistic license.
=cut