#!/usr/bin/perl -w
##################################################################
## Programm zur Erstellung von Interferenzmustern mit Pstricks
## Letzte Aenderung: 26.11.2009
## Autor:  Xenia Rendtel
##################################################################
use POSIX qw /floor ceil/;
use Math::Trig;
use strict;
use lib '/home/xenia/Schule/Informatik-Eigen/Interferenz';
use hilfsfunktionen;
my (
	$e,                  $s,
	$d,                  $l1,
	$l2,                 $weiter,
	$kreise,             $diff,
	$i,                  $ymax,
	$ymin,               $xmin,
	$xmax,               @ausgabedatei,
	@ausgabedateizeilen, $kopf,
	$kommandodatei,      $texdatei,
	$leer,               $eingabedateizeilen,
	@eingabedatei,       $kommandodateinummer,
	$datei,              $zeile,
	$ausrichtung,        $bezeichnung,
	$func,               $variable,
	$j,                  $schritt,
	$spalten,            $nachkommastellen,
	$spaltenausrichtung, $liste,
	$endeerreicht,       $hilfszeile,
	$anzahlzeilen
);
my $boegen   = 0;
my $hyperbel = 0;
$xmin = $xmax = $ymin = $ymax = 0;
$kopf = 1;
$diff = 0;
### Das Array wird eingelesen
@ausgabedateizeilen = ();

for ( $i = 0 ; $i <= 150 ; $i++ ) {
	$ausgabedateizeilen[$i] = 0;
}

# In ein array wird geschrieben
sub schreibeinarray {
	my ( $layer, $zeile ) = @_;
	$ausgabedatei[$layer][ $ausgabedateizeilen[$layer] ] =
	  $zeile;
	$ausgabedateizeilen[$layer]++;
}

# Der Kopf der Latex-Datei wird geschrieben
sub kopfdatei {
	if ( $kopf == 1 ) {
		kommentar( 1, "Interferenzhyperbeln" );
		kommentar( 1, "Autor: X. Rendtel" );
		kommentar( 1, "Letzte Aenderung: 2009" );
		latex( 2,
			"\\documentclass[10pt, a4paper]{article}" );
		usepackage( "utf8", "inputenc" );
		usepackage(
			"",
			"pstricks,pst-pdf,pst-node,xcolor, "
			  . "pst-circ,pst-func,pst-math,pst-eucl, "
			  . "pstricks-add,multido"    
		);
		latex( 3,
			"\\pagestyle{empty} \n\\begin{document} " );
	}
	beginpicture(4);
}

sub fussdatei {
	endpicture(11);
	if ( $kopf == 1 ) { latex( 11, "\\end{document}" ); }
}
#### Pictureumgebung
sub beginpicture {
	my ($layer) = @_;
	schreibeinarray(
		$layer,
		sprintf(
			"\\begin{pspicture}(%g,%g)(%g,%g)\n",
			getminmax( "x", "min" ),
			getminmax( "y", "min" ),
			getminmax( "x", "max" ),
			getminmax( "y", "max" )
		)
	);
}

sub endpicture {
	my ($layer) = @_;
	latex( $layer, "\\end{pspicture}" );
}

