Bitte warten...

PHP: Geometrische Funktionen

PHP bietet praktisch für alle gängigen geometrischen Aufgaben entsprechende trigonometrische Funktionen zur Berechnung von Winkeln und Strecken. Die wichtigsten sind:

sin() und asin() - Sinus und Arkussinus
cos() und acos() - Kosinus und Arkuskosinus
tan() und atan() - Tangens und Arkustangens
hypot() - Länge einer Hypotenuse
pi() - die Kreiszahl π

Bei der Verwendung dieser Funktionen ist zu beachten, dass Winkel nicht in Grad, sondern in Radiant angegeben werden. Das heißt, der Vollkreis von 360° beträgt 2 π (ca. 6,28), der Halbkreis von 180° entsprechend 1 π (ca. 3,14) und der Viertelkreis von 90° demnach π / 2 (ca. 1,57). Für die Umrechnung stehen folgende Funktionen zur Verfügung:

deg2rad() - Umrechnung von Grad in Radiant
rad2deg() - Umrechnung von Radiant in Grad

Außerdem sollte man das Problem der Nichtumwandelbarkeit vieler Gleitkommazahlen in Binärzahlen bedenken, die insbesondere bei Vergleichsoperationen zu unerwarteten Ergebnissen führen kann:

cos(pi() / 2) ergibt 6.1232339957368E-17 statt 0.
tan(pi()) ergibt -1.2246467991474E-16 statt 0.
tan(pi() / 2) ergibt 1.6331239353195E+16 statt usw.

Häufig benötigt man zusätzlich folgende Funktionen:

pow() - Potenz
sqrt() - Quadratwurzel

Die hier vorgestellten Funktionen greifen gelegentlich auf andere Funktionen zurück, die an anderer Stelle auf dieser Seite erläutert werden. Um einzelne Funktionen verwenden zu können, müssen daher auch die anderen benötigten Funktionen zur Verfügung stehen!

Berechnung von Koordinaten

Innerhalb eines Koordinatensystems wird die Beziehung zwischen einzelnen Punkten im Wesentlichen durch ihren Abstand zueinander und durch den Winkel zwischen einer imaginären Verbindungslinie und einer Bezugsachse bestimmt.

In diesem Beispiel haben wir ein Koordinatensystem, bei dem die horizontale Position nach rechts und die vertikale Position nach unten hin zunimmt. Der Nullpunkt befindet sich also in der oberen linken Ecke.

P₀ P₁ dx dy c α₁ β₁ α₂ β₂ P₀ (5;6) P₁ (1;4) P₂ (9;4) P₃ (9;8)

Der diagonale Abstand der Punkte zueinander $c kann mit Hilfe des Satzes des Pythagoras berechnet werden. Der horizontale Abstand $dx und der vertikale Abstand $dy errechnen sich aus der Differenz der jeweiligen Koordinaten.

$c = hypot($dx, $dy); bzw.
$c = sqrt(pow($dx, 2) + pow($dy, 2));

Die Winkel können durch Arkussinus- bzw. Arkuskosinusberechnung ermittelt werden.

Über den Arkussinus lassen sich die Winkel zwischen der Hypotenuse $c und den Ankatheten des Dreiecks zwischen zwei Punkten bestimmen. Der Wert liegt hier immer zwischen –90° und +90°, wobei das Vorzeichen angibt, ob sich der Punkt P₁ links oder rechts bzw. ober- oder unterhalb von P₀ befindet, je nachdem, ob der Arkussinus auf $dx für den Winkel α₁ oder auf $dy für den Winkel β₁ angewendet wurde. Für eine eindeutige Bestimmung der Position von P₁ ist die Berechnung eines einzelnen Winkels über den Arkussinus nicht ausreichend, da im Beispiel der Winkel α₁ der Punkte P₂ und P₃ sowie der Winkel β₁ der Punkte P₁ und P₂ den gleichen Wert haben.

