use strict;
use Tk;


###  大域変数宣言
#####################

my $R;
my $sR;
my $theta;

# 時間
my $t = 0;
my $dt = 1 / 100;

# メイングラフィクスサイズ	
my $gc_size = 500; 
my ( $gc_width , $gc_height ) = ( $gc_size*1.1 , $gc_size*1.1 );

# 各グラフィックスのスケール
my $scale1;
my $scale2;
my ( $Ox1, $Oy1 ) = ( $gc_width/4, $gc_height/4 );
my ( $Ox2, $Oy2 ) = ( $gc_width/2, $gc_height/2 );

# 関数の係数
my @a0 = (1,0);
my @a1 = (1,0);
my @a2 = (1,0);
my @a3 = (1,0);
my @a4 = (1,0);

###  大域変数宣言終わり
#####################


# グラフィカルオブジェクト作成
my $top_windw = MainWindow->new();
my $start_button = $top_windw->Button( -text => 'Start/Stop', -command => [\&start_animation]  )->pack();
my $graph_frame = $top_windw->Frame()->pack();
my $g1_frame = $graph_frame->Frame()->pack( -side => 'left' );
my $ctrl_frame = $g1_frame->Frame()->pack( -side => 'top' );
my $ctrl_b_frame = $ctrl_frame->Frame()->pack();
my $l1_button = $ctrl_b_frame->Button( -text => '   z^4   ', -command => [\&l1_button_T]  )->pack(  -side => 'left' );
my $l1a_button = $ctrl_b_frame->Button( -text => ' ? ', -command => [\&l1a_button_T]  )->pack(  -side => 'left' );
my $l2_button = $ctrl_frame->Button( -text => 'z^4 + z^3 + z^2 + z + 1', -command => [\&l2_button_F]  )->pack( -side => 'top' );
$ctrl_frame -> Label( -text => ' z = R ( cos t + i sin t ) ' )-> pack( -side => 'top' );
my $t_text = ' t : 0 x 3.14';
$ctrl_frame -> Label( -textvariable => \$t_text )-> pack(-side => 'top' );
my $ctrl_e_frame = $ctrl_frame->Frame()->pack( -side => 'top' );
$ctrl_e_frame -> Label( -text => ' R : ' ) -> pack( -side => 'left' );
my $tmpRe = 1.5;
my $Rentry = $ctrl_e_frame -> Entry( -textvariable => \$tmpRe ) -> pack();
$top_windw-> bind( '<Return>', \&eRchenged );
my $tmpRs = $tmpRe*10;
my $Rscale = $ctrl_frame ->Scale( -orient => 'h', -from => 1, -to => 200, -variable => \$tmpRs, -command => \&sRchenged, -showvalue => '' )->pack( -side => 'top' );
my $g2_frame = $graph_frame->Frame()->pack();
my $canvas1 = $g1_frame->Canvas( 'width' => $gc_width/2, 'height' => $gc_height/2 )->pack();
my $gc1_label_text = 'z';
my $gc1_label = $g1_frame->Label( -textvariable => \$gc1_label_text )->pack();
my $canvas2 = $g2_frame->Canvas( 'width' => $gc_width, 'height' => $gc_height )->pack();
my $gc2_label_text = 'f(z)';
my $gc2_label = $g2_frame->Label( -textvariable => \$gc2_label_text )->pack();


# 基準線描画
my $r1 = $gc_size/2;
$canvas1->create( 'oval', $Ox1-$r1/2 , $Oy1-$r1/2 , $Ox1+$r1/2 , $Oy1+$r1/2 );
$canvas1->create( 'line' , 0, $Oy1, $gc_width, $Oy1 );
$canvas1->create( 'line' , $Ox1, 0, $Ox1, $gc_height );
#$canvas2->create( 'oval' , $Ox2-$r1 , $Oy2-$r1 , $Ox2+$r1 , $Oy2+$r1 );
$canvas2->create( 'line' , 0, $Oy2, $gc_width, $Oy2 );
$canvas2->create( 'line' , $Ox2, 0, $Ox2, $gc_height );


# 現在の値のグラフィカルオブジェクト用データ変数withダミーーデータ
my @cline1_data = (0,0,0,0);
my @cline2_data = (0,0,0,0);
my @ccirc2_data = (0,0,0,0);
my @cline3_data = (0,0,0,0);
my @ccirc31_data = (0,0,0,0);
my @ccirc32_data = (0,0,0,0);
my @ccircR_data = (0,0,0,0);


