Benutzer:Stündle/Baustelle

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen
#!/usr/bin/perl

#
# Trägheitskräfte als Scheinkräfte
#
# Zentrifugalkraft und Corioliskraft im Zusammenspiel
#
# Maßstabsgetreue Vektoren (hoffentlich)
#


use strict;
use warnings;

use Image::Magick;
use utf8;
use File::Copy;
use FileHandle;
use File::Path;
use Math::Trig;
# use Math::Round qw/round/;

sub pfeil($$$$$$);
sub grundfläche($);
sub coriolisbahn();
sub hintergrund($);
sub kugel($$);
sub kugel_bewegt($$);
sub nummer($);
sub omega();


binmode(STDOUT, ":utf8");

print "Los geht's!\n"; 

#Global
#my $schrittzahl = 90; # nur gerade Werte zulässig
my $schritte_pro_umdrehung = int(92);
# my $umdrehungen_drehscheibe = -2;

my $umdrehungen_drehscheibe = -6; # * 0.75

#Lokal
my $svg_dir = "./svg";
my $png_dir = "./png";
my $svg_rot_filename = $svg_dir . "/coriolis-%03d.svg";
my $png_rot_filename = $png_dir . "/coriolis-%03d.png";
my $gif_filename = "./coriolis-animation.gif";
my $error = "";
my $image = Image::Magick->new;
my $animation = Image::Magick->new;
my $hello = "Hällö Perl";
my $svg_fh = undef;
my $zeit = time();

$image->Set(size=>'600x600');

mkdir($svg_dir);
mkdir($png_dir);

# Programmstruktur: Defs erzeugen
my $header = '<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        xmlns:ev="http://www.w3.org/2001/xml-events"
        version="1.1" baseProfile="full"
        width="600px" height="600px" viewBox="0 0 600 600">'."\n";
my $footer = '</svg>';
my $data = $header;
my $drehrate = 1./9.; # 1/4 Umdrehung pro Sekunde?
# will x Umdrehungen sehen
# habe x Drehrate
# habe x schritte_pro_umdrehung
my $schrittzahl = abs($schritte_pro_umdrehung * $umdrehungen_drehscheibe);
my $delay = 100./($schritte_pro_umdrehung * $drehrate); # in 10ms
my $geschwindigkeit = 2 * pi * $drehrate * 100.; # pixel pro sekunde # r = 100px 2pi => Winkelgeschwindigkeit
# my $geschwindigkeit = 40./3.; # pixel pro sekunde
my $schrittweiteKugel = $geschwindigkeit * $delay/100.;