# Die Eingabedatei wird gelesen
sub leseeingabedatei {
	my $dateiname = shift(@_);
	my $zeile;
	open( my $EINGABEDATEI, $dateiname )
	  || die $dateiname . ": $!";
	while ( $zeile = <$EINGABEDATEI> ) {

# Zeilenenden beseitigen, Kommentare und Leerzeilen ignorieren
		$zeile =~ s/[\r\n]//g;
		$zeile =~ s/ +/ /g;
		$zeile =~ s/ +$//g;
		$zeile =~ s/^ +//g;
		next if ( $zeile =~ /^\#/ );
		next if ( $zeile =~ /^$/ );
		if ( $zeile =~ /^lesedatei (.*)$/i ) {
			leseeingabedatei($1);
		} else {
			$eingabedatei[$eingabedateizeilen] = $zeile;
			$eingabedateizeilen++;
		}
	}
	close($EINGABEDATEI);
}
### Minimum und Maximum setzen
sub setminmax {
	my ( $min, $xodery, $minmax ) = @_;
	if ( $xodery eq "x" ) {
		if ( $minmax eq "min" ) { $xmin = $min; }
		else { $xmax = $min; }
	}
	if ( $xodery eq "y" ) {
		if ( $minmax eq "min" ) { $ymin = $min; }
		else { $ymax = $min; }
	}
}

sub getminmax {
	my ( $xodery, $minmax ) = @_;
	if ( $xodery eq "x" ) {
		if ( $minmax eq "min" ) { return $xmin; }
		else { return $xmax; }
	}
	if ( $xodery eq "y" ) {
		if ( $minmax eq "min" ) { return $ymin; }
		else { return $ymax; }
	}
}
## Minimum und Maximum bestimmen
sub minmax {
	my ( $xminlokal, $xmaxlokal, $yminlokal, $ymaxlokal ) =
	  @_;
	if ( $xminlokal < getminmax( "x", "min" ) ) {
		setminmax( $xminlokal, "x", "min" );
	}
	if ( $xmaxlokal > getminmax( "x", "max" ) ) {
		setminmax( $xmaxlokal, "x", "max" );
	}
	if ( $yminlokal < getminmax( "y", "min" ) ) {
		setminmax( $yminlokal, "y", "min" );
	}
	if ( $ymaxlokal > getminmax( "y", "max" ) ) {
		setminmax( $ymaxlokal, "y", "max" );
	}
}

sub degtorad {
	my ($wert) = @_;
	return $wert * pi() / 180;
}

sub radtodeg {
	my ($wert) = @_;
	return $wert * 180 / pi();
}
my $abstand = 0;

sub setabstand {
	my ($wert) = @_;
	$abstand = $wert;
}

sub getabstand {
	return $abstand;
}
my ( $wellenlaenge1, $wellenlaenge2 );
$wellenlaenge1 = $wellenlaenge2 = 1;

sub setwelleeins {
	my ($wert) = @_;
	$wellenlaenge1 = $wert;
}

sub setwellezwei {
	my ($wert) = @_;
	$wellenlaenge2 = $wert;
}

sub getwelleeins {
	return $wellenlaenge1;
}

sub getwellezwei {
	return $wellenlaenge2;
}
my $anzahl = 4;

sub setkreisanzahl {
	my ($wert) = @_;
	$anzahl = $wert;
}

sub getkreisanzahl {
	return $anzahl;
}
my $liniendicke = 1;

sub setliniendicke {
	my ($wert) = @_;
	$liniendicke = $wert;
}

sub getliniendicke {
	return $liniendicke;
}

sub seterreger {
	my ( $abstand, $wellenlaenge1, $wellenlaenge2, $anzahl,
		$liniendicke )
	  = @_;
	$e = $abstand / 2;
	kommentar( 2, "Abstand Erreger: " . $abstand );
	kommentar( 2,
		"Wellenlaenge Erreger 1: " . $wellenlaenge1 );
	kommentar( 2,
		"Wellenlaenge Erreger 2: " . $wellenlaenge2 );
	kommentar( 2, "Anzahl Kreise: " . $anzahl );
	ausgabe(
		    "\\psset{linecolor=black, fillcolor=black!20, "
		  . "linestyle=solid, linewidth= "
		  . $liniendicke
		  . "pt, dotstyle = *, plotpoints = 1000, dotsize = 3pt,"
		  . " arrowsize = 3pt 2, arrowinset = 0.25, xunit = 1cm, "
		  . "yunit = 1cm, algebraic =true}
	"
	);
}
sub setboegen { my $wert = @_; $boegen = $wert; }
sub getboegen { return $boegen; }
## Die Kreise werden gezeichnet
sub erzeugekreise {
	my ( $x, $lambda, $start, $anzahlkreise ) = @_;
	minmax(
		$x - $lambda * ($anzahlkreise),
		$x + $lambda * ($anzahlkreise),
		-$lambda * ($anzahlkreise),
		$lambda * ($anzahlkreise)
	);
	if ( getboegen() == 1 ) {
		$anzahlkreise = 5 * $anzahlkreise;
	} else {
		$anzahlkreise = $anzahlkreise;
	}
	if ( $start == 0 ) {
		schreibeinarray(
			10,
			sprintf(
				"\\multido{\\nx=0+%f}{%i}{",
				$lambda, $anzahlkreise
			)
		);
		schreibeinarray(
			10,
			sprintf(
				"\\pscircle[linewidth=1pt](%f,0){\\nx}}\n",
				$x )
		);
		schreibeinarray(
			10,
			sprintf(
				"\\multido{\\nx=%f+%f}{%i}{",
				$lambda / 2,
				$lambda, $anzahlkreise
			)
		);
		schreibeinarray(
			10,
			sprintf(
"\\pscircle[linestyle=dashed, linewidth=1pt](%f,0){\\nx}}\n",
				$x )
		);
	} else {
		schreibeinarray(
			10,
			sprintf(
				"\\multido{\\nx=0+%f}{%i}{",
				$lambda, $anzahlkreise
			)
		);
		schreibeinarray(
			10,
			sprintf(
"\\pscircle[linestyle=dashed, linewidth=1pt](%f,0){\\nx}}\n",
				$x )
		);
		schreibeinarray(
			10,
			sprintf(
				"\\multido{\\nx=%f+%f}{%i}{",
				$lambda / 2,
				$lambda, $anzahlkreise
			)
		);
		schreibeinarray(
			10,
			sprintf(
				"\\pscircle[linewidth=1pt](%f,0){\\nx}}\n",
				$x )
		);
	}
}

sub hyperbelfunktion {
	my ( $a, $e, $ymin, $ymax, $farbe ) = @_;
	my $b = sqrt( $e * $e - $a * $a );
	my $i = 0;
	my $t = 0;
	for ( $i = 0 ; $i <= 3 ; $i = $i + 1 / 1000 ) {
		if ( $b * sinh($i) < $ymax ) {
			$t = $i;
		} else {
			$t = $t;
		}
	}
	schreibeinarray(
		10,
		sprintf(
"\\parametricplot[linecolor=%s]{%g}{%g}{%g*COSH(t)|%g*SINH(t)}",
			$farbe, -$t, $t, $a, $b
		)
	);
	schreibeinarray(
		10,
		sprintf(
"\\parametricplot[linecolor=%s]{%g}{%g}{%g*COSH(t)|%g*SINH(t)}",
			$farbe, -$t, $t, -$a, -$b
		)
	);
}

sub kreisboegen {
	my ( $x1, $laenge, $kreise, $start ) = @_;
	my (
		$xabstandlinks, $xabstandrechts, $alpha,
		$beta,          $gamma,          $delta,
		$i,             $abstand,        $eckelinks,
		$eckerechts,    $berg,           $tal,
	);
	if ( $start == 0 ) { $berg = "solid"; $tal = "dashed"; }
	else { $berg = "dashed"; $tal = "solid"; }
}

sub kreisboegen2 {
	my ( $x1, $laenge, $kreise, $start ) = @_;
	my (
		$xabstandlinks, $xabstandrechts, $alpha,
		$beta,          $gamma,          $delta,
		$i,             $abstand,        $eckelinks,
		$eckerechts,    $berg,           $tal,
	);
	if ( $start == 0 ) { $berg = "solid"; $tal = "dashed"; }
	else { $berg = "dashed"; $tal = "solid"; }
	$xabstandlinks  = abs( $x1 - $xmin );
	$xabstandrechts = abs( $xmax - $x1 );
	$eckelinks      =
	  sqrt(
		$ymax * $ymax + $xabstandlinks * $xabstandlinks );
	$eckerechts =
	  sqrt(
		$ymax * $ymax + $xabstandrechts * $xabstandrechts );

	for ( $i = 0 ; $i <= 100 ; $i++ ) {
		$abstand = ( $kreise * $laenge ) + $laenge * $i;
		if ( $abstand <= $xabstandlinks ) {
			$beta =
			  nachkommastellen(
				radtodeg( acos( $ymax / $abstand ) ), 4 );
			if ( $abstand <= $eckelinks ) {
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$berg,    $x1,
						$abstand, 90 + $beta,
						270 - $beta
					)
				);
			}
		} else {
			$alpha = nachkommastellen(
				radtodeg(
					acos( $xabstandlinks / $abstand )
				),
				4
			);
			$beta =
			  nachkommastellen(
				radtodeg( acos( $ymax / $abstand ) ), 4 );
			if ( $abstand <= $eckelinks ) {
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$berg,    $x1,
						$abstand, 90 + $beta,
						180 - $alpha
					)
				);
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$berg,    $x1,
						$abstand, 180 + $alpha,
						270 - $beta
					)
				);
			}
		}
		if ( $abstand <= $xabstandrechts ) {
			$delta =
			  nachkommastellen(
				radtodeg( acos( $ymax / $abstand ) ), 4 );
			if ( $abstand <= $eckerechts ) {
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$berg,    $x1,
						$abstand, 270 + $delta,
						90 - $delta
					)
				);
			}
		} else {
			$gamma = nachkommastellen(
				radtodeg(
					acos( $xabstandrechts / $abstand )
				),
				4
			);
			$delta =
			  nachkommastellen(
				radtodeg( acos( $ymax / $abstand ) ), 4 );
			if ( $abstand <= $eckerechts ) {
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$berg,  $x1, $abstand,
						$gamma, 90 - $delta
					)
				);
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$berg,    $x1,
						$abstand, 270 + $delta,
						360 - $gamma
					)
				);
			}
		}
	}
	for ( $i = 0 ; $i <= 100 ; $i++ ) {
		$abstand =
		  ( $kreise * $laenge + $laenge / 2 ) + $laenge *
		  $i;
		if ( $abstand <= $xabstandlinks ) {
			$beta =
			  nachkommastellen(
				radtodeg( acos( $ymax / $abstand ) ), 4 );
			if ( $abstand <= $eckelinks ) {
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$tal,     $x1,
						$abstand, 90 + $beta,
						270 - $beta
					)
				);
			}
		} else {
			$alpha = nachkommastellen(
				radtodeg(
					acos( $xabstandlinks / $abstand )
				),
				4
			);
			$beta =
			  nachkommastellen(
				radtodeg( acos( $ymax / $abstand ) ), 4 );
			if ( $abstand <= $eckelinks ) {
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$tal,     $x1,
						$abstand, 90 + $beta,
						180 - $alpha
					)
				);
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$tal,     $x1,
						$abstand, 180 + $alpha,
						270 - $beta
					)
				);
			}
		}
		if ( $abstand <= $xabstandrechts ) {
			$delta =
			  nachkommastellen(
				radtodeg( acos( $ymax / $abstand ) ), 4 );
			if ( $abstand <= $eckerechts ) {
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$tal,     $x1,
						$abstand, 270 + $delta,
						90 - $delta
					)
				);
			}
		} else {
			$gamma =
			  radtodeg(
				acos( $xabstandrechts / $abstand ) );
			$delta = radtodeg( acos( $ymax / $abstand ) );
			if ( $abstand <= $eckerechts ) {
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$tal,   $x1, $abstand,
						$gamma, 90 - $delta
					)
				);
				schreibeinarray(
					10,
					sprintf(
"\\psarc[linestyle=%s](%g,0){%g}{%g}{%g}",
						$tal,     $x1,
						$abstand, 270 + $delta,
						360 - $gamma
					)
				);
			}
		}
	}
	ausgabe("");
}

sub hyperbel {
	my ( $e, $laenge1, $laenge2, $anzahl ) = @_;
	my (
		$a,     $s,     $d,     $n,     $x, $y,
		$xhilf, $yhilf, $xnext, $ynext, $genau
	);
	$genau = 0;
	$d     = ceil($e);
	for ( $n = 0 ; $n <= $anzahl ; $n++ ) {
		$s     = $laenge1 * $n;
		$xhilf =
		  nachkommastellen(
			( 2 * $d * $s + $s * $s ) / ( 4 * $e ), 4 );
		if ( ( $d * $d - ( $xhilf - $e ) * ( $xhilf - $e ) )
			>= 0 )
		{
			$yhilf = nachkommastellen(
				sqrt(
					$d * $d - ( $xhilf - $e ) *
					  ( $xhilf - $e )
				),
				4
			);
			$a = (
				sqrt(
					( $xhilf - $e ) * ( $xhilf - $e ) +
					  $yhilf * $yhilf
				  ) - sqrt(
					( $xhilf + $e ) * ( $xhilf + $e ) +
					  $yhilf * $yhilf
				  )
			) / 2;
			if ( $diff == 1 ) {
				hyperbelfunktion( $a, $e, -$ymax, $ymax,
					"blue" );
			} else {
				hyperbelfunktion( $a, $e, -$ymax, $ymax,
					"red" );
			}
		}
	}
	for ( $n = 1 ; $n <= $anzahl ; $n++ ) {
		$s     = ( 2 * $n - 1 ) * $laenge1 / 2;
		$xhilf = ( 2 * $d * $s + $s * $s ) / ( 4 * $e );
		if ( ( $d * $d - ( $xhilf - $e ) * ( $xhilf - $e ) )
			>= 0 )
		{
			$yhilf =
			  sqrt(
				$d * $d - ( $xhilf - $e ) * ( $xhilf - $e )
			  );
			$a = (
				sqrt(
					( $xhilf - $e ) * ( $xhilf - $e ) +
					  $yhilf * $yhilf
				  ) - sqrt(
					( $xhilf + $e ) * ( $xhilf + $e ) +
					  $yhilf * $yhilf
				  )
			) / 2;
			if ( $diff == 1 ) {
				hyperbelfunktion( $a, $e, -$ymax, $ymax,
					"red" );
			} else {
				hyperbelfunktion( $a, $e, -$ymax, $ymax,
					"blue" );
			}
		}
	}
}
my $start1 = 0;
my $start2 = 0;
$kommandodateinummer = 0;
while ( exists $ARGV[$kommandodateinummer] ) {
	$kommandodatei = $ARGV[$kommandodateinummer];
	$texdatei      = $kommandodatei;
	$texdatei =~ s/\.ptxt$//i;
	$texdatei = $texdatei . " . adam ";
	$kommandodateinummer++;
	$eingabedateizeilen = 0;
	leseeingabedatei($kommandodatei);
	for ( $i = 0 ; $i < $eingabedateizeilen ; $i++ ) {
		$zeile = $eingabedatei[$i];
		if ( $zeile =~ /^abstand( [-0-9\.]+)$/i ) {
			setabstand($1);
		} elsif ( $zeile =~ /^anzahlkreise( [-0-9\.]+)$/i )
		{
			setkreisanzahl($1);
		} elsif ( $zeile =~
			/^wellenlaenge( [-0-9\.]+),([-0-9\.]+)$/i )
		{
			setwelleeins($1);
			setwellezwei($2);
		} elsif ( $zeile =~ /^gegen$/i ) {
			$start2 = 1;
			$diff   = 1;
		} elsif ( $zeile =~ /^boegen$/i ) {
			setboegen(1);
		} elsif ( $zeile =~ /^hyperbel$/i ) {
			$hyperbel = 1;
		}

		# Alle anderen Befehle sind Schrott
		else {
			printf( "%% Unbekannter Befehl '%s'\n",
				$zeile );
		}
	}
}
seterreger(
	getabstand(),   getwelleeins(),
	getwellezwei(), getkreisanzahl(),
	getliniendicke()
);
erzeugekreise( -$e, getwelleeins(), $start1,
	getkreisanzahl() );
erzeugekreise( $e, getwellezwei(), $start2,
	getkreisanzahl() );
if ( $hyperbel == 1 ) {
	hyperbel( $e, getwelleeins(), getwellezwei(), 1000 );
}
$leer = 1;
my $layer;
for ( $layer = 0 ; $layer <= 100 ; $layer++ ) {

	for ( $i = 0 ; $i < $ausgabedateizeilen[$layer] ; $i++ )
	{
		$leer = 0;
	}
}
if ( $leer == 0 ) {
	kopfdatei();
	fussdatei();
	for ( $layer = 0 ; $layer <= 11 ; $layer++ ) {
		for (
			$i = 0 ;
			$i < $ausgabedateizeilen[$layer] ;
			$i++
		  )
		{
			printf( "%s \n", $ausgabedatei[$layer][$i] );
		}
	}
} else {
	printf("%% Die Datei ist leer \n");
}