# 現在の値のグラフィカルオブジェクト
my $cline1 = $canvas1->create( 'line' , @cline1_data );
$canvas1->itemconfigure( $cline1, -fill => 'black', -width => 2.0 );
my $ccirc2 = $canvas2->create( 'oval' , @ccirc2_data );
$canvas2->itemconfigure( $ccirc2, -fill => 'green');
my $cline2 = $canvas2->create( 'line' , @cline2_data );
$canvas2->itemconfigure( $cline2, -fill => 'green', -width => 2.0 );
my $cline3 = $canvas2->create( 'line' , @cline3_data );
my $ccirc31 = $canvas2->create( 'oval' , @ccirc31_data );
my $ccirc32 = $canvas2->create( 'oval' , @ccirc32_data );
$canvas2->itemconfigure( $cline3, -fill => '' );
$canvas2->itemconfigure( $ccirc31, -outline => '' );
$canvas2->itemconfigure( $ccirc32, -outline => '', -fill => '' );
my $ccircR = $canvas2->create( 'oval' , @ccircR_data );



# 初期化
&calc_data;
&Rchenged($tmpRe);
&show_data;


# メインループ
MainLoop();
##################################################################### メイン関数の終了

#####################
###  数学関係
#####################

# 複素数関係
#####################
sub abs{
	my ($x,$y) = @_;
	return sqrt( $x*$x+$y*$y );
}


sub prod{
	my (($x1,$y1),($x2,$y2)) = @_;
	return ( $x1*$x2 - $y1*$y2, $x1*$y2 + $y1*$x2 );
}

sub sum{
	my (($x1,$y1),($x2,$y2)) = @_;
	return ( $x1+$x2 , $y1+$y2 );
}


# 関数関係
#####################
sub function{
	my ($x,$y) = @_;


	my @z0 = (1,0);
	my @z1 = &prod( @z0, ($x,$y) );
	my @z2 = &prod( @z1, ($x,$y) );
	my @z3 = &prod( @z2, ($x,$y) );
	my @z4 = &prod( @z3, ($x,$y) );

	my @zz = (0,0);
	@zz = &sum( @zz, &prod( @a0, @z0 ) );
	@zz = &sum( @zz, &prod( @a1, @z1 ) );
	@zz = &sum( @zz, &prod( @a2, @z2 ) );
	@zz = &sum( @zz, &prod( @a3, @z3 ) );
	@zz = &sum( @zz, &prod( @a4, @z4 ) );

	return @zz;
}


sub function4{
	my ($x,$y) = @_;

	my @z0 = (1,0);
	my @z1 = &prod( @z0, ($x,$y) );
	my @z2 = &prod( @z1, ($x,$y) );
	my @z3 = &prod( @z2, ($x,$y) );
	my @z4 = &prod( @z3, ($x,$y) );

	return &prod( @a4, @z4 );
}

sub get_small_R{
	my ($r) = @_;

	return 
		&abs( @a0 )
		+ &abs( @a1 ) * $r
		+ &abs( @a2 ) * $r * $r
		+ &abs( @a3 ) * $r * $r * $r ;
}

#####################


#####################
###  グラフィックス関係
#####################

# 現在のグラフィカルデータの計算
sub calc_data{
	my $point_num = 10;

	@cline1_data = ();
	@cline2_data = ();
	for( my $i=0; $i <= $point_num; $i++ ){

		my $r = $R * $i / $point_num;
		my ($x,$y) = ( $r*cos($theta), $r*sin($theta) );
		push @cline1_data, $Ox1 + $x*$scale1 , $Oy1 - $y*$scale1;


		($x,$y) = &function( ($x,$y) );
		push @cline2_data, $Ox2 + $x*$scale2 , $Oy2 - $y*$scale2;


	}

	my ($x,$y) = &function( ( $R*cos($theta), $R*sin($theta) ) );
	@ccirc2_data = (
		$Ox2+($x)*$scale2-5, $Oy2-($y)*$scale2-5,
		$Ox2+($x)*$scale2+5, $Oy2-($y)*$scale2+5
	);

	($x,$y) = &function4( ( $R*cos($theta), $R*sin($theta) ) );
	@ccirc31_data = ( 
		$Ox2+($x-$sR)*$scale2, $Oy2-($y-$sR)*$scale2,
		$Ox2+($x+$sR)*$scale2, $Oy2-($y+$sR)*$scale2
	);
	@ccirc32_data = ( 
		$Ox2+($x)*$scale2 -3, $Oy2-($y)*$scale2 -3,
		$Ox2+($x)*$scale2 +3, $Oy2-($y)*$scale2 +3
	);

	@cline3_data = (
		$Ox2, $Oy2,
		$Ox2 + $x*$scale2, $Oy2 - $y*$scale2
	);

}