for(my $s = int(0); $s < 0.75*$schrittzahl; $s++) {
  print "Schritt: ".$s."\n";
  $header = '<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        xmlns:ev="http://www.w3.org/2001/xml-events"
        version="1.1" baseProfile="full"
        width="600px" height="600px" viewBox="0 0 600 600">'."\n";
  $footer = '</svg>';

  # rotierendes Bezugsystem
  $data = $header;
  $image = Image::Magick->new;
  #$image->Set(size=>'600x600');


  $data .= hintergrund((2 * pi * $umdrehungen_drehscheibe * $s) / $schrittzahl);
  $data .= grundfläche(0); #// 2 * pi * $bogen * $s / ($schrittzahl-1));
  $data .= omega();

# schritte_pro_umdrehung

  if (($s%(1.5*$schritte_pro_umdrehung)) > 1 * $schritte_pro_umdrehung-2)  { # zurück bewegen
  # hier: schritte_pro_umdrehung + 1 0..1
  # $s 2*schritte_pro_umdrehung-1.....3*schritte_pro_umdrehung-1
    $data .= nummer("4");

    $data .= kugel_bewegt(1.-(($s%(1.5*$schritte_pro_umdrehung))-(1 * $schritte_pro_umdrehung-1))/($schritte_pro_umdrehung/2), -1);
    print "Zurück: " . ((($s%(1.5*$schritte_pro_umdrehung))-(1 * $schritte_pro_umdrehung-1))/($schritte_pro_umdrehung/2)) . " // " . $s . "\n";


  } elsif (($s%(1.5*$schritte_pro_umdrehung)) > 0.75 * $schritte_pro_umdrehung) { # Kugle stoppt
    $data .= nummer("3");

    $data .= kugel_bewegt(1, 0);
    print "Ruhe: " . 1 . " // " . $s . "\n";
  } elsif (($s%(1.5*$schritte_pro_umdrehung)) > 0.25 * $schritte_pro_umdrehung - 1) { # vor bewegen
  # hier: schritte_pro_umdrehung + 1 0..1 
  # $s schritte_pro_umdrehung-2.....2*schritte_pro_umdrehung-2
    $data .= nummer("2");

    $data .= kugel_bewegt((($s%(1.5*$schritte_pro_umdrehung))-(0.25*$schritte_pro_umdrehung))/($schritte_pro_umdrehung/2), +1);
    print "Vor: " . ((($s%(1.5*$schritte_pro_umdrehung))-(0.25*$schritte_pro_umdrehung))/($schritte_pro_umdrehung/2)) . " // " . $s . "\n";


  } else { # in Ruhe
    $data .= nummer("1");

    $data .= kugel_bewegt(0, 0);
    print "Ruhe: " . 0 . " // " . $s . "\n";
  }




  $data .= $footer;

  open($svg_fh, "> " . sprintf($svg_rot_filename, $s));
  binmode( $svg_fh, ":utf8" );

  print $svg_fh $data;

  close($svg_fh);


  $image = Image::Magick->new();
  #$error = $image->Read(sprintf($svg_fix_filename, $s));
  #warn "$error" if "$error";
  $error = $image->Read(sprintf($svg_rot_filename, $s));
  warn "$error" if "$error";
  #$image->Resize(geometry=>"500x500"); #, width=>integer, height=>integer,

  $image->Write(sprintf($png_rot_filename, $s));

  #$image->Resize(geometry=>"260x260"); #, width=>integer, height=>integer,

  push(@$animation, $image);
}


print "Animation erstellen: ".$gif_filename."\n";
print "Delay: " . $delay . "x10ms\n";
$animation->[0]->Coalesce();

$animation->Set(delay => $delay, loop => 0); # * 10ms
$animation->Write( $gif_filename );

$zeit = time()-$zeit;
print "Zeit: " . $zeit . " s\n";

print "\nFertig!\n";


sub grundfläche($) {
  #my $data = $_{'data'};
  my $winkel = sprintf("%.2f", (180. * $_[0] / pi)); # in grad umrechnen
  my $body = '<g id="grundflaeche"  transform="rotate('.$winkel.', 300, 300)">'."\n";

  $body .= '<path d="M 300,300 L 300,50 A 250,250 0 0 0 50,300" fill="#ffcbcbff" stroke="none"/>'."\n";
  $body .= '<path d="M 300,300 L 50,300 A 250,250 0 0 0 300,550" fill="#cbffcbff" stroke="none"/>'."\n";
  $body .= '<path d="M 300,300 L 300,550 A 250,250 0 0 0 550,300" fill="#ffcbcbff" stroke="none"/>'."\n";
  $body .= '<path d="M 300,300 L 550,300 A 250,250 0 0 0 300,50" fill="#cbffcbff" stroke="none"/>'."\n";

  $body .= '<circle cx="300" cy="300" r="250" fill="none" stroke="#ff9b9bff" stroke-width="5px" />'."\n";

  # $body .= coriolisbahn();

  $body .= "</g>\n";
  #$data .= $body;
  return $body;

}