Über den Arkuskosinus lassen sich die Winkel zwischen der Hypotenuse $c und dem positiven Abschnitt der Achsen, die durch den Punkt P₀ laufen, bestimmen. Der Wert liegt hier immer zwischen 0° und 180°, wodurch sich anhand des Winkels feststellen lässt, ob sich der Punkt P₁ links oder rechts bzw. ober- oder unterhalb von P₀ befindet, je nachdem, ob der Arkuskosinus auf $dx für den Winkel β₂ oder auf $dy für den Winkel α₂ angewendet wurde. Für eine eindeutige Bestimmung der Position von P₁ ist die Berechnung eines einzelnen Winkels über den Arkuskosinus nicht ausreichend, da im Beispiel der Winkel α₂ der Punkte P₁ und P₂ sowie der Winkel β₂ der Punkte P₂ und P₃ den gleichen Wert haben.

Code kopieren
  $points = [
    [5,6],  # P0
    [1,4],  # P1
    [9,4],  # P2
    [9,8],  # P3
  ];
  
  for ($i = 1; $i < count($points); $i++) {
    $dx = $points[$i][0] - $points[0][0];
    $dy = $points[$i][1] - $points[0][1];
    $c  = hypot($dx, $dy);  # == sqrt(pow($dx, 2) + pow($dy, 2));

    if ($c != 0) {
      $alpha1 = asin($dx / $c);
      $beta1  = asin($dy / $c);
      $alpha2 = acos($dy / $c);
      $beta2  = acos($dx / $c);
    } else $alpha1 = $beta1 = $alpha2 = $beta2 = 0;

    echo "P".$i.": ";
    echo "c = ".$c."; ";
    echo "α₁ = ".rad2deg($alpha1)."; ";
    echo "β₁ = ".rad2deg($beta1)."; ";
    echo "α₂ = ".rad2deg($alpha2)."; ";
    echo "β₂ = ".rad2deg($beta2)."<br>\r\n";
  }

Wie man sieht, werden auf diese Weise für die Beschreibung des Verhältnisses zwischen zwei Punkten im Koordinatensystem immer drei Parameter benötigt: der Abstand $c sowie zwei Winkel, die über den Arkussinus oder den Arkuskosinus bestimmt wurden.

Einfacher wäre es dagegen, wenn das Verhältnis der Punkte lediglich durch ihren Abstand zueinander sowie einen einzigen Winkel des Dreiecks zwischen ihnen beschrieben werden könnte, wobei dieser Winkel einen Wert zwischen 0° und 360° annehmen können müsste.

P₀ P₁ dx dy c α₁ β₁ α₂ β₂ P₀ P₁ dx dy c δ

Die Funktion coord_props() implementiert diese Anforderung. Sie erwartet den Ausgangs- sowie den Zielpunkt als Argumente $p0 und $p1 und gibt ein Array zurück, das den Abstand der Punkte und den Winkel δ enthält, der rechtsdrehend von dem negativen Abschnitt der senkrechten Achse gemessen wird, die durch den Punkt P₀ verläuft.

Code kopieren
  function coord_props($p0, $p1) {
    if ($p0[0] == $p1[0] && $p0[1] == $p1[1]) return [0, 0];
    else {
      $dx = $p1[0] - $p0[0];
      $dy = $p1[1] - $p0[1];
      $c = hypot($dx, $dy);
      $alpha = asin($dx / $c);
      $delta = ($dy <  0) * (($dx < 0) * 2 * pi() + $alpha) +
               ($dy >= 0) * (                pi() - $alpha);
      return [$c, $delta];
    }
  }

  $points = [
    [5,6],  # P0
    [1,4],  # P1
    [9,4],  # P2
    [9,8],  # P3
  ];
  
  for ($i = 1; $i < count($points); $i++) {
    $props = coord_props($points[0], $points[$i]);
    $c     = $props[0];
    $delta = $props[1];

    echo "P".$i.": ";
    echo "c = ".$c."; ";
    echo "δ = ".rad2deg($delta)."<br>\r\n";
  }

Mit der folgenden Funktion coord_pos() lassen sich nun umgekehrt die Koordinaten eines Punktes ermitteln, der sich zu einem gegebenen Punkt $p0 im Abstand $c mit dem Winkel $delta befindet.