# 半径変化時の処理
sub Rchenged{
	my ($tmpR) = @_;
	if( $tmpR > 0 ){
		$R = $tmpR; 
	}
	else{ $tmpR=1; }


	$scale1 = $gc_size / (4*$R);
	$scale2 = $gc_size / (2*&abs( &function( ($R,0) ) ) );
	$sR = &get_small_R( $R );

	@ccircR_data = ( 
		$Ox2 - $R*$scale2, $Oy2 - $R*$scale2,
		$Ox2 + $R*$scale2, $Oy2 + $R*$scale2
	);
	$canvas2->coords( $ccircR, @ccircR_data );

	&calc_data;
	&show_data;
}


#####################
###  コマンド関係
#####################

sub sRchenged{
	$tmpRe = $tmpRs / 10.0;
	&Rchenged($tmpRe);
}

sub eRchenged{
	if( $tmpRe > 0 ){
		$tmpRs = $tmpRe*10; 
		&Rchenged($tmpRe);
	}else{
		$tmpRs = 10;
		$tmpRe = 1; 
		&Rchenged($tmpRe);
	}
}

sub l1_button_T{
	$canvas2->itemconfigure( $cline3, -fill => 'red' );
	$canvas2->itemconfigure( $ccirc32, -outline => 'black', -fill => 'red' );
	$l1_button->configure(  -command => [\&l1_button_F] );
}

sub l1_button_F{
	$canvas2->itemconfigure( $cline3, -fill => '' );
	$canvas2->itemconfigure( $ccirc32, -outline => '', -fill => '' );
	$l1_button->configure(  -command => [\&l1_button_T] );
}


sub l1a_button_T{
	$canvas2->itemconfigure( $ccirc31, -outline => 'red' );
	$l1a_button->configure(  -command => [\&l1a_button_F] );
}

sub l1a_button_F{
	$canvas2->itemconfigure( $ccirc31, -outline => '' );
	$l1a_button->configure(  -command => [\&l1a_button_T] );
}


sub l2_button_T{
	$canvas2->itemconfigure( $cline2, -fill => 'green' );
	$canvas2->itemconfigure( $ccirc2, -outline => 'black', -fill => 'green' );
	$l2_button->configure(  -command => [\&l2_button_F] );
}

sub l2_button_F{
	$canvas2->itemconfigure( $cline2, -fill => '' );
	$canvas2->itemconfigure( $ccirc2, -outline => '', -fill => '' );
	$l2_button->configure(  -command => [\&l2_button_T] );
}


#####################
###  アニメーション関係
#####################
my $next_animation_ID;
sub next_animation{
	$top_windw->afterCancel($next_animation_ID);
	$next_animation_ID = $top_windw->after( 100, \&animation_func );
}

sub start_animation{
	&Rchenged;	
	&next_animation;
	$start_button->configure(  -command => [\&stop_animation] );
}

sub stop_animation{
	$top_windw->afterCancel( $next_animation_ID );
	$start_button->configure(  -command => [\&start_animation] );
}

sub show_data{
	$canvas1->coords( $cline1, @cline1_data );
	$canvas2->coords( $cline2, @cline2_data );
	$canvas2->coords( $cline3, @cline3_data );
	$canvas2->coords( $ccirc31, @ccirc31_data );
	$canvas2->coords( $ccirc32, @ccirc32_data );
	$canvas2->coords( $ccirc2, @ccirc2_data );
}

sub animation_func{
	$t += $dt;
	$t_text = ' t : '.$t.' x 3.14';
	$theta = $t*3.14159;
	
	&calc_data;
	&show_data;

	if( $t>2 ){
		&stop_animation;
		$t = 0;
	}else{
		&next_animation;
	}
}