sub hintergrund($) {
  my $winkel = sprintf("%.2f", (-1 * 180. * $_[0] / pi)); # in grad umrechnen
  my $data = '<g id="hintergrund"  transform="rotate('.$winkel.', 300, 300)">'."\n";

  $data .= '<circle cx="300" cy="300" r="300" fill="white" stroke="none" />'."\n";

  #// -300 .. + 900 // 1200 div 20 => 60
  for(my $x = -300; $x <= 900; $x += 40) { # horizontale Linien
    $data .= '<line x1="'.$x.'" y1="-300" x2="'.$x.'" y2="900" stroke-width="1px" stroke="lightgray" />'."\n";
  }

  for(my $y = -300; $y <= 900; $y += 40) { # horizontale Linien
    $data .= '<line x1="-300" y1="'.$y.'" x2="900" y2="'.$y.'" stroke-width="1px" stroke="lightgray" />'."\n";
  }

  $data .= '<line x1="-300" y1="300" x2="900" y2="300" stroke-width="3px" stroke="green" />'."\n";

  $data .= '<line x1="300" y1="-300" x2="300" y2="900" stroke-width="3px" stroke="green" />'."\n";

  $data .= "</g>\n";
  return $data;

}


sub kugel($$) {

  my $pos = $_[0];
  my $winkel = $_[1]; # sprintf("%.2f", (180. * $_[1] / pi)); # in grad umrechnen
  my $data = '<g id="kugel">'."\n";
  my $x = 300 + 250 * $pos * sin($winkel*1); # 1/-1 Drehrichtung
  my $y = 300 + 250 * $pos * cos($winkel);

  $data .= '<circle cx="'.$x.'" cy="'.$y.'" r="20" fill="red" stroke="darkred" stroke-width="3px"/>'."\n";


  $data .= "</g>\n";
  return $data
}


sub kugel_bewegt($$) {
  my $position = $_[0] - 0.5; # -1..+1
  my $direction = $_[1];
  my $data = '<g id="kugel">'."\n";
  my $x = 300 - 157.1 * 2 * $position; # 0.5*3*100*2pi/6 
  my $y = 300-100;
  my $winkel = 0;
  my $radius = sqrt((300-$y) * (300-$y) + ($x-300) * ($x-300)); # a^2 + b^2 =

  if($x > 300) {
    $winkel = atan((300-$y)/($x-300));
  } elsif( $x < 300) {
    $winkel = atan((300-$y)/($x-300));
    $winkel += pi;
  } else {
    $winkel = pi/2;
  }

  #$data .= '<circle cx="300" cy="300" r="185" fill="none" stroke="darkgray" stroke-width="3px"/>'."\n";
  #$body .= '<path d="M 300,300 L 550,300 A 250,250 0 0 0 300,50" fill="none" stroke="3px"/>'."\n";
#TODO
# Bahn festlegen
# Coriolis und Zentrifugalkraft abstimmen
# Alle Vektoren einbringen


  # Bahn
  $data .= '<line x1="126.8" y1="200" x2="473.2" y2="200" stroke-width="3px" stroke="orange" />'."\n";

  #$data .= '<path d="M 300,300 A 185,185 0 0 0 300,115" fill="none" stroke="darkgray" stroke="3px"/>'."\n";
  $data .= '<circle cx="'.$x.'" cy="'.$y.'" r="20" fill="red" stroke="darkred" stroke-width="3px"/>'."\n";

  $data .= pfeil($x, $y, 175./100 * $radius/2. , $winkel + pi/2, "F_Z", "darkslategrey");

  if ($direction != 0) {
    $data .= pfeil($x, $y, 85, -1 * pi/2 * $direction, "v'_ ", "darkslateblue");
    $data .= pfeil($x, $y, 175. , pi/2 + pi/2 * $direction , "F_C", "darkslategrey");
  }


  $data .= "</g>\n";
  return $data


}

sub pfeil($$$$$$) {
# Position, Betrag, Richtung
  my $x1 = $_[0];
  my $y1 = $_[1];
  my $betrag = $_[2];
  my $winkel = $_[3];
  my @text = split(/_/, $_[4]);
  my $farbe = $_[5]; # 5()
  my $data = ""; # '<g id="kugel">'."\n";
  my $x2 = $x1 + ($betrag-20) * sin($winkel);
  my $y2 = $y1 + ($betrag-20) * cos($winkel);
  my $p1x = $x1 + ($betrag) * sin($winkel); # $x2; # x1 + ($betrag) * sin($winkel);
  my $p1y = $y1 + ($betrag) * cos($winkel); # $y2;
  my $p2x = $p1x - 25 * sin($winkel) - 8 * cos($winkel) ; #  * sin($winkel+pi);
  my $p2y = $p1y + 8 * sin($winkel) - 25 * cos($winkel); 
  my $p3x = $p1x - 25 * sin($winkel) + 8 * cos($winkel); #  * sin($winkel+pi);
  my $p3y = $p1y - 8 * sin($winkel) - 25 * cos($winkel);
  my $tx = ($x1+$x2)/2 + 40 * cos($winkel);
  my $ty = ($y1+$y2)/2 - 40 * sin($winkel);
  my $t1x = $tx - 15;
  my $t1y = $ty;
  my $t2x = $t1x + 15;
  my $t2y = $t1y + 10;

  $data .= '<line x1="'.$x1.'" y1="'.$y1.'" x2="'.$x2.'" y2="'.$y2.'" stroke-width="2px" stroke="'.$farbe.'" />'."\n";
  $data .= '<polyline points="'.$p1x.','.$p1y.' '.$p2x.','.$p2y.' '.$p3x.','.$p3y.'"  fill="'.$farbe.'" stroke="none" />'."\n";
  $data .= '<text x="'.$t1x.'" y="'.$t1y.'" font-size="40" font-style="italic" fill="'.$farbe.'" >'.$text[0].'</text>'."\n";
  $data .= '<text x="'.$t2x.'" y="'.$t2y.'" font-size="25" font-style="normal" fill="'.$farbe.'" >'.$text[1].'</text>'."\n";

  return $data;
}

sub nummer($) {

  my $data = '<g id="nummer">'."\n";

  my $farbe = "black";
  my $text = $_[0];
  my $x = 35;
  my $y = 35;
  my $tx = 20;
  my $ty = 53;

  $data .= '<circle cx="'.$x.'" cy="'.$y.'" r="30" fill="lightgray" stroke="black" stroke-width="3px"/>'."\n";

  $data .= '<text x="'.$tx.'" y="'.$ty.'" font-size="60" font-style="normal" fill="'.$farbe.'" >'.$text.'</text>'."\n";

  $data .= "</g>\n";
  return $data


}

sub omega() {
  my $winkel=-45;
  my $data = '<g id="omega">'."\n";

  my $x = 315;
  my $y = 330;
  my $p1x = $x;
  my $p1y = $y;
  my $p2x = $p1x -25; #  * sin($winkel+pi);
  my $p2y = $p1y +8; 
  my $p3x = $p1x -25; #  * sin($winkel+pi);
  my $p3y = $p1y - 8;


  $data .= '<path d=" M 300,330 A 30,30 0 1 1 330,300" stroke="#ff6b6bff" fill="none" stroke-width="3px"   transform="rotate('.$winkel.', 300, 300)"/>'."\n";
  $data .= '<polyline points="'.$p1x.','.$p1y.' '.$p2x.','.$p2y.' '.$p3x.','.$p3y.'"  fill="#ff6b6bff" stroke="none"   transform="rotate('.$winkel.', 300, 300)"/>'."\n";
  $data .= '<text x="330" y="305" font-size="40" font-style="italic" fill="#ff6b6bff" >ω</text>'."\n";


  $data .= "</g>\n";
  #$data .= $body;
  return $data;

}

# EOF