Code kopieren
  function coord_pos($p0, $c, $delta) {
    $x = $p0[0] + sin($delta) * $c;
    $y = $p0[1] - cos($delta) * $c;
    return [$x, $y];
  }

  $p0 = [0,0];
  $c = 4;

  for ($i = 0; $i < 8; $i++) {
    $delta = deg2rad($i * 45);
    
    $pos = coord_pos($p0, $c, $delta);
    $x = number_format($pos[0], 2, ".", "");
    $y = number_format($pos[1], 2, ".", "");
    
    echo "P".($i + 1)." [".$x.";".$y."]: ";
    echo "c = ".$c."; ";
    echo "δ = ".rad2deg($delta)."<br>\r\n";
  }

Schnittpunkte ermitteln

Unter Umständen möchte man feststellen, ob und an welchem Punkt sich die Achsen zweier Strecken schneiden und ob sich auch die Strecken selbst schneiden.

P₀ P₁ P₂ P₃ P₄ P₅ S₂ S₀

Die folgende Funktion coord_intersect() erwartet dazu zwei Wertepaare, die aus den Koordinaten der Endpunkte zweier zu vergleichender Strecken bestehen. Je nach Konstellation der Linien zueinander werden verschiedene Rückgabewerte generiert (s. Beispiel).

Code kopieren
  function coord_round($n) {
    # normalizes numbers to buffer floating point problem
    # you can lower the sensitivity by decreasing argument #2 to get rougher results
    return round($n, 12);
  }

  function coord_round_pos($pos) {
    # normalizes coordinates to buffer floating point problem
    return [coord_round($pos[0]), coord_round($pos[1])];
  }

  function coord_positive_angle($alpha) {
    # converts negative angles to positive
    if ($alpha < 0) return ($alpha + 2 * pi()); else return $alpha;
  }

  function coord_sign($n) {
    # returns the sign of a number
    if ($n < 0) return -1; else return 1;
  }
  
  function coord_intersect($l0, $l1) {
    $props0 = coord_props($l0[0], $l0[1]);
    $props1 = coord_props($l1[0], $l1[1]);
    
    if (coord_round($props0[0]) == 0 || coord_round($props1[0]) == 0) {  # one line has zero length
      $ret0 = 0;
      $ret1 = 0;
    } elseif (
      coord_round($props0[1]) == coord_round($props1[1]) ||
      coord_round($props0[1]) == coord_round($props1[1] - pi()) ||
      coord_round($props1[1]) == coord_round($props0[1] - pi())
    ) {  # lines are parallel
      
        $props = coord_props($l0[0], $l1[0]);
        if (
          coord_round($props[1]) == coord_round($props0[1]) ||
          coord_round($props[1]) == coord_round(coord_positive_angle($props0[1] - pi())) ||
          $props[0] == 0
        ) {  # lines share the same axis
          $ret0 = 2;
          $ret1 = 0;
        } else {  # lines have different axes
          $ret0 = 1;
          $ret1 = 0;
        }
      
    } else {  # axes intersect
      
      $dx = $l1[0][0] - $l0[0][0];
      $dy = $l1[0][1] - $l0[0][1];
      
      $alpha = $props0[1] - 0.5 * pi();
      $beta  = 1.5 * pi() - $props1[1];
      
      if (coord_round(sin($beta)) == 0) {
        $gamma = pi() - $props0[1];
        $c0 = $dy / cos($gamma);  # result of cos() is never 0
        $c1 = ($dx - sin($gamma) * $c0) * -1 * coord_sign($l1[1][0] - $l1[0][0]);
        $edges = [$c0, $c1];
        $pos = $l1[0];
      } else {
        $c = $dy / sin($beta);
        $edges = coord_edges($dx + cos($beta) * $c, $alpha, $beta);
        $pos = coord_pos($l1[0], $c * -1,   $props1[1]);
      }
      
      $s0 = coord_pos($l0[0], $edges[0], $props0[1]);
      $s1 = coord_pos($pos,   $edges[1], $props1[1]);  # must be equal to $s0
      
      $ret1 = $s0;
      
      # check if lines intersect
      $d00 = coord_props($l0[0], $s0);
      $d01 = coord_props($l0[1], $s0);
      $d10 = coord_props($l1[0], $s0);
      $d11 = coord_props($l1[1], $s0);
      
      if (  # V intersection
        coord_round_pos($l0[0]) == coord_round_pos($l1[0]) ||
        coord_round_pos($l0[0]) == coord_round_pos($l1[1]) ||
        coord_round_pos($l0[1]) == coord_round_pos($l1[0]) ||
        coord_round_pos($l0[1]) == coord_round_pos($l1[1])
      ) $ret0 = 4;
      elseif (  # T intersection
        (
          coord_round($d00[1]) != coord_round($d01[1]) &&
          (coord_round_pos($l1[0]) == coord_round_pos($s0) || coord_round_pos($l1[1]) == coord_round_pos($s0))
        ) ||
        (
          coord_round($d10[1]) != coord_round($d11[1]) &&
          (coord_round_pos($l0[0]) == coord_round_pos($s0) || coord_round_pos($l0[1]) == coord_round_pos($s0))
        )
      ) $ret0 = 5;
      elseif (  # X intersection
        coord_round($d00[1]) != coord_round($d01[1]) &&
        coord_round($d10[1]) != coord_round($d11[1])
      ) $ret0 = 6;
      else $ret0 = 3;  # no intersection
      
    }
    
    return [$ret0, $ret1];
  }
  
  $lines = [
    [
      [2,1],
      [3,5],
    ],
    [
      [9,3],
      [6,6],
    ],
  );
  
  $sect = coord_intersect($lines[0], $lines[1]);
  if ($sect[0] > 2) {
    echo "Schnittpunkt: [".$sect[0][0].";".$sect[0][1]."]; ";
    if ($sect[0] == 6) echo "schneiden sich";
    elseif ($sect[0] == 5) echo "berühren sich T-Form";
    elseif ($sect[0] == 4) echo "berühren sich V-Form";
    else echo "schneiden sich nicht";
  } elseif ($sect[0] == 2) {
    echo "fluchtend";
  } elseif ($sect[0] == 1) {
    echo "parallel";
  } else $text = "keine Linie";

Und hier der Code in Aktion:

Prüfen, ob sich ein Punkt in einem Dreieck befindet

Um festzustellen, ob sich ein Punkt innerhalb eines gegebenen Dreiecks befindet, muss überprüft werden, ob alle Winkel zwischen dem erwähnten Punkt und den drei Eckpunkten des Dreiecks kleiner als 180° bzw. π sind. Ist dies nicht der Fall, so befindet sich der Punkt außerhalb des Dreiecks.

T₀ T₁ T₂ P₀ α β γ T₀ T₁ T₂ P₁ α β γ

Die folgende Funktion coord_is_on_triangle() erwartet dazu als Argumente die Koordinaten des betreffenden Punktes und der Eckpunkte des Dreiecks innerhalb eines Arrays. Rückgabewert ist 2, wenn sich der Punkt im Dreieck befindet. Liegt der Punkt direkt auf der Verbindungslinie der Eckpunkte, wird 1 zurückgegeben, ansonsten 0.

Code kopieren
  function coord_positive_angle($alpha) {
    # converts negative angles to positive
    if ($alpha < 0) return ($alpha + 2 * pi()); else return $alpha;
  }

  function coord_is_on_triangle($p0, $tri) {
    # checks if point $p0 is part of triangle $tri
    $a = [];
    foreach ($tri as $p1) {
      $props = coord_props($p0, $p1);
      $a[] = $props[1];
    }
    reset($tri);
    # the amount of negative angles depends on the direction of the points in the triangle
    $negative = 0;
    $alpha = $a[1] - $a[0];
    if ($alpha < 0) $negative++;
    $beta  = $a[2] - $a[1];
    if ($beta  < 0) $negative++;
    $gamma = $a[0] - $a[2];
    if ($gamma < 0) $negative++;
    if ($negative == 2) $sg = -1; else $sg = 1;
    $alpha = coord_positive_angle($alpha * $sg);
    $beta  = coord_positive_angle($beta  * $sg);
    $gamma = coord_positive_angle($gamma * $sg);
    # if any of the three angles between point $p0 and the triangle corners is > 180° $p0 is outside the triangle
    if     ($alpha <  pi() && $beta <  pi() && $gamma <  pi()) return 2;
    elseif ($alpha == pi() && $beta == pi() && $gamma == pi()) return 1;
    else return 0;
  }
  
  $points = [
    [5,6],  # P0
    [8,3],  # P1
  ];
  
  $tri = [
    [4,1],  # T0
    [2,8],  # T1
    [9,9],  # T2
  ];
  
  for($i = 0; $i < count($points); $i++) {
    echo "Punkt P".$i." [".$points[$i][0].";".$points[$i][1]."] befindet sich ";
    if (coord_is_on_triangle($points[$i], $tri) == TRUE) echo "innerhalb"; else echo "außerhalb";
    echo " des Dreiecks.<br>\r\n";
  }
  reset($points);

