]> mj.ucw.cz Git - anim.git/commitdiff
Animace detailu Fortunova algoritmu.
authorMartin Mares <mj@ucw.cz>
Sun, 2 Dec 2007 20:29:23 +0000 (21:29 +0100)
committerMartin Mares <mj@ucw.cz>
Sun, 2 Dec 2007 20:29:23 +0000 (21:29 +0100)
fortune.pl [new file with mode: 0755]
x.pl [deleted file]

diff --git a/fortune.pl b/fortune.pl
new file mode 100755 (executable)
index 0000000..46bf34c
--- /dev/null
@@ -0,0 +1,224 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Gtk2 -init;
+use Cairo;
+
+my $pi = 3.1415926536;
+
+sub sqr($) {
+       my ($x) = @_;
+       return $x * $x;
+}
+
+sub is_zero($) {
+       my ($x) = @_;
+       return ($x < 1e-10 && $x > -1e-10);
+}
+
+sub draw_para($$$$$) {
+       # Draw a parabola y=a(x-x0)^2 + y0
+       my ($cairo,$a,$x0,$y0,$ww) = @_;
+       if (!defined($a)) {
+               # Degenerate parabola
+               $cairo->move_to($x0, $y0);
+               $cairo->line_to($x0, 0);
+       } else {
+               my $been = 0;
+               for (my $x=0; $x<$ww; $x++) {
+                       my $y = $a*sqr($x-$x0) + $y0;
+                       next if ($y < -10000 || $y > 10000);
+                       if ($been++) {
+                               $cairo->line_to($x, $y);
+                       } else {
+                               $cairo->move_to($x, $y);
+                       }
+               }
+       }
+       $cairo->stroke;
+}
+
+sub solve_para($$$) {
+       my ($h0, $x0, $y0) = @_;
+       my $h = $y0 - $h0;
+       if (is_zero($h)) {
+               return (undef, $x0, $h0);
+       } else {
+               return (1/(2*$h), $x0, $h0 + $h/2);
+       }
+}
+
+sub solve_circ($$$$$$) {
+       my ($x0, $y0, $x1, $y1, $x2, $y2) = @_;
+       my $axc = ($x0 + $x1) / 2;
+       my $ayc = ($y0 + $y1) / 2;
+       my $adx = $y1 - $y0;
+       my $ady = $x0 - $x1;
+       my $bxc = ($x1 + $x2) / 2;
+       my $byc = ($y1 + $y2) / 2;
+       my $bdx = $y2 - $y1;
+       my $bdy = $x1 - $x2;
+       my $alpha = (($bxc-$axc)*(-$bdy) - ($byc-$ayc)*(-$bdx)) /
+                   ($adx*(-$bdy) - $ady*(-$bdx));
+       my $x = $axc + $alpha*$adx;
+       my $y = $ayc + $alpha*$ady;
+       my $r = sqrt(sqr($x-$x0) + sqr($y-$y0));
+       return ($x, $y, $r);
+}
+
+sub para_isec($$$$$$) {
+       # Parameters of two parabolas
+       my ($a, $b, $c, $d, $e, $f) = @_;
+       if (!defined($a) || !defined($b)) {
+               # Either is degenerate
+               return;
+       }
+       # Coefficients of the corresponding quadratic equation
+       my $A = $a - $d;
+       my $B = 2*($d*$e - $a*$b);
+       my $C = $a*sqr($b) - $d*sqr($e) + $c - $f;
+       # Is the equation linear?
+       if (is_zero($A)) {
+               if (is_zero($B)) { return; }
+               my $x = -$C/$B;
+               my $y = $a*sqr($x-$b) + $c;
+               return [$x, $y];
+       }
+       # No, really quadratic. Consider its discriminant.
+       my $D = sqr($B) - 4*$A*$C;
+       if ($D < 0) {
+               return;
+       } elsif (is_zero($D)) {
+               my $x = -$B / (2*$A);
+               my $y = $a*sqr($x-$b) + $c;
+               return [$x, $y];
+       } else {
+               my $DD = sqrt($D);
+               my $x1 = (-$B + $DD) / (2*$A);
+               my $x2 = (-$B - $DD) / (2*$A);
+               if ($x1 > $x2) { ($x1,$x2) = ($x2,$x1); }
+               my $y1 = $a*sqr($x1-$b) + $c;
+               my $y2 = $a*sqr($x2-$b) + $c;
+               return ([$x1,$y1], [$x2,$y2]);  # In order left, right
+       }
+}
+
+my $area = Gtk2::DrawingArea->new();
+my $cairo;
+my $dh = 620;
+sub draw() {
+       my $win = $area->window;
+       my $alloc = $area->allocation;
+       my $w = $alloc->width;
+       my $h = $alloc->height;
+
+       $cairo = Gtk2::Gdk::Cairo::Context->create($win);
+       $cairo->rectangle(0, 0, $w, $h);
+       $cairo->set_source_rgb(0, 0, 0);
+       $cairo->fill;
+
+       my @pts = ( [$w/3, $h-600], [$w/2, $h-700], [2*$w/3, $h-650] );
+       my ($cx, $cy, $cr) = solve_circ($pts[0]->[0], $pts[0]->[1], $pts[1]->[0], $pts[1]->[1], $pts[2]->[0], $pts[2]->[1]);
+       my $ch = $cy + $cr;
+       my $h0 = $h-$dh;
+       if (abs($ch-$h0) < 2) {
+               $h0 = $ch;
+       }
+
+       for (my $i=0; $i<$#pts; $i++) {
+               my $p = $pts[$i];
+               my $q = $pts[$i+1];
+               my $xc = ($p->[0] + $q->[0]) / 2;
+               my $yc = ($p->[1] + $q->[1]) / 2;
+               my $dx = ($q->[1] - $p->[1]);
+               my $dy = ($p->[0] - $q->[0]);
+               $cairo->set_source_rgb(0.5, 0, 0.5);
+               $cairo->move_to($xc - 10*$dx, $yc - 10*$dy);
+               $cairo->line_to($xc + 10*$dx, $yc + 10*$dy);
+               $cairo->stroke;
+               $cairo->set_source_rgb(0.5, 0.5, 0.5);
+               $cairo->move_to($p->[0], $p->[1]);
+               $cairo->line_to($q->[0], $q->[1]);
+               $cairo->stroke;
+       }
+       {
+               my $p = $pts[0];
+               my $q = $pts[2];
+               my $xc = ($p->[0] + $q->[0]) / 2;
+               my $yc = ($p->[1] + $q->[1]) / 2;
+               my $dx = ($q->[1] - $p->[1]);
+               my $dy = ($p->[0] - $q->[0]);
+               $cairo->set_source_rgb(0.5, 0, 0.5);
+               $cairo->move_to($xc - 10*$dx, $yc - 10*$dy);
+               $cairo->line_to($xc + 10*$dx, $yc + 10*$dy);
+               $cairo->stroke;
+               $cairo->set_source_rgb(0.5, 0.5, 0.5);
+               $cairo->move_to($p->[0], $p->[1]);
+               $cairo->line_to($q->[0], $q->[1]);
+               $cairo->stroke;
+       }
+
+       $cairo->set_source_rgb(1, 0, 1);
+       $cairo->arc($cx, $cy, $cr, 0, 2*$pi);
+       $cairo->stroke;
+
+       $cairo->set_source_rgb(1, 1, 1);
+       $cairo->move_to(0, $h0);
+       $cairo->line_to($w, $h0);
+       $cairo->stroke;
+
+       foreach my $p (@pts) {
+               $cairo->arc($p->[0], $p->[1], 2, 0, 2*$pi);
+               $cairo->fill;
+       }
+
+       $cairo->set_source_rgb(0, 1, 0);
+       my @paras = ();
+       foreach my $p (@pts) {
+               next if ($p->[1] > $h0);
+               my ($pa,$px,$py) = solve_para($h0, $p->[0], $p->[1]);
+               draw_para($cairo, $pa, $px, $py, $w);
+               push @paras, [$pa,$px,$py];
+       }
+       if ($h0 > $ch) {
+               splice @paras, 1, 1;
+       }
+       for (my $i=0; $i<$#paras; $i++) {
+               my $p = $paras[$i];
+               my $q = $paras[$i+1];
+               my @isec = para_isec($p->[0], $p->[1], $p->[2], $q->[0], $q->[1], $q->[2]);
+               foreach my $pt (@isec) {
+                       $cairo->set_source_rgb(1, 0, 0);
+                       $cairo->arc($pt->[0], $pt->[1], 2, 0, 2*$pi);
+                       $cairo->fill;
+               }
+       }
+}
+
+my $timer;
+$area->signal_connect("expose-event" => sub {
+       draw();
+});
+
+my $window = Gtk2::Window->new ('toplevel');
+$window->signal_connect ("delete-event" => sub { Gtk2->main_quit });
+$window->set_title("Brum");
+$window->set_wmclass("anim", "Anim");
+$window->set_default_size(640, 480);
+$window->add ($area);
+$window->show_all;
+$window->fullscreen;
+$window->signal_connect("key-press-event" => sub {
+       my ($w, $evt) = @_;
+       my $k = Gtk2::Gdk::keyval_name(0, $evt->keyval);
+       if ($k eq "space" || $k eq "Right" || $k eq "Return") {
+               $dh -= 10;
+               draw();
+       } elsif ($k eq "q" || $k eq "Escape") {
+               Gtk2->main_quit;
+       }
+});
+
+Gtk2->main;
diff --git a/x.pl b/x.pl
deleted file mode 100755 (executable)
index 0e94b1b..0000000
--- a/x.pl
+++ /dev/null
@@ -1,142 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-
-use Gtk2 -init;
-use Cairo;
-
-my $pi = 3.1415926536;
-
-sub para($$$$$) {
-       # draw a parabola y=a(x-x0)^2 + y0
-       my ($cairo,$a,$x0,$y0,$ww) = @_;
-       my $been = 0;
-       for (my $x=0; $x<$ww; $x++) {
-               my $y = $a*($x-$x0)*($x-$x0) + $y0;
-               next if ($y < -10000 || $y > 10000);
-               if ($been++) {
-                       $cairo->line_to($x, $y);
-               } else {
-                       $cairo->move_to($x, $y);
-               }
-       }
-       $cairo->stroke;
-}
-
-sub solve_para($$$) {
-       my ($h0, $x0, $y0) = @_;
-       my $h = $y0 - $h0;
-       return (1/(2*$h), $x0, $h0 + $h/2);
-}
-
-sub solve_circ($$$$$$) {
-       my ($x0, $y0, $x1, $y1, $x2, $y2) = @_;
-       my $axc = ($x0 + $x1) / 2;
-       my $ayc = ($y0 + $y1) / 2;
-       my $adx = $y1 - $y0;
-       my $ady = $x0 - $x1;
-       my $bxc = ($x1 + $x2) / 2;
-       my $byc = ($y1 + $y2) / 2;
-       my $bdx = $y2 - $y1;
-       my $bdy = $x1 - $x2;
-       my $alpha = (($bxc-$axc)*(-$bdy) - ($byc-$ayc)*(-$bdx)) /
-                   ($adx*(-$bdy) - $ady*(-$bdx));
-       my $x = $axc + $alpha*$adx;
-       my $y = $ayc + $alpha*$ady;
-       my $r = sqrt(($x-$x0)*($x-$x0) + ($y-$y0)*($y-$y0));
-       return ($x, $y, $r);
-}
-
-my $area = Gtk2::DrawingArea->new();
-my $cairo;
-my $dh = 625;
-sub draw() {
-       my $win = $area->window;
-       my $alloc = $area->allocation;
-       my $w = $alloc->width;
-       my $h = $alloc->height;
-
-       $cairo = Gtk2::Gdk::Cairo::Context->create($win);
-       $cairo->rectangle(0, 0, $w, $h);
-       $cairo->set_source_rgb(0, 0, 0);
-       $cairo->fill;
-
-       my @pts = ( [$w/3, $h-600], [$w/2, $h-700], [2*$w/3, $h-650] );
-       my ($cx, $cy, $cr) = solve_circ($pts[0]->[0], $pts[0]->[1], $pts[1]->[0], $pts[1]->[1], $pts[2]->[0], $pts[2]->[1]);
-
-       for (my $i=0; $i<$#pts; $i++) {
-               my $p = $pts[$i];
-               my $q = $pts[$i+1];
-               my $xc = ($p->[0] + $q->[0]) / 2;
-               my $yc = ($p->[1] + $q->[1]) / 2;
-               my $dx = ($q->[1] - $p->[1]);
-               my $dy = ($p->[0] - $q->[0]);
-               $cairo->set_source_rgb(0.5, 0, 0.5);
-               $cairo->move_to($xc - 10*$dx, $yc - 10*$dy);
-               $cairo->line_to($xc + 10*$dx, $yc + 10*$dy);
-               $cairo->stroke;
-               $cairo->set_source_rgb(0.5, 0.5, 0.5);
-               $cairo->move_to($p->[0], $p->[1]);
-               $cairo->line_to($q->[0], $q->[1]);
-               $cairo->stroke;
-       }
-       {
-               my $p = $pts[0];
-               my $q = $pts[2];
-               my $xc = ($p->[0] + $q->[0]) / 2;
-               my $yc = ($p->[1] + $q->[1]) / 2;
-               my $dx = ($q->[1] - $p->[1]);
-               my $dy = ($p->[0] - $q->[0]);
-               $cairo->set_source_rgb(0.5, 0, 0.5);
-               $cairo->move_to($xc - 10*$dx, $yc - 10*$dy);
-               $cairo->line_to($xc + 10*$dx, $yc + 10*$dy);
-               $cairo->stroke;
-               $cairo->set_source_rgb(0.5, 0.5, 0.5);
-               $cairo->move_to($p->[0], $p->[1]);
-               $cairo->line_to($q->[0], $q->[1]);
-               $cairo->stroke;
-       }
-
-       $cairo->set_source_rgb(1, 0, 1);
-       $cairo->arc($cx, $cy, $cr, 0, 2*$pi);
-       $cairo->stroke;
-
-       $cairo->set_source_rgb(1, 1, 1);
-       my $h0 = $h-$dh;
-       $cairo->move_to(0, $h0);
-       $cairo->line_to($w, $h0);
-       $cairo->stroke;
-
-       foreach my $p (@pts) {
-               $cairo->arc($p->[0], $p->[1], 2, 0, 2*$pi);
-               $cairo->fill;
-       }
-
-       $cairo->set_source_rgb(0, 1, 0);
-       foreach my $p (@pts) {
-               next if ($p->[1] > $h0);
-               my ($pa,$px,$py) = solve_para($h0, $p->[0], $p->[1]);
-               para($cairo, $pa, $px, $py, $w);
-       }
-}
-
-my $timer;
-$area->signal_connect("expose-event" => sub {
-       draw();
-});
-
-my $window = Gtk2::Window->new ('toplevel');
-$window->signal_connect ("delete-event" => sub { Gtk2->main_quit });
-$window->set_title("Brum");
-$window->set_wmclass("anim", "Anim");
-$window->set_default_size(640, 480);
-$window->add ($area);
-$window->show_all;
-$window->fullscreen;
-$window->signal_connect("key-press-event" => sub {
-       $dh -= 10;
-       draw();
-});
-
-Gtk2->main;