package CFFClock; use Geometry qw( RING_WIDTH DIAL_RADIUS MAJOR_MARK_INNER MAJOR_MARK_OUTER MINOR_MARK_INNER MINOR_MARK_OUTER HOUR_LENGTH MINUTE_LENGTH HOUR_WIDTH MINUTE_WIDTH SECOND_LENGTH SECOND_WIDTH SECOND_DISC_RADIUS SECOND_DISC_POSITION SECOND_COUNTERWEIGHT CENTER_RADIUS ); use strict; use warnings; use Time::HiRes qw(time); use Math::Trig qw(pi); ############################################################ # # Constructeur # ############################################################ sub new { my ($class,%arg)=@_; my $self={ canvas => $arg{canvas}, width => 0, height => 0, cx => 0, cy => 0, radius => 0, initialized => 0, }; bless $self,$class; return $self; } ############################################################ # # Démarrage # ############################################################ sub start { my $self=shift; $self->resize(); my $canvas=$self->{canvas}; # # 50 images / seconde # $canvas->repeat( 16, sub{ $self->update(); } ); } ############################################################ # # Redimensionnement # ############################################################ sub resize { my $self=shift; my $c=$self->{canvas}; $self->{width} = $c->Width; $self->{height} = $c->Height; my $size = $self->{width}; $size = $self->{height} if $self->{height} < $size; $self->{radius}=0.46*$size; $self->{cx}=$self->{width}/2; $self->{cy}=$self->{height}/2; # # Le cadran est dessiné UNE seule fois # $self->draw_dial(); } ############################################################ # # Boucle d'animation # ############################################################ sub update { my $self=shift; my $c=$self->{canvas}; # # On ne redessine que les éléments mobiles # $c->delete("hands"); $c->delete("seconds"); $c->delete("center"); $self->draw_hands(); $self->draw_second_hand(); $self->draw_center(); } ############################################################ # # Les fonctions suivantes seront écrites # dans les prochaines parties. # ############################################################ ############################################################ # # Dessin du cadran CFF # ############################################################ sub draw_dial { my $self = shift; my $c = $self->{canvas}; my $cx = $self->{cx}; my $cy = $self->{cy}; my $r = $self->{radius}; # # Nettoyage # $c->delete("dial"); ######################################################## # Ombre ######################################################## $c->createOval( $cx-$r+12, $cy-$r+12, $cx+$r+12, $cy+$r+12, -fill => "#c4c4c4", -outline => "black", -width => int($r*0.110), -tags=>"dial", ); $c->createOval( $cx-$r+10, $cy-$r+10, $cx+$r+10, $cy+$r+10, -fill => "#c4c4c4", -outline => "#d8d8d8", -width => int($r*0.110), -tags=>"dial", ); ######################################################## # Lunette extérieure ######################################################## $c->createOval( $cx-$r, $cy-$r, $cx+$r, $cy+$r, -fill => "#c4c4c4", -outline => "black", -width => int($r*0.110), -tags=>"dial", ); $c->createOval( $cx-$r, $cy-$r, $cx+$r, $cy+$r, # -fill => "#d9d9d9", -fill => "black", # -outline => "#666666", -outline => "#d8d8d8", -width => int($r*0.100), -tags=>"dial", ); $c->createOval( $cx-$r+29, $cy-$r+29, $cx+$r-29, $cy+$r-29, -fill => "#c8c8c8", -outline => "black", -width => int($r*0.110), -tags=>"dial", ); ######################################################## # Fond blanc ######################################################## # my $ri = $r*0.965; my $ri = $r*0.965; $c->createOval( $cx-$ri, $cy-$ri, $cx+$ri, $cy+$ri, -fill=>"white", -outline=>"", -tags=>"dial", ); ######################################################## # Les 60 graduations ######################################################## for my $i (0..59) { my $a = ($i*6-90)*pi/180; my ($r1,$r2,$w); if($i%5==0) { # # Graduation principale # $r1=$ri*0.82; $r2=$ri*0.96; $w=int($r*0.012); $w=4 if $w<4; $w=10; } else { # # Graduation secondaire # $r1=$ri*0.90; $r2=$ri*0.96; $w=int($r*0.004); $w=1 if $w<1; $w=4; } my $x1=$cx+cos($a)*$r1; my $y1=$cy+sin($a)*$r1; my $x2=$cx+cos($a)*$r2; my $y2=$cy+sin($a)*$r2; $c->createLine( $x1,$y1, $x2,$y2, -fill=>"black", -width=>$w, -capstyle=>"projecting", -tags=>"dial", ); } ######################################################## # Cercle central (sous les aiguilles) ######################################################## my $d=$r*0.020; $c->createOval( $cx-$d, $cy-$d, $cx+$d, $cy+$d, -fill=>"red", -outline=>"", -tags=>"dial", ); } ############################################################ # # Dessin des aiguilles # ############################################################ sub draw_hands { my $self = shift; my ($sec,$min,$hour) = localtime(time); my $hour_angle = (($hour % 12) + $min/60 + $sec/3600) * 30 - 90; my $minute_angle = ($min + $sec/60) * 6 - 90; $self->draw_hand( $hour_angle, $self->{radius} * 0.70, $self->{radius} * 0.040, "black" ); $self->draw_hand( $minute_angle, $self->{radius} * 0.90, $self->{radius} * 0.040, "black" ); } ############################################################ # # Dessin d'une aiguille # ############################################################ sub draw_hand { my ($self,$angle,$length,$width,$color)=@_; my $c = $self->{canvas}; my $cx = $self->{cx}; my $cy = $self->{cy}; my $a = $angle * pi / 180; my $dx = cos($a); my $dy = sin($a); my $px = -$dy; my $py = $dx; # # Longueur derrière l'axe # my $back = $length * 0.12; # # Pointe # my $tipx = $cx + $dx * $length; my $tipy = $cy + $dy * $length; # # Arrière # my $bx = $cx - $dx * $back; my $by = $cy - $dy * $back; # # Polygone # my @poly = ( $bx + $px * $width, $by + $py * $width, $cx + $px * ($width * 0.90), $cy + $py * ($width * 0.90), $tipx + $px * ($width * 0.68), $tipy + $py * ($width * 0.68), $tipx - $px * ($width * 0.68), $tipy - $py * ($width * 0.68), $cx - $px * ($width * 0.90), $cy - $py * ($width * 0.90), $bx - $px * $width, $by - $py * $width, ); $c->createPolygon( @poly, -fill => $color, -outline => $color, -tags => "hands", ); } ############################################################ # # Trotteuse CFF # ############################################################ sub draw_second_hand { my $self = shift; my $c = $self->{canvas}; my $cx = $self->{cx}; my $cy = $self->{cy}; my $r = $self->{radius}; my $t = time(); # # Temps écoulé dans la minute # my $phase = $t - int($t/60)*60; my $angle; # # Rotation en 58.5 s # puis arrêt jusqu'à 60 s # if ($phase < 58.5) { $angle = $phase * 360 / 58.5; } else { $angle = 360; } $angle -= 90; my $a = $angle * pi / 180; my $dx = cos($a); my $dy = sin($a); # # Longueur # # my $len = $r * SECOND_LENGTH; my $len = $r * 0.74; # # Petit contrepoids # my $back = $r * SECOND_COUNTERWEIGHT; my $bx = $cx - $dx * $back; my $by = $cy - $dy * $back; # # Tige rouge # $c->createLine( $bx, $by, $cx + $dx * $len, $cy + $dy * $len, -fill => "#d00000", -width => 6, -capstyle => "round", -tags=>"seconds", ); # # Disque rouge # # my $disc = $r * SECOND_DISC_RADIUS; my $disc = $r * 0.05; # my $disc_pos = $r * 0.23; my $disc_pos = $r * 0.72; my $x = $cx + $dx * $disc_pos; my $y = $cy + $dy * $disc_pos; $c->createOval( $x-$disc, $y-$disc, $x+$disc, $y+$disc, -fill => "#d00000", -outline => "#d00000", -tags=>"seconds", ); } sub draw_center { my $self=shift; my $c=$self->{canvas}; my $r=$self->{radius}*0.022; $c->createOval( $self->{cx}-$r, $self->{cy}-$r, $self->{cx}+$r, $self->{cy}+$r, -fill => "#d00000", -outline => "#d00000", -tags=>"center", ); } 1;