Seiten eines beliebigen Dreiecks berechnen

Sind die Länge einer Seite und die angrenzenden Winkel bekannt, so können die Längen der übrigen Seiten errechnet werden, indem man das Dreieck an der Höhe über einer gesuchten Seite teilt und die Eigenschaften der Teildreiecke berechnet.

a α β b c b₂ b₁ hb

Die Funktion coord_edges() erwartete als Argumente dazu die Länge der bekannten Seite a und die Größen der angrenzenden Winkel α und β. Der Rückgabewert ist ein Array mit den Längen der Seiten b und c.

Code kopieren
  function coord_edges($a, $alpha, $beta) {
    # calculates the lengths of the other edges of a triangle with edge length $a and $alpha and $beta to be the angles next to $a.
    $hb = sin($alpha) * $a;
    $gamma = pi() - $alpha - $beta;
    $c = $hb / sin($gamma);
    $b1 = $a * cos($alpha);
    $b2 = $c * cos($gamma);
    $b = $b1 + $b2;
    return [$b, $c];
  }

  $edges = coord_edges(12.5, deg2rad(58), deg2rad(64));
  echo "b = ".$edges[0]."<br>";
  echo "c = ".$edges[1]."<br>";

Fläche eines beliebigen Dreiecks berechnen

Die Fläche eines beliebigen Dreiecks, dessen Seitenlängen bekannt sind, errechnet sich relativ einfach aus der Hälfte des Produktes aus einer Seitenlänge und der Höhe auf diese Seite:

Formel 1

Die Höhe errechnet sich nach folgender Formel aus dem Pythagorassatz:

Formel 2

Der Abschnitt c1 errechnet sich nach dieser Formel:

Formel 3

T₀ T₁ T₂ a b c c₁ c₂ hc

Dazu erwartet die folgende Formel coord_triangle_area() ein Array, das die drei Wertepaare der Eckpunktkoordinaten des Dreiecks enthält. Der Rückgabewert ist die Fläche des Dreiecks.

Code kopieren
  function coord_triangle_area($tri) {
    # calculates the area of an arbitrary triangle between given points
    $props0 = coord_props($tri[0], $tri[1]);
    $props1 = coord_props($tri[1], $tri[2]);
    $props2 = coord_props($tri[2], $tri[0]);
    $a = $props0[0];
    $b = $props1[0];
    $c = $props2[0];
    if (coord_round($a) != 0 && coord_round($b) != 0 && coord_round($c) != 0) {
      $c1 = (pow($a, 2) - pow($b, 2) - pow($c, 2)) / (-2 * $c);
      $hc1 = sqrt(pow($b, 2) - pow($c1, 2));
      # just for the record, hc1 and hc2 should be equal:
      # $c2 = $c - $c1;
      # $hc2 = sqrt(pow($a, 2) - pow($c2, 2));
      $area = $c * $hc1 / 2;
      #echo "<!-- ".$c1." -->\r\n";
    } else $area = 0;
    return $area;
  }

  $tri = [
    [4,1],  # T0
    [2,8],  # T1
    [9,9],  # T2
  ];
  
  echo "Fläche = ".coord_triangle_area($tri);

Beliebige Flächen bestimmen

Mit folgender Funktion lässt sich die Fläche eines beliebigen Polygons bestimmen:

Code kopieren
  function coord_path_area($points) {
    $area = 0;
    $c = count($points);
    for ($i = 0; $i < $c; $i++) {
      $x1 = $points[$i][0];
      $y1 = $points[$i][1];
      $x2 = $points[coord_increase($i, $c)][0];
      $y2 = $points[coord_increase($i, $c)][1];
      $area += ($x1 - $x2) * ($y1 + $y2);
    }
    return ($area / 2);
  }

  $points = [
    [1,4],
    [5,2],
    [12,3],
    [6,13],
    [12,12],
    [10,10],
    [18,7],
    [18,14],
    [14,18],
    [3,16],
  ];

  $area = coord_path_area($points);
  echo "Fläche: ".$area." cm².";

Kurvenverlauf einer Ellipse

Eine Ellipse kann durch die Länge ihrer Halbachsen a und b beschrieben werden. Für die Punkte der Ellipse gilt, dass die Summe der Strecken zwischen einem beliebigen Punkt und den beiden Brennpunkten der Ellipse immer der doppelten Länge der großen Halbachse a entspricht. Außerdem gilt, dass jede Strecke, die aus den Teilstrecken a (große Halbachse) und b (kleine Halbachse) besteht und die die beiden Achsen miteinander verbindet, die jeweils durch die gegenüberliegenden Scheitelpunkte der Ellipse verlaufen, die Ellipse genau an dem Punkt schneidet, an dem sich die Teilstrecken a und b berühren, wie folgende Animation veranschaulicht:

a b

Es besteht also eine Relation zwischen dem Winkel α dieser Strecke zur Hauptachse der Ellipse und der Position des Schnittpunktes dieser Strecke mit der Ellipse. Die Position dieses Punktes relativ zum Mittelpunkt der Ellipse M lässt sich über folgende Gleichungen berechnen:

Formel 4 Formel 5

Wird für eine Umlaufbahn der Winkel der Strecke zur Hauptachse proportional zur Zeit ermittelt

Formel 6

wobei ein vollständiger Umlauf tU 360° also 2π entspricht, so ergibt sich aber keine Bahn mit konstanter Geschwindigkeit, da die regelmäßige Kreisbewegung der Strecke auf die Ellipse als gestauchten Kreis projiziert wird und der Verlauf der Geschwindigkeit so ebenfalls ›gestaucht‹ wird. Um die Hauptscheitelpunkte ist die Geschwindigkeit daher geringer als im Bereich um die Nebenscheitelpunkte.

Entsprechend der folgenden Darstellung werden für die korrekte Berechnung der Position des Punktes P folgende Werte benötigt:

α und r oder x oder y oder
β und s oder x oder y oder
x und y

a b c r s α β P x y t S

Die Länge der Strecke r lässt sich mit folgender Formel bestimmen (s. Polarkoordinaten bzgl. Brennpunkt):

Formel 7 für den linken bzw. Formel 21 für den rechten Brennpunkt.

oder in PHP:

$r = pow($b, 2) / ($a * (1 - $e * cos($alpha)));
$r = pow($b, 2) / ($a * (1 + $e * cos($alpha)));

Die Variable e enthält hier die numerische Exzentrizität der Ellipse, für die gilt:

Formel 8

Daraus folgt: Formel 9

Außerdem gilt:

Formel 22 $a = sqrt(pow($b, 2) + pow($c, 2));
Formel 23 $a = sqrt(-pow($b, 2) / (pow($e, 2) - 1));
Formel 24 $b = sqrt(pow($a, 2) - pow($e * $a, 2));

Die Länge der Strecke s lässt sich mit folgender Formel bestimmen (s. Polarkoordinaten bzgl. Mittelpunkt):

Formel 10 oder in PHP:

$s = $b / sqrt(1 - pow($e, 2) * pow(cos($beta), 2));

Position eines Objekts auf einer Keplerbahn berechnen

Ein Objekt, das sich auf einer sogenannten Keplerbahn um dessen Schwerpunkt bewegt, der sich in einem der Brennpunkte der elliptischen Bahn befindet, hat keine konstante Geschwindigkeit. Aufgrund der Gravitationskraft ist die Geschwindigkeit an der Apside in der Nähe des Zentralkörpers größer als an der entfernten Apside:

Die Polarkoordinaten des Objekts können mit Hilfe der Kepler-Gleichung bestimmt werden. Dazu wird die wahre Anomalie des Objekts errechnet. Das ist der Winkel zwischen der Periapsis und dem Objekt zu einem bestimmten Zeitpunkt mit dem Schwerpunkt als Scheitelpunkt. Die folgende Funktion anomaly() benötigt die numerische Exzentrizität der Ellipse sowie die Zeit, die seit der Passage des Objekts durch die Periapsis vergangen ist, als Argumente. Sie gibt die mittlere Anomalie $M, die exzentrische Anomalie $E sowie die wahre Anomalie $T zurück. $E wird hier mit Hilfe des Newton-Verfahrens in sechs Durchgängen ermittelt. Je höher die Anzahl der Durchgänge, umso größer die Genauigkeit.

Code kopieren
  function anomaly($e, $t) {
    $M = 2 * pi() * $t;
    $E = $M;
    for ($i = 0; $i < 6; $i++) {
      $E = $E - ($E - $e * sin($E) - $M) / (1 - $e * cos($E));
    }
    $T = acos((cos($E) - $e) / (1 - $e * cos($E))) * (1 - 2 * (sin($E) < 0));
    return [$M, $E, $T];
  }
  
  $a = 149597870.7;  // große Halbachse in km
  $ex = 0.0167;  // numerische Exzentrizität der Umlaufbahn
  $P = 365.256;  // Dauer der Bahnperiode (Umlaufzeit) in Tagen
  $f = 150.23 / $P;  // Quotient aus dem Zeitpunkt der Messung in Tagen und der Bahnperiode
  $anom = anomaly($ex, $f);
  $alpha = $anom[2];  // wahre Anomalie
  $r = $a - $a * $ex * cos($anom[1]);  // Abstand vom Brennpunkt zum Objekt
  echo rad2deg($alpha);

Äquatoriale und horizontale Koordinaten berechnen

Mit den folgenden Funktionen lassen sich aus geozentrisch-ekliptikalen Koordinaten eines Himmelskörpers die entsprechenden äquatorialen bzw. horizontalen Koordinaten ermitteln. Wobei gilt:

$lat = ekliptikale Breite
$lon = ekliptikale Länge
$obliq = Schiefe der Ekliptik
$lat2 = geografische Breite des Beobachters
$lmst = Sternzeit als Winkel

(Diese Funktionen wurden bei der Planetenkarte eingesetzt.)

Code kopieren
  function equatorial($lat, $lon, $obliq) {
    # returns equatorial from geocentric ecliptic coordinates
    $dec = asin( cos($obliq) * sin($lat) + sin($obliq) * cos($lat) * sin($lon));
    $ra  = atan2(cos($obliq) * sin($lon) - sin($obliq) * tan($lat),  cos($lon));
    $ra += 2 * pi() * ($ra < 0);
    return [$dec, $ra];
  }

  function horizontal($lat, $lon, $lat2, $lmst) {
    # returns horizontal from geocentric ecliptic coordinates
    $coords = equatorial($lat, $lon);
    $dec = $coords[0];
    $ra  = $coords[1];
    $alt = asin(sin($lat2) * sin($dec) + cos($lat2) * cos($dec) * cos($lmst - $ra));
    $azm = atan2(sin($ra - $lmst), cos($lat2) * tan($dec) - sin($lat2) * cos($lmst - $ra));
    $azm += 2 * pi() * ($azm < 0);
    return [$alt, $azm];
  }

Winkel umrechnen

Mit den folgenden Funktionen können Winkel umgerechnet werden:

rad2dms() - Radiant nach Grad, Minute, Sekunde
rad2hms() - Radiant nach Stunde, Minute, Sekunde
dms2rad() - Umkehrfunktion von rad2dms()
hms2rad() - Umkehrfunktion von rad2hms()

Code kopieren
  function rad2dms($rad) {
    $sgn = 1 - (2 * ($rad < 0));
    $rad = abs($rad);
    $t = rad2deg($rad);
    $d = floor($t);
    $m = floor(($t - $d) * 60);
    $s = (($t - $d) * 60 - $m) * 60;
    return [$sgn * $d, $m, $s];
  }
  
  function rad2hms($rad) {
    $sgn = 1 - (2 * ($rad < 0));
    $rad = abs($rad);
    $t = 12 * $rad / pi();
    $h = floor($t);
    $m = floor(($t - $h) * 60);
    $s = (($t - $h) * 60 - $m) * 60;
    return [$sgn * $h, $m, $s];
  }
  
  function dms2rad($d, $m, $s) {
    $sgn = 1 - (2 * substr_count($d, "-"));
    return $sgn * deg2rad((abs($d) * 3600 + $m * 60 + $s) / 3600);
  }
  
  function hms2rad($h, $m, $s) {
    $sgn = 1 - (2 * substr_count($h, "-"));
    return $sgn * deg2rad((abs($h) * 3600 + $m * 60 + $s) / 240);
  }

Achteck in einem Quadrat

Wie lang sind die Seiten eines gleichmäßigen Achtecks, das mit vier Seiten auf einem Quadrat aufliegt?

Bekannt:
a = Seitenlänge des Quadrats

Gesucht:
x = Seitenlänge des Achtecks

a x

Formel:
Formel 11 oder in PHP:

Code kopieren
$x = $a - 2 * ($a - sqrt(2 * pow($a / 2, 2)));

Höhe über einer Seite eines beliebigen Dreiecks

Bekannt:
a = Seitenlänge des Dreiecks
β = Winkel an einem Ende der Seite a
γ = Winkel an dem anderen Ende der Seite a

Gesucht:
h = Höhe über der Seite a

a β γ h

Formel:
Formel 12 oder in PHP:

Code kopieren
$h = $a / (cos($beta) / sin($beta) + cos($gamma) / sin($gamma));

Länge der dritten Seite eines beliebigen Dreiecks

Bekannt:
a = erste Seitenlänge des Dreiecks
b = zweite Seitenlänge des Dreiecks
γ = Winkel zwischen den gegebenen Seiten

Gesucht:
c = Länge der dritten Seite

a b c γ

Formel:
Formel 13 oder in PHP:

Code kopieren
$c = sqrt(pow(sin($gamma) * $a, 2) + pow($b - sqrt(pow($a ,2) - pow(sin($gamma) * $a, 2)), 2));

Variante:

Bekannt:
a = erste Seitenlänge des Dreiecks
b = zweite Seitenlänge des Dreiecks
α = Winkel zwischen einer der gegebenen Seiten und c

Gesucht:
c = Länge der dritten Seite

a b c α

Formel:
Formel 14 oder in PHP:

Code kopieren
$c = sqrt(pow($a, 2) - pow(sin($alpha) * $b, 2)) + sqrt(pow($b, 2) - pow(sin($alpha) * $b, 2));

Länge der zweiten Seite eines beliebigen Dreiecks

Bekannt:
a = erste Seitenlänge des Dreiecks
α = Winkel an einem Ende der Seite a
β = Winkel an dem anderen Ende der Seite a

Gesucht:
c = zweite Seitenlänge des Dreiecks

a c α β

Formel:
Formel 15 oder in PHP:

Code kopieren
$c = $a * (cos($alpha) + sin($alpha) * cos(pi() - $alpha - $beta) / sin(pi() - $alpha - $beta));

Winkel in einem beliebigen Dreieck

Bekannt:
a = erste Seitenlänge des Dreiecks
b = zweite Seitenlänge des Dreiecks
c = dritte Seitenlänge des Dreiecks

Gesucht:
α = einer der Winkel

a b c α

Formel:
Formel 16 oder in PHP:

Code kopieren
$alpha = acos((pow($a, 2) - pow($b, 2) - pow($c, 2)) / (-2 * $b * $c));