<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://wiki.delphigl.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Seth</id>
		<title>DGL Wiki - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://wiki.delphigl.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Seth"/>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php/Spezial:Beitr%C3%A4ge/Seth"/>
		<updated>2026-04-29T14:00:03Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.27.4</generator>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=25416</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=25416"/>
				<updated>2011-10-23T20:34:58Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Link zum englischen Tutorial aktualisiert.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projiziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse. Somit gibt es eine Gerade, bzw. eine Trennungsachse senkrecht zur unserer Projektionsachse, welche die beiden Polygone separiert.  &lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir projizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es diese eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch die Normale der Kollision oder '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Rotation ==&lt;br /&gt;
&lt;br /&gt;
Um Polygone behandeln zu können, die rotieren, sind lediglich einige Änderungen an der Polygonklasse erforderlich.&lt;br /&gt;
Hierbei gibt es mehrere Optionen, zum einen können wir unsere Vertices in jedem Schritt drehen und speichern, allerdings kann dies auf Dauer zu Ungenauigkeiten führen. Eine zweite Möglichkeit wäre, bei jedem Zugriff auf die Vertices, einen gedrehten Vektor auszugeben. Dies erhöht zwar&lt;br /&gt;
die benötigte Rechenleistung, ist aber deutlich genauer. Das Seperation Axis Theorem kann dann mit den gedrehten Vertices weiter verfahren.&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_exe|text=Windows-Binary}}&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_src|text=Delphi-Quelltext}}&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Kreis_exe|text=Windows-Binary}}&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Kreis_src|text=Delphi-Quelltext}}&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Trennung_exe|text=Windows-Binary}}&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Trennung_src|text=Delphi-Quelltext}}&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 4 - Rotation ===&lt;br /&gt;
&lt;br /&gt;
Die Rotation des Polygons erfolgt beim Auslesen der Vertex Koordinaten mittels einer Rotationsmatrix:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  acos, asin: extended;&lt;br /&gt;
begin&lt;br /&gt;
  sincos(degtorad(fangle),asin,acos);&lt;br /&gt;
  result.x := fvertices[n].x * acos + fvertices[n].y * -asin;&lt;br /&gt;
  result.y := fvertices[n].x * asin + fvertices[n].y * acos;&lt;br /&gt;
end;   &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es den Code für die Behandlung von Rotation:'''&lt;br /&gt;
* {{ArchivLink|file=tut_SAT_Rotation_src|text=Delphi-Quelltext}}&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.metanetsoftware.com/technique/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | [[Tutorial Kollision1]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21202</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21202"/>
				<updated>2008-03-11T16:07:14Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projiziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse. Somit gibt es eine Gerade, bzw. eine Trennungsachse senkrecht zur unserer Projektionsachse, welche die beiden Polygone separiert.  &lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir projizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es diese eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch die Normale der Kollision oder '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Rotation ==&lt;br /&gt;
&lt;br /&gt;
Um Polygone behandeln zu können, die rotieren, sind lediglich einige Änderungen an der Polygonklasse erforderlich.&lt;br /&gt;
Hierbei gibt es mehrere Optionen, zum einen können wir unsere Vertices in jedem Schritt drehen und speichern, allerdings kann dies auf Dauer zu Ungenauigkeiten führen. Eine zweite Möglichkeit wäre, bei jedem Zugriff auf die Vertices, einen gedrehten Vektor auszugeben. Dies erhöht zwar&lt;br /&gt;
die benötigte Rechenleistung, ist aber deutlich genauer. Das Seperation Axis Theorem kann dann mit den gedrehten Vertices weiter verfahren.&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_exe.zip tut_SAT_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_src.zip tut_SAT_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Kreis_exe.zip tut_SAT_Kreis_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Kreis_src.zip tut_SAT_Kreis_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Trennung_exe.zip tut_SAT_Trennung_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Trennung_src.zip tut_SAT_Trennung_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 4 - Rotation ===&lt;br /&gt;
&lt;br /&gt;
Die Rotation des Polygons erfolgt beim Auslesen der Vertex Koordinaten mittels einer Rotationsmatrix:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  acos, asin: extended;&lt;br /&gt;
begin&lt;br /&gt;
  sincos(degtorad(fangle),asin,acos);&lt;br /&gt;
  result.x := fvertices[n].x * acos + fvertices[n].y * -asin;&lt;br /&gt;
  result.y := fvertices[n].x * asin + fvertices[n].y * acos;&lt;br /&gt;
end;   &lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es den Code für die Behandlung von Rotation:'''&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/Download/tut_SAT_Rotation_src.zip tut_SAT_Rotation_src.zip]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | [[Tutorial Kollision1]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21201</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21201"/>
				<updated>2008-03-11T16:05:30Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: normalisiert durch normiert ersetzt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projiziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse. Somit gibt es eine Gerade, bzw. eine Trennungsachse senkrecht zur unserer Projektionsachse, welche die beiden Polygone separiert.  &lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir projizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es diese eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Rotation ==&lt;br /&gt;
&lt;br /&gt;
Um Polygone behandeln zu können, die rotieren, sind lediglich einige Änderungen an der Polygonklasse erforderlich.&lt;br /&gt;
Hierbei gibt es mehrere Optionen, zum einen können wir unsere Vertices in jedem Schritt drehen und speichern, allerdings kann dies auf Dauer zu Ungenauigkeiten führen. Eine zweite Möglichkeit wäre, bei jedem Zugriff auf die Vertices, einen gedrehten Vektor auszugeben. Dies erhöht zwar&lt;br /&gt;
die benötigte Rechenleistung, ist aber deutlich genauer. Das Seperation Axis Theorem kann dann mit den gedrehten Vertices weiter verfahren.&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_exe.zip tut_SAT_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_src.zip tut_SAT_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Kreis_exe.zip tut_SAT_Kreis_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Kreis_src.zip tut_SAT_Kreis_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Trennung_exe.zip tut_SAT_Trennung_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Trennung_src.zip tut_SAT_Trennung_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 4 - Rotation ===&lt;br /&gt;
&lt;br /&gt;
Die Rotation des Polygons erfolgt beim Auslesen der Vertex Koordinaten mittels einer Rotationsmatrix:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  acos, asin: extended;&lt;br /&gt;
begin&lt;br /&gt;
  sincos(degtorad(fangle),asin,acos);&lt;br /&gt;
  result.x := fvertices[n].x * acos + fvertices[n].y * -asin;&lt;br /&gt;
  result.y := fvertices[n].x * asin + fvertices[n].y * acos;&lt;br /&gt;
end;   &lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es den Code für die Behandlung von Rotation:'''&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/Download/tut_SAT_Rotation_src.zip tut_SAT_Rotation_src.zip]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | [[Tutorial Kollision1]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21200</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21200"/>
				<updated>2008-03-11T16:03:36Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projiziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse. Somit gibt es eine Gerade, bzw. eine Trennungsachse senkrecht zur unserer Projektionsachse, welche die beiden Polygone separiert.  &lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir projizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es diese eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Rotation ==&lt;br /&gt;
&lt;br /&gt;
Um Polygone behandeln zu können, die rotieren, sind lediglich einige Änderungen an der Polygonklasse erforderlich.&lt;br /&gt;
Hierbei gibt es mehrere Optionen, zum einen können wir unsere Vertices in jedem Schritt drehen und speichern, allerdings kann dies auf Dauer zu Ungenauigkeiten führen. Eine zweite Möglichkeit wäre, bei jedem Zugriff auf die Vertices, einen gedrehten Vektor auszugeben. Dies erhöht zwar&lt;br /&gt;
die benötigte Rechenleistung, ist aber deutlich genauer. Das Seperation Axis Theorem kann dann mit den gedrehten Vertices weiter verfahren.&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_exe.zip tut_SAT_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_src.zip tut_SAT_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Kreis_exe.zip tut_SAT_Kreis_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Kreis_src.zip tut_SAT_Kreis_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Trennung_exe.zip tut_SAT_Trennung_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Trennung_src.zip tut_SAT_Trennung_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 4 - Rotation ===&lt;br /&gt;
&lt;br /&gt;
Die Rotation des Polygons erfolgt beim Auslesen der Vertex Koordinaten mittels einer Rotationsmatrix:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  acos, asin: extended;&lt;br /&gt;
begin&lt;br /&gt;
  sincos(degtorad(fangle),asin,acos);&lt;br /&gt;
  result.x := fvertices[n].x * acos + fvertices[n].y * -asin;&lt;br /&gt;
  result.y := fvertices[n].x * asin + fvertices[n].y * acos;&lt;br /&gt;
end;   &lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es den Code für die Behandlung von Rotation:'''&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/Download/tut_SAT_Rotation_src.zip tut_SAT_Rotation_src.zip]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | [[Tutorial Kollision1]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21199</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21199"/>
				<updated>2008-03-11T16:02:49Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Code für Rotation hinzugefügt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projiziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse. Somit gibt es eine Gerade, bzw. eine Trennungsachse senkrecht zur unserer Projektionsachse, welche die beiden Polygone separiert.  &lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir projizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es diese eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Rotation ==&lt;br /&gt;
&lt;br /&gt;
Um Polygone behandeln zu können, die rotieren, sind lediglich einige Änderungen an der Polygonklasse erforderlich.&lt;br /&gt;
Hierbei gibt es mehrere Optionen, zum einen können wir unsere Vertices in jedem Schritt drehen und speichern, allerdings kann dies auf Dauer zu Ungenauigkeiten führen. Eine zweite Möglichkeit wäre, bei jedem Zugriff auf die Vertices, einen gedrehten Vektor auszugeben. Dies erhöht zwar&lt;br /&gt;
die benötigte Rechenleistung, ist aber deutlich genauer. Das Seperation Axis Theorem kann dann mit den gedrehten Vertices weiter verfahren.&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_exe.zip tut_SAT_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_src.zip tut_SAT_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Kreis_exe.zip tut_SAT_Kreis_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Kreis_src.zip tut_SAT_Kreis_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Trennung_exe.zip tut_SAT_Trennung_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Trennung_src.zip tut_SAT_Trennung_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 4 - Rotation ===&lt;br /&gt;
&lt;br /&gt;
Die Rotation des Polygons erfolgt beim Auslesen der Vertex Positionen mittels einer Rotationsmatrix:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  acos, asin: extended;&lt;br /&gt;
begin&lt;br /&gt;
  sincos(degtorad(fangle),asin,acos);&lt;br /&gt;
  result.x := fvertices[n].x * acos + fvertices[n].y * -asin;&lt;br /&gt;
  result.y := fvertices[n].x * asin + fvertices[n].y * acos;&lt;br /&gt;
end;   &lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es den Code für die Behandlung von Rotation:'''&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/Download/tut_SAT_Rotation_src.zip tut_SAT_Rotation_src.zip]&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | [[Tutorial Kollision1]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21157</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21157"/>
				<updated>2008-03-03T13:10:58Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Ergänzung (Rotation) hinzugefügt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projiziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse. Somit gibt es eine Gerade, bzw. eine Trennungsachse senkrecht zur unserer Projektionsachse, welche die beiden Polygone separiert.  &lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir projizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es diese eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Rotation ==&lt;br /&gt;
&lt;br /&gt;
Um Polygone behandeln zu können, die rotieren, sind lediglich einige Änderungen an der Polygonklasse erforderlich.&lt;br /&gt;
Hierbei gibt es mehrere Optionen, zum einen können wir unsere Vertices in jedem Schritt drehen und speichern, allerdings kann dies auf Dauer zu Ungenauigkeiten führen. Eine zweite Möglichkeit wäre, bei jedem Zugriff auf die Vertices, einen gedrehten Vektor auszugeben. Dies erhöht zwar&lt;br /&gt;
die benötigte Rechenleistung, ist aber deutlich genauer. Das Seperation Axis Theorem kann dann mit den gedrehten Vertices weiter verfahren.&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_exe.zip tut_SAT_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_src.zip tut_SAT_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Kreis_exe.zip tut_SAT_Kreis_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Kreis_src.zip tut_SAT_Kreis_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Trennung_exe.zip tut_SAT_Trennung_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Trennung_src.zip tut_SAT_Trennung_src.zip]&lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | [[Tutorial Kollision1]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21132</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21132"/>
				<updated>2008-02-20T15:07:59Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Kleine Ergänzung und Rechtschreibung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projiziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse. Somit gibt es eine Gerade, bzw. eine Trennungsachse senkrecht zur unserer Projektionsachse, welche die beiden Polygone separiert.  &lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir projizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es diese eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_exe.zip tut_SAT_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_src.zip tut_SAT_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Kreis_exe.zip tut_SAT_Kreis_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Kreis_src.zip tut_SAT_Kreis_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Trennung_exe.zip tut_SAT_Trennung_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Trennung_src.zip tut_SAT_Trennung_src.zip]&lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | [[Tutorial Kollision1]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21035</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=21035"/>
				<updated>2007-12-22T12:10:35Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir projizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es diese eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_exe.zip tut_SAT_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_src.zip tut_SAT_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Kreis_exe.zip tut_SAT_Kreis_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Kreis_src.zip tut_SAT_Kreis_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Trennung_exe.zip tut_SAT_Trennung_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Trennung_src.zip tut_SAT_Trennung_src.zip]&lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | - }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20891</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20891"/>
				<updated>2007-09-22T09:43:52Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von Belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' (Trennungsachse).&lt;br /&gt;
Nun gibt es unendlich viele Achsen die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir multiplizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_exe.zip tut_SAT_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_src.zip tut_SAT_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Kreis_exe.zip tut_SAT_Kreis_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Kreis_src.zip tut_SAT_Kreis_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Trennung_exe.zip tut_SAT_Trennung_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Trennung_src.zip tut_SAT_Trennung_src.zip]&lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | - }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20890</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20890"/>
				<updated>2007-09-22T09:42:24Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Entgültig Geraden durch Achsen ersetzt (und ein paar Kleinigkeiten)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, daher auch der Name ''Separating Axis'' für Trennungsachse.&lt;br /&gt;
Nun gibt es unendlich viele Achse die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Achse projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Achse die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir multiplizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_exe.zip tut_SAT_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_src.zip tut_SAT_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Kreis_exe.zip tut_SAT_Kreis_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Kreis_src.zip tut_SAT_Kreis_src.zip]&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' [http://files.delphigl.com/download/tut_SAT_Trennung_exe.zip tut_SAT_Trennung_exe.zip]&lt;br /&gt;
&lt;br /&gt;
''Source:'' [http://files.delphigl.com/download/tut_SAT_Trennung_src.zip tut_SAT_Trennung_src.zip]&lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Seth|Seth]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Objekt immer um eigene Achse drehen]] | - }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20879</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20879"/>
				<updated>2007-09-19T18:56:56Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Anmerkung zum MTD hinzugefügt (skalarprodukt)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. &lt;br /&gt;
Daher auch der Name ''Separating Axis''.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, denn&lt;br /&gt;
wie der Name schon sagt, werden diese &amp;quot;Geraden&amp;quot; gemeinhin mit Trennungsachsen betitelt.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir multiplizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. Allerdings sollte man vor der Verwendung sicherstellen, dass dieser Vektor vom Polygon wegzeigt. Hierzu können wir ebenfalls das Skalarprodukt nutzen. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20878</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20878"/>
				<updated>2007-09-19T18:52:12Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: noch mehr code entfernt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. &lt;br /&gt;
Daher auch der Name ''Separating Axis''.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, denn&lt;br /&gt;
wie der Name schon sagt, werden diese &amp;quot;Geraden&amp;quot; gemeinhin mit Trennungsachsen betitelt.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir multiplizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20877</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20877"/>
				<updated>2007-09-19T18:51:00Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. &lt;br /&gt;
Daher auch der Name ''Separating Axis''.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, denn&lt;br /&gt;
wie der Name schon sagt, werden diese &amp;quot;Geraden&amp;quot; gemeinhin mit Trennungsachsen betitelt.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir multiplizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon dann ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
Gezeichnet wird er mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawCircle(C: TCircle; aColor: TColor);&lt;br /&gt;
begin&lt;br /&gt;
  with Image1.Canvas do&lt;br /&gt;
  begin&lt;br /&gt;
    Pen.Color := aColor;&lt;br /&gt;
    Ellipse(round(C.position.x - C.radius), round(C.position.y - C.radius),&lt;br /&gt;
                          round(C.position.x + C.radius), round(C.position.y + C.radius));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20876</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20876"/>
				<updated>2007-09-19T18:49:25Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right|framed|Normale der Seite des Quadrats]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. &lt;br /&gt;
Daher auch der Name ''Separating Axis''.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg|framed]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg|framed]][[Bild:SAT_Keine_Kollision.jpg|framed]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, denn&lt;br /&gt;
wie der Name schon sagt, werden diese &amp;quot;Geraden&amp;quot; gemeinhin mit Trennungsachsen betitelt.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right|framed|Projektionsachsen eines Kreises]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir multiplizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon dann ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
Gezeichnet wird er mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawCircle(C: TCircle; aColor: TColor);&lt;br /&gt;
begin&lt;br /&gt;
  with Image1.Canvas do&lt;br /&gt;
  begin&lt;br /&gt;
    Pen.Color := aColor;&lt;br /&gt;
    Ellipse(round(C.position.x - C.radius), round(C.position.y - C.radius),&lt;br /&gt;
                          round(C.position.x + C.radius), round(C.position.y + C.radius));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20875</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20875"/>
				<updated>2007-09-19T18:45:07Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. &lt;br /&gt;
Daher auch der Name ''Separating Axis''.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, denn&lt;br /&gt;
wie der Name schon sagt, werden diese &amp;quot;Geraden&amp;quot; gemeinhin mit Trennungsachsen betitelt.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir multiplizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon dann ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
Gezeichnet wird er mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawCircle(C: TCircle; aColor: TColor);&lt;br /&gt;
begin&lt;br /&gt;
  with Image1.Canvas do&lt;br /&gt;
  begin&lt;br /&gt;
    Pen.Color := aColor;&lt;br /&gt;
    Ellipse(round(C.position.x - C.radius), round(C.position.y - C.radius),&lt;br /&gt;
                          round(C.position.x + C.radius), round(C.position.y + C.radius));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20874</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20874"/>
				<updated>2007-09-19T18:44:01Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Viel Code entfernt (liegt den Beispielen bei), kleine Fehler entfernt, Gerade wird nun stehts mit Achse betitelt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|thumb|right]]&lt;br /&gt;
Das Separating Axis Theorem (''kurz: SAT'') besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt, bzw. die beiden trennt. &lt;br /&gt;
Daher auch der Name ''Separating Axis''.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert, so erhält man einen Vektor der senkrecht zu dem original Vektor ist. Da es zwei Möglichkeiten gibt, spricht man von der linken oder rechten Normale (aus der Sicht des Vektors).&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält,.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch erhalten wir ein eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden eindimensionalen Strecken schneiden. &lt;br /&gt;
Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden. Dies ist auch  der Grund, warum dieses Verfahren recht schnell ist, da im besten Fall schon im ersten &lt;br /&gt;
Durchlauf abgebrochen werden kann.&lt;br /&gt;
&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projiziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Der Begriff &amp;quot;Gerade&amp;quot; ist hier allerdings nicht ganz korrekt. Eine Gerade hat eine räumliche Lage, diese ist für unser Vorhaben jedoch nicht von belangen, deshalb werde ich im Folgenden das Wort ''Achse'' benutzen, denn&lt;br /&gt;
wie der Name schon sagt, werden diese &amp;quot;Geraden&amp;quot; gemeinhin mit Trennungsachsen betitelt.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Achse.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer eindimensionalen Achse darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projiziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann mit einer einfachen Abfrage auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Achsen aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Achsen projizieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist, wenn wir einen Kreis haben, der mit einem Polygon kollidiert?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Achsen, die den Kreismittelpunkt und die Ecken unseres Polygons verbinden würden.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg|thumb|right]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Achsen auf die wir projizieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projizieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projiziert, indem der Vektor, auf den wir multiplizieren, mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
Hierzu ist zu sagen, dass dies noch dahingehend optimieren kann, dass man feststellt, in welcher Voronoi-Region des Polygons sich der Kreis befindet. Wenn man diese Region hat, reicht es eine Achse zu prüfen.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projiziert und geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt (für '''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den eindimensionalen Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygonein in Frage kommen. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. &lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon dann ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit Position und Padius bekommt er seine Werte zugewiesen.&lt;br /&gt;
Gezeichnet wird er mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawCircle(C: TCircle; aColor: TColor);&lt;br /&gt;
begin&lt;br /&gt;
  with Image1.Canvas do&lt;br /&gt;
  begin&lt;br /&gt;
    Pen.Color := aColor;&lt;br /&gt;
    Ellipse(round(C.position.x - C.radius), round(C.position.y - C.radius),&lt;br /&gt;
                          round(C.position.x + C.radius), round(C.position.y + C.radius));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die Hälfte des Vektors verschieben, dies hängt von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Quellen ==&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng) [http://www.harveycartel.org/metanet/tutorials/tutorialA.html]&lt;br /&gt;
&lt;br /&gt;
SAT-Tutorial(Eng / VB) [http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection]&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20299</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20299"/>
				<updated>2007-04-09T11:28:18Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
=== Der Code ===&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei extendeds in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: extended;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Polygon Klasse&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    procedure SetVertex(n: integer; Value: TVector2f);// Setzt die Objektkoordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);                // Fügt ein Vertex hinzu&lt;br /&gt;
    procedure AddVertexAbs(v: TVector2f);             // Fügt ein Vertex mit Weltkoordinaten hinzu&lt;br /&gt;
    procedure RemoveVertex(n: integer);               // Entfernt ein Vertex&lt;br /&gt;
    property position: TVector2f read fposition write fposition;             // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex write SetVertex; // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;          // Vertex Weltkoordinaten&lt;br /&gt;
    property Count: integer read GetCount;                                   // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertexAbs(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v2f_sub(v, position);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.SetVertex(n: integer; Value: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  fvertices[n] := Value;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist,&lt;br /&gt;
wenn wir einen Kreis haben, der mit einem Polygon kollidiert ?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Geraden, die vom Kreismittelpunkt zu den Ecken unseres Polygons führen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Geraden, bzw. die Achsen auf die wir projezieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projezieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projeziert, indem der Vektor auf den wir multiplizieren mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
=== Der Code === &lt;br /&gt;
&lt;br /&gt;
Der Code bietet noch viel Spielraum für Optimierungen, so ist es zum Beispiel nicht nötig, für jedes Vertex eine Projektionsachse zu berechnen, sondern es reicht aus, das Vertex, bzw die Kante zu nutzen, die sich auch in Reichweite des Kreises befindet, da diese zwangsläufig geschnitten werden müssen.&lt;br /&gt;
Natürlich benötigen wir zunächst eine Kreis-Klasse:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TCircle = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;&lt;br /&gt;
    fradius: extended;&lt;br /&gt;
  public&lt;br /&gt;
    property position: TVector2f read fposition write fposition;&lt;br /&gt;
    property radius: extended read fradius write fradius;&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die Kollision zweier Kreise kann dann gleich mit implementiert werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CircleCircleIntersect(A, B: TCircle): boolean;&lt;br /&gt;
begin&lt;br /&gt;
  result := (sqr(A.position.x - B.position.x) + sqr(A.position.y - B.position.y)) &amp;lt; sqr(A.radius + B.radius);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Das sollte denke ich, soweit klar sein.&lt;br /&gt;
Nun folgt der Code zur Berechnung der Kreis &amp;lt;&amp;gt; Polygon Kollision. Es gibt nur eine äußere Schleife, da die Berechnungen für den Kreis gleich mit in dieser vorgenommen werden können. Ein bisschen Code ließe sich sicherlich auch noch auslagern, ich habe den Code so gelassen, weil ich denke, dass es der Übersicht sicherlich förderlich ist.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CirclePolyIntersect(P: TPolygon; C: TCircle): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, pmin, pmax, cmin, cmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(P.position, C.position);&lt;br /&gt;
// P - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (P.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(P.vertices[l], P.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
//C - Alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
    proj := v2f_normalize(v2f_sub(C.position, P.vertices_abs[i]));&lt;br /&gt;
    // s.o.&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein&lt;br /&gt;
Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projeziert und&lt;br /&gt;
geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Tortenstücks und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
''Hier folgt demnächst eine Anleitung für die Kollision von beliebigen Tortenstücken mit einem Polygon.''&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der Unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt ('''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den 1D Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygone geeignet sind. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. &lt;br /&gt;
&lt;br /&gt;
=== Der Code ===&lt;br /&gt;
&lt;br /&gt;
Der bisherige Code sollte soweit verstanden sein, deshalb habe ich mir die Freiheit genommen ein wenig Code auszulagern:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CreateAxis(P: TPolygon): TV2fArray;&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
  tmp: TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (P.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(P.vertices[l], P.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    setlength(result, length(result) + 1);&lt;br /&gt;
    result[high(result)] := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure ProjectOntoAxis(P: TPolygon; proj: TVector2f; var pmin, pmax: extended);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
  dp: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Projeziert den ersten Wert&lt;br /&gt;
  pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
  pmax := pmin;&lt;br /&gt;
  // Findet den kleinsten und größten projezierten Wert für die Gerade für P&lt;br /&gt;
  for i := 1 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    // projezieren&lt;br /&gt;
    dp := v2f_dotproduct(P.vertices[i], proj);&lt;br /&gt;
    if dp &amp;lt; pmin then&lt;br /&gt;
      pmin := dp;&lt;br /&gt;
    if dp &amp;gt; pmax then&lt;br /&gt;
      pmax := dp;&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function CollisionCheck(A, B: TPolygon; var axis: TVector2f; voffset: TVector2f): boolean;&lt;br /&gt;
var&lt;br /&gt;
  foffset,&lt;br /&gt;
  amin, amax,&lt;br /&gt;
  bmin, bmax,&lt;br /&gt;
  d1, d2, depth: extended;&lt;br /&gt;
begin&lt;br /&gt;
  ProjectOntoAxis(A, axis, amin, amax);&lt;br /&gt;
  ProjectOntoAxis(B, axis, bmin, bmax);&lt;br /&gt;
  foffset := v2f_dotproduct(voffset, axis);&lt;br /&gt;
  amin := amin + foffset;&lt;br /&gt;
  amax := amax + foffset;&lt;br /&gt;
  d1 := amin - bmax;&lt;br /&gt;
  d2 := bmin - amax;&lt;br /&gt;
  // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
  if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
  begin&lt;br /&gt;
    result := false;&lt;br /&gt;
    exit;&lt;br /&gt;
  end;&lt;br /&gt;
  // Ansonsten den Verschiebungsvektor bestimmen&lt;br /&gt;
  depth := max(d1, d2);&lt;br /&gt;
  axis := v2f_scale(axis, abs(depth));&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die ersten beiden Funktionen sollten klar sein, bei der dritten gibt es eine kleine Neuerung.&lt;br /&gt;
Wenn eine Kollision stattfindet, bricht diese Funktion nicht ab und die Projektionsachse wird mit&lt;br /&gt;
der Differenz multipliziert, deren Betrag am kleinsten ist. Da es sich um negative Werte handelt kann man statt:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  depth := min(abs(d1), abs(d2));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
ganz einfach:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  depth := max(d1, d2);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
schreiben. Die neue PolyPolyIntersect Funktion sieht so aus:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon; var MTD: TVector2f): boolean;&lt;br /&gt;
var&lt;br /&gt;
  axis: TV2fArray;&lt;br /&gt;
  voffset: TVector2f;&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  MTD := to_v2f(0, 0);&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
  // Alle Achsen für A&lt;br /&gt;
  axis := CreateAxis(A);&lt;br /&gt;
  // Alle Achsen für B&lt;br /&gt;
  axis := CreateAxis(B);&lt;br /&gt;
  // Projezieren der Polygone&lt;br /&gt;
  for i := 0 to high(axis) do&lt;br /&gt;
    if CollisionCheck(A, B, axis[i], voffset) = false then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  // MTD bestimmen&lt;br /&gt;
  MTD := axis[0];&lt;br /&gt;
  for i := 1 to high(axis) do&lt;br /&gt;
    if v2f_length(axis[i]) &amp;lt; v2f_length(MTD) then&lt;br /&gt;
      MTD := axis[i];&lt;br /&gt;
  if v2f_dotproduct(voffset, MTD) &amp;lt; 0 then&lt;br /&gt;
    MTD := v2f_scale(MTD, -1);&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden zunächst alle Achsen ermittelt und dann projeziert, dabei werden die&lt;br /&gt;
Achsen mit sämtlichen potentiellen MTDs überschrieben und daraus der kleinste berechnet.&lt;br /&gt;
Diesen Vektor übergeben wir einfach mittels Var-Parameter und können dann unsere Polygone&lt;br /&gt;
trennen, indem wir den MTD-Vektor von ihrer derzeitigen Position abziehen.&lt;br /&gt;
&lt;br /&gt;
Dieser Code hier sorgt dafür, dass das Polygon auch wirklich von dem anderen getrennt und nicht&lt;br /&gt;
noch weiter hineingeschoben wird:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  if v2f_dotproduct(voffset, MTD) &amp;lt; 0 then&lt;br /&gt;
    MTD := v2f_scale(MTD, -1);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
Die Koordinaten der Vertices werden absolut zur Position und ''entgegen'' des Uhrzeigersinns angegeben.&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon dann ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit position und radius bekommt er seine Werte zugewiesen.&lt;br /&gt;
Gezeichnet wird er mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawCircle(C: TCircle; aColor: TColor);&lt;br /&gt;
begin&lt;br /&gt;
  with Image1.Canvas do&lt;br /&gt;
  begin&lt;br /&gt;
    Pen.Color := aColor;&lt;br /&gt;
    Ellipse(round(C.position.x - C.radius), round(C.position.y - C.radius),&lt;br /&gt;
                          round(C.position.x + C.radius), round(C.position.y + C.radius));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die hälfte des Vektors verschieben, dies hängt&lt;br /&gt;
von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB):''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20298</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20298"/>
				<updated>2007-04-08T10:06:27Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Anm. zu Punkten + Hinz. &amp;quot;Demnächst Tortenstücke&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
=== Der Code ===&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei extendeds in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: extended;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Polygon Klasse&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    procedure SetVertex(n: integer; Value: TVector2f);// Setzt die Objektkoordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);                // Fügt ein Vertex hinzu&lt;br /&gt;
    procedure AddVertexAbs(v: TVector2f);             // Fügt ein Vertex mit Weltkoordinaten hinzu&lt;br /&gt;
    procedure RemoveVertex(n: integer);               // Entfernt ein Vertex&lt;br /&gt;
    property position: TVector2f read fposition write fposition;             // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex write SetVertex; // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;          // Vertex Weltkoordinaten&lt;br /&gt;
    property Count: integer read GetCount;                                   // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertexAbs(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v2f_sub(v, position);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.SetVertex(n: integer; Value: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  fvertices[n] := Value;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist,&lt;br /&gt;
wenn wir einen Kreis haben, der mit einem Polygon kollidiert ?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Geraden, die vom Kreismittelpunkt zu den Ecken unseres Polygons führen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Geraden, bzw. die Achsen auf die wir projezieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projezieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projeziert, indem der Vektor auf den wir multiplizieren mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
=== Der Code === &lt;br /&gt;
&lt;br /&gt;
Der Code bietet noch viel Spielraum für Optimierungen, so ist es zum Beispiel nicht nötig, für jedes Vertex eine Projektionsachse zu berechnen, sondern es reicht aus, das Vertex, bzw die Kante zu nutzen, die sich auch in Reichweite des Kreises befindet, da diese zwangsläufig geschnitten werden müssen.&lt;br /&gt;
Natürlich benötigen wir zunächst eine Kreis-Klasse:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TCircle = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;&lt;br /&gt;
    fradius: extended;&lt;br /&gt;
  public&lt;br /&gt;
    property position: TVector2f read fposition write fposition;&lt;br /&gt;
    property radius: extended read fradius write fradius;&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die Kollision zweier Kreise kann dann gleich mit implementiert werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CircleCircleIntersect(A, B: TCircle): boolean;&lt;br /&gt;
begin&lt;br /&gt;
  result := (sqr(A.position.x - B.position.x) + sqr(A.position.y - B.position.y)) &amp;lt; sqr(A.radius + B.radius);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Das sollte denke ich, soweit klar sein.&lt;br /&gt;
Nun folgt der Code zur Berechnung der Kreis &amp;lt;&amp;gt; Polygon Kollision. Es gibt nur eine äußere Schleife, da die Berechnungen für den Kreis gleich mit in dieser vorgenommen werden können. Ein bisschen Code ließe sich sicherlich auch noch auslagern, ich habe den Code so gelassen, weil ich denke, dass es der Übersicht sicherlich förderlich ist.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CirclePolyIntersect(P: TPolygon; C: TCircle): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, pmin, pmax, cmin, cmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(P.position, C.position);&lt;br /&gt;
// P - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (P.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(P.vertices[l], P.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
//C - Alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
    proj := v2f_normalize(v2f_sub(C.position, P.vertices_abs[i]));&lt;br /&gt;
    // s.o.&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Punktes und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Ganz am Rande möchte ich noch erwähnen, dass es ebenso möglich ist, zu prüfen, ob sich ein&lt;br /&gt;
Punkt in einem Polygon befindet. Hierzu wird einfach der Punkt auf die Achsen projeziert und&lt;br /&gt;
geprüft ob er größer als das Minimum und kleiner als das Maximum des Polygons auf dieser Achse ist.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Tortenstücks und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
''Hier folgt demnächst eine Anleitung für die Kollision von beliebigen Tortenstücken mit einem Polygon.''&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der Unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt ('''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den 1D Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygone geeignet sind. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. &lt;br /&gt;
&lt;br /&gt;
=== Der Code ===&lt;br /&gt;
&lt;br /&gt;
Der bisherige Code sollte soweit verstanden sein, deshalb habe ich mir die Freiheit genommen ein wenig Code auszulagern:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CreateAxis(P: TPolygon): TV2fArray;&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
  tmp: TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (P.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(P.vertices[l], P.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    setlength(result, length(result) + 1);&lt;br /&gt;
    result[high(result)] := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure ProjectOntoAxis(P: TPolygon; proj: TVector2f; var pmin, pmax: extended);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
  dp: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Projeziert den ersten Wert&lt;br /&gt;
  pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
  pmax := pmin;&lt;br /&gt;
  // Findet den kleinsten und größten projezierten Wert für die Gerade für P&lt;br /&gt;
  for i := 1 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    // projezieren&lt;br /&gt;
    dp := v2f_dotproduct(P.vertices[i], proj);&lt;br /&gt;
    if dp &amp;lt; pmin then&lt;br /&gt;
      pmin := dp;&lt;br /&gt;
    if dp &amp;gt; pmax then&lt;br /&gt;
      pmax := dp;&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function CollisionCheck(A, B: TPolygon; var axis: TVector2f; voffset: TVector2f): boolean;&lt;br /&gt;
var&lt;br /&gt;
  foffset,&lt;br /&gt;
  amin, amax,&lt;br /&gt;
  bmin, bmax,&lt;br /&gt;
  d1, d2, depth: extended;&lt;br /&gt;
begin&lt;br /&gt;
  ProjectOntoAxis(A, axis, amin, amax);&lt;br /&gt;
  ProjectOntoAxis(B, axis, bmin, bmax);&lt;br /&gt;
  foffset := v2f_dotproduct(voffset, axis);&lt;br /&gt;
  amin := amin + foffset;&lt;br /&gt;
  amax := amax + foffset;&lt;br /&gt;
  d1 := amin - bmax;&lt;br /&gt;
  d2 := bmin - amax;&lt;br /&gt;
  // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
  if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
  begin&lt;br /&gt;
    result := false;&lt;br /&gt;
    exit;&lt;br /&gt;
  end;&lt;br /&gt;
  // Ansonsten den Verschiebungsvektor bestimmen&lt;br /&gt;
  depth := max(d1, d2);&lt;br /&gt;
  axis := v2f_scale(axis, abs(depth));&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die ersten beiden Funktionen sollten klar sein, bei der dritten gibt es eine kleine Neuerung.&lt;br /&gt;
Wenn eine Kollision stattfindet, bricht diese Funktion nicht ab und die Projektionsachse wird mit&lt;br /&gt;
der Differenz multipliziert, deren Betrag am kleinsten ist. Da es sich um negative Werte handelt kann man statt:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  depth := min(abs(d1), abs(d2));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
ganz einfach:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  depth := max(d1, d2);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
schreiben. Die neue PolyPolyIntersect Funktion sieht so aus:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon; var MTD: TVector2f): boolean;&lt;br /&gt;
var&lt;br /&gt;
  axis: TV2fArray;&lt;br /&gt;
  voffset: TVector2f;&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  MTD := to_v2f(0, 0);&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
  // Alle Achsen für A&lt;br /&gt;
  axis := CreateAxis(A);&lt;br /&gt;
  // Alle Achsen für B&lt;br /&gt;
  axis := CreateAxis(B);&lt;br /&gt;
  // Projezieren der Polygone&lt;br /&gt;
  for i := 0 to high(axis) do&lt;br /&gt;
    if CollisionCheck(A, B, axis[i], voffset) = false then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  // MTD bestimmen&lt;br /&gt;
  MTD := axis[0];&lt;br /&gt;
  for i := 1 to high(axis) do&lt;br /&gt;
    if v2f_length(axis[i]) &amp;lt; v2f_length(MTD) then&lt;br /&gt;
      MTD := axis[i];&lt;br /&gt;
  if v2f_dotproduct(voffset, MTD) &amp;lt; 0 then&lt;br /&gt;
    MTD := v2f_scale(MTD, -1);&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden zunächst alle Achsen ermittelt und dann projeziert, dabei werden die&lt;br /&gt;
Achsen mit sämtlichen potentiellen MTDs überschrieben und daraus der kleinste berechnet.&lt;br /&gt;
Diesen Vektor übergeben wir einfach mittels Var-Parameter und können dann unsere Polygone&lt;br /&gt;
trennen, indem wir den MTD-Vektor von ihrer derzeitigen Position abziehen.&lt;br /&gt;
&lt;br /&gt;
Dieser Code hier sorgt dafür, dass das Polygon auch wirklich von dem anderen getrennt und nicht&lt;br /&gt;
noch weiter hineingeschoben wird:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  if v2f_dotproduct(voffset, MTD) &amp;lt; 0 then&lt;br /&gt;
    MTD := v2f_scale(MTD, -1);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit position und radius bekommt er seine Werte zugewiesen.&lt;br /&gt;
Gezeichnet wird er mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawCircle(C: TCircle; aColor: TColor);&lt;br /&gt;
begin&lt;br /&gt;
  with Image1.Canvas do&lt;br /&gt;
  begin&lt;br /&gt;
    Pen.Color := aColor;&lt;br /&gt;
    Ellipse(round(C.position.x - C.radius), round(C.position.y - C.radius),&lt;br /&gt;
                          round(C.position.x + C.radius), round(C.position.y + C.radius));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die hälfte des Vektors verschieben, dies hängt&lt;br /&gt;
von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB):''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20297</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20297"/>
				<updated>2007-04-05T11:56:24Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
=== Der Code ===&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei extendeds in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: extended;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Polygon Klasse&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    procedure SetVertex(n: integer; Value: TVector2f);// Setzt die Objektkoordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);                // Fügt ein Vertex hinzu&lt;br /&gt;
    procedure AddVertexAbs(v: TVector2f);             // Fügt ein Vertex mit Weltkoordinaten hinzu&lt;br /&gt;
    procedure RemoveVertex(n: integer);               // Entfernt ein Vertex&lt;br /&gt;
    property position: TVector2f read fposition write fposition;             // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex write SetVertex; // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;          // Vertex Weltkoordinaten&lt;br /&gt;
    property Count: integer read GetCount;                                   // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertexAbs(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v2f_sub(v, position);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.SetVertex(n: integer; Value: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  fvertices[n] := Value;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist,&lt;br /&gt;
wenn wir einen Kreis haben, der mit einem Polygon kollidiert ?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Geraden, die vom Kreismittelpunkt zu den Ecken unseres Polygons führen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Geraden, bzw. die Achsen auf die wir projezieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projezieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projeziert, indem der Vektor auf den wir multiplizieren mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
=== Der Code === &lt;br /&gt;
&lt;br /&gt;
Der Code bietet noch viel Spielraum für Optimierungen, so ist es zum Beispiel nicht nötig, für jedes Vertex eine Projektionsachse zu berechnen, sondern es reicht aus, das Vertex, bzw die Kante zu nutzen, die sich auch in Reichweite des Kreises befindet, da diese zwangsläufig geschnitten werden müssen.&lt;br /&gt;
Natürlich benötigen wir zunächst eine Kreis-Klasse:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TCircle = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;&lt;br /&gt;
    fradius: extended;&lt;br /&gt;
  public&lt;br /&gt;
    property position: TVector2f read fposition write fposition;&lt;br /&gt;
    property radius: extended read fradius write fradius;&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die Kollision zweier Kreise kann dann gleich mit implementiert werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CircleCircleIntersect(A, B: TCircle): boolean;&lt;br /&gt;
begin&lt;br /&gt;
  result := (sqr(A.position.x - B.position.x) + sqr(A.position.y - B.position.y)) &amp;lt; sqr(A.radius + B.radius);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Das sollte denke ich, soweit klar sein.&lt;br /&gt;
Nun folgt der Code zur Berechnung der Kreis &amp;lt;&amp;gt; Polygon Kollision. Es gibt nur eine äußere Schleife, da die Berechnungen für den Kreis gleich mit in dieser vorgenommen werden können. Ein bisschen Code ließe sich sicherlich auch noch auslagern, ich habe den Code so gelassen, weil ich denke, dass es der Übersicht sicherlich förderlich ist.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CirclePolyIntersect(P: TPolygon; C: TCircle): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, pmin, pmax, cmin, cmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(P.position, C.position);&lt;br /&gt;
// P - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (P.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(P.vertices[l], P.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
//C - Alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
    proj := v2f_normalize(v2f_sub(C.position, P.vertices_abs[i]));&lt;br /&gt;
    // s.o.&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der Unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt ('''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den 1D Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygone geeignet sind. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. &lt;br /&gt;
&lt;br /&gt;
=== Der Code ===&lt;br /&gt;
&lt;br /&gt;
Der bisherige Code sollte soweit verstanden sein, deshalb habe ich mir die Freiheit genommen ein wenig Code auszulagern:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CreateAxis(P: TPolygon): TV2fArray;&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
  tmp: TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (P.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(P.vertices[l], P.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    setlength(result, length(result) + 1);&lt;br /&gt;
    result[high(result)] := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure ProjectOntoAxis(P: TPolygon; proj: TVector2f; var pmin, pmax: extended);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
  dp: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Projeziert den ersten Wert&lt;br /&gt;
  pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
  pmax := pmin;&lt;br /&gt;
  // Findet den kleinsten und größten projezierten Wert für die Gerade für P&lt;br /&gt;
  for i := 1 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    // projezieren&lt;br /&gt;
    dp := v2f_dotproduct(P.vertices[i], proj);&lt;br /&gt;
    if dp &amp;lt; pmin then&lt;br /&gt;
      pmin := dp;&lt;br /&gt;
    if dp &amp;gt; pmax then&lt;br /&gt;
      pmax := dp;&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function CollisionCheck(A, B: TPolygon; var axis: TVector2f; voffset: TVector2f): boolean;&lt;br /&gt;
var&lt;br /&gt;
  foffset,&lt;br /&gt;
  amin, amax,&lt;br /&gt;
  bmin, bmax,&lt;br /&gt;
  d1, d2, depth: extended;&lt;br /&gt;
begin&lt;br /&gt;
  ProjectOntoAxis(A, axis, amin, amax);&lt;br /&gt;
  ProjectOntoAxis(B, axis, bmin, bmax);&lt;br /&gt;
  foffset := v2f_dotproduct(voffset, axis);&lt;br /&gt;
  amin := amin + foffset;&lt;br /&gt;
  amax := amax + foffset;&lt;br /&gt;
  d1 := amin - bmax;&lt;br /&gt;
  d2 := bmin - amax;&lt;br /&gt;
  // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
  if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
  begin&lt;br /&gt;
    result := false;&lt;br /&gt;
    exit;&lt;br /&gt;
  end;&lt;br /&gt;
  // Ansonsten den Verschiebungsvektor bestimmen&lt;br /&gt;
  depth := max(d1, d2);&lt;br /&gt;
  axis := v2f_scale(axis, abs(depth));&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die ersten beiden Funktionen sollten klar sein, bei der dritten gibt es eine kleine Neuerung.&lt;br /&gt;
Wenn eine Kollision stattfindet, bricht diese Funktion nicht ab und die Projektionsachse wird mit&lt;br /&gt;
der Differenz multipliziert, deren Betrag am kleinsten ist. Da es sich um negative Werte handelt kann man statt:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  depth := min(abs(d1), abs(d2));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
ganz einfach:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  depth := max(d1, d2);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
schreiben. Die neue PolyPolyIntersect Funktion sieht so aus:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon; var MTD: TVector2f): boolean;&lt;br /&gt;
var&lt;br /&gt;
  axis: TV2fArray;&lt;br /&gt;
  voffset: TVector2f;&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  MTD := to_v2f(0, 0);&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
  // Alle Achsen für A&lt;br /&gt;
  axis := CreateAxis(A);&lt;br /&gt;
  // Alle Achsen für B&lt;br /&gt;
  axis := CreateAxis(B);&lt;br /&gt;
  // Projezieren der Polygone&lt;br /&gt;
  for i := 0 to high(axis) do&lt;br /&gt;
    if CollisionCheck(A, B, axis[i], voffset) = false then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  // MTD bestimmen&lt;br /&gt;
  MTD := axis[0];&lt;br /&gt;
  for i := 1 to high(axis) do&lt;br /&gt;
    if v2f_length(axis[i]) &amp;lt; v2f_length(MTD) then&lt;br /&gt;
      MTD := axis[i];&lt;br /&gt;
  if v2f_dotproduct(voffset, MTD) &amp;lt; 0 then&lt;br /&gt;
    MTD := v2f_scale(MTD, -1);&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden zunächst alle Achsen ermittelt und dann projeziert, dabei werden die&lt;br /&gt;
Achsen mit sämtlichen potentiellen MTDs überschrieben und daraus der kleinste berechnet.&lt;br /&gt;
Diesen Vektor übergeben wir einfach mittels Var-Parameter und können dann unsere Polygone&lt;br /&gt;
trennen, indem wir den MTD-Vektor von ihrer derzeitigen Position abziehen.&lt;br /&gt;
&lt;br /&gt;
Dieser Code hier sorgt dafür, dass das Polygon auch wirklich von dem anderen getrennt und nicht&lt;br /&gt;
noch weiter hineingeschoben wird:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  if v2f_dotproduct(voffset, MTD) &amp;lt; 0 then&lt;br /&gt;
    MTD := v2f_scale(MTD, -1);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit position und radius bekommt er seine Werte zugewiesen.&lt;br /&gt;
Gezeichnet wird er mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawCircle(C: TCircle; aColor: TColor);&lt;br /&gt;
begin&lt;br /&gt;
  with Image1.Canvas do&lt;br /&gt;
  begin&lt;br /&gt;
    Pen.Color := aColor;&lt;br /&gt;
    Ellipse(round(C.position.x - C.radius), round(C.position.y - C.radius),&lt;br /&gt;
                          round(C.position.x + C.radius), round(C.position.y + C.radius));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die hälfte des Vektors verschieben, dies hängt&lt;br /&gt;
von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB):''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20296</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20296"/>
				<updated>2007-04-05T11:51:47Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
=== Der Code ===&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei extendeds in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: extended;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Polygon Klasse&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    procedure SetVertex(n: integer; Value: TVector2f);// Setzt die Objektkoordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);                // Fügt ein Vertex hinzu&lt;br /&gt;
    procedure AddVertexAbs(v: TVector2f);             // Fügt ein Vertex mit Weltkoordinaten hinzu&lt;br /&gt;
    procedure RemoveVertex(n: integer);               // Entfernt ein Vertex&lt;br /&gt;
    property position: TVector2f read fposition write fposition;             // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex write SetVertex; // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;          // Vertex Weltkoordinaten&lt;br /&gt;
    property Count: integer read GetCount;                                   // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertexAbs(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v2f_sub(v, position);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.SetVertex(n: integer; Value: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  fvertices[n] := Value;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist,&lt;br /&gt;
wenn wir einen Kreis haben, der mit einem Polygon kollidiert ?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Geraden, die vom Kreismittelpunkt zu den Ecken unseres Polygons führen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Geraden, bzw. die Achsen auf die wir projezieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projezieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projeziert, indem der Vektor auf den wir multiplizieren mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
=== Der Code === &lt;br /&gt;
&lt;br /&gt;
Der Code bietet noch viel Spielraum für Optimierungen, so ist es zum Beispiel nicht nötig, für jedes Vertex eine Projektionsachse zu berechnen, sondern es reicht aus, das Vertex, bzw die Kante zu nutzen, die sich auch in Reichweite des Kreises befindet, da diese zwangsläufig geschnitten werden müssen.&lt;br /&gt;
Natürlich benötigen wir zunächst eine Kreis-Klasse:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TCircle = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;&lt;br /&gt;
    fradius: extended;&lt;br /&gt;
  public&lt;br /&gt;
    property position: TVector2f read fposition write fposition;&lt;br /&gt;
    property radius: extended read fradius write fradius;&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die Kollision zweier Kreise kann dann gleich mit implementiert werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CircleCircleIntersect(A, B: TCircle): boolean;&lt;br /&gt;
begin&lt;br /&gt;
  result := (sqr(A.position.x - B.position.x) + sqr(A.position.y - B.position.y)) &amp;lt; sqr(A.radius + B.radius);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Das sollte denke ich, soweit klar sein.&lt;br /&gt;
Nun folgt der Code zur Berechnung der Kreis &amp;lt;&amp;gt; Polygon Kollision. Es gibt nur eine äußere Schleife, da die Berechnungen für den Kreis gleich mit in dieser vorgenommen werden können. Ein bisschen Code ließe sich sicherlich auch noch auslagern, ich habe den Code so gelassen, weil ich denke, dass es der Übersicht sicherlich förderlich ist.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CirclePolyIntersect(P: TPolygon; C: TCircle): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, pmin, pmax, cmin, cmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(P.position, C.position);&lt;br /&gt;
// P - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (P.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(P.vertices[l], P.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
//C - Alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
    proj := v2f_normalize(v2f_sub(C.position, P.vertices_abs[i]));&lt;br /&gt;
    // s.o.&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Polygone trennen ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Damit unsere Kollisionserkennung praxistauglich wird, müssen die Polygone, wenn sie kollidieren auch wieder getrennt werden können. Hierzu benötigen wir einen Vektor, der Unsere beiden Polygone wieder auseinander &amp;quot;schiebt&amp;quot;. Selbstverständlich könnte man einen beliebigen Vektor nehmen, aber das Ergebnis wäre eher realtitätsfern, deshalb brauchen wir den Vektor, der den kürzesten Weg beschreibt, um die beiden Polygone zu trennen. Dieser Vektor wird auch '''MTD'''-Vektor genannt ('''M'''inimum '''T'''ranslation '''D'''istance). Hier kommt ein weiterer Vorteil des Separating Axis Theorems zum tragen, denn den Vektor den wir suchen, haben wir schon so gut wie berechnet. &lt;br /&gt;
Wir multiplizieren alle unsere Projektionsachsen mit den Differenzen, die wir bei den 1D Kollisionen herausbekommen haben, somit erhalten wir Vektoren, die für das Außeinander-Schieben unserer Polygone geeignet sind. Nun müssen wir nur noch den kürzesten davon finden, dies ist unser MTD. &lt;br /&gt;
&lt;br /&gt;
=== Der Code ===&lt;br /&gt;
&lt;br /&gt;
Der bisherige Code sollte soweit verstanden sein, deshalb habe ich mir die Freiheit genommen ein wenig Code auszulagern:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CreateAxis(P: TPolygon): TV2fArray;&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
  tmp: TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (P.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(P.vertices[l], P.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    setlength(result, length(result) + 1);&lt;br /&gt;
    result[high(result)] := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure ProjectOntoAxis(P: TPolygon; proj: TVector2f; var pmin, pmax: extended);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
  dp: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Projeziert den ersten Wert&lt;br /&gt;
  pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
  pmax := pmin;&lt;br /&gt;
  // Findet den kleinsten und größten projezierten Wert für die Gerade für P&lt;br /&gt;
  for i := 1 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    // projezieren&lt;br /&gt;
    dp := v2f_dotproduct(P.vertices[i], proj);&lt;br /&gt;
    if dp &amp;lt; pmin then&lt;br /&gt;
      pmin := dp;&lt;br /&gt;
    if dp &amp;gt; pmax then&lt;br /&gt;
      pmax := dp;&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function CollisionCheck(A, B: TPolygon; var axis: TVector2f; voffset: TVector2f): boolean;&lt;br /&gt;
var&lt;br /&gt;
  foffset,&lt;br /&gt;
  amin, amax,&lt;br /&gt;
  bmin, bmax,&lt;br /&gt;
  d1, d2, depth: extended;&lt;br /&gt;
begin&lt;br /&gt;
  result := true;&lt;br /&gt;
  ProjectOntoAxis(A, axis, amin, amax);&lt;br /&gt;
  ProjectOntoAxis(B, axis, bmin, bmax);&lt;br /&gt;
  foffset := v2f_dotproduct(voffset, axis);&lt;br /&gt;
  amin := amin + foffset;&lt;br /&gt;
  amax := amax + foffset;&lt;br /&gt;
  d1 := amin - bmax;&lt;br /&gt;
  d2 := bmin - amax;&lt;br /&gt;
  // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
  if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
  begin&lt;br /&gt;
    result := false;&lt;br /&gt;
    exit;&lt;br /&gt;
  end;&lt;br /&gt;
  // Ansonsten den Verschiebungsvektor bestimmen&lt;br /&gt;
  depth := max(d1, d2);&lt;br /&gt;
  axis := v2f_scale(axis, abs(depth));&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die ersten beiden Funktionen sollten klar sein, bei der dritten gibt es eine kleine Neuerung.&lt;br /&gt;
Wenn eine Kollision stattfindet, bricht diese Funktion nicht ab und die Projektionsachse wird mit&lt;br /&gt;
der Differenz multipliziert, deren Betrag am kleinsten ist. Da es sich um negative Werte handelt kann man statt:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  depth := min(abs(d1), abs(d2));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
ganz einfach:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  depth := max(d1, d2);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
schreiben. Die neue PolyPolyIntersect Funktion sieht so aus:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon; var MTD: TVector2f): boolean;&lt;br /&gt;
var&lt;br /&gt;
  axis: TV2fArray;&lt;br /&gt;
  voffset: TVector2f;&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  MTD := to_v2f(0, 0);&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
  // Alle Achsen für A&lt;br /&gt;
  axis := CreateAxis(A);&lt;br /&gt;
  // Alle Achsen für B&lt;br /&gt;
  axis := CreateAxis(B);&lt;br /&gt;
  // Projezieren der Polygone&lt;br /&gt;
  for i := 0 to high(axis) do&lt;br /&gt;
    if CollisionCheck(A, B, axis[i], voffset) = false then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  // MTD bestimmen&lt;br /&gt;
  MTD := axis[0];&lt;br /&gt;
  for i := 1 to high(axis) do&lt;br /&gt;
    if v2f_length(axis[i]) &amp;lt; v2f_length(MTD) then&lt;br /&gt;
      MTD := axis[i];&lt;br /&gt;
  if v2f_dotproduct(voffset, MTD) &amp;lt; 0 then&lt;br /&gt;
    MTD := v2f_scale(MTD, -1);&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden zunächst alle Achsen ermittelt und dann projeziert, dabei werden die&lt;br /&gt;
Achsen mit sämtlichen potentiellen MTDs überschrieben und daraus der kleinste berechnet.&lt;br /&gt;
Diesen Vektor übergeben wir einfach mittels Var-Parameter und können dann unsere Polygone&lt;br /&gt;
trennen, indem wir den MTD-Vektor von ihrer derzeitigen Position abziehen.&lt;br /&gt;
&lt;br /&gt;
Dieser Code hier sorgt dafür, dass das Polygon auch wirklich von dem anderen getrennt und nicht&lt;br /&gt;
noch weiter hineingeschoben wird:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  if v2f_dotproduct(voffset, MTD) &amp;lt; 0 then&lt;br /&gt;
    MTD := v2f_scale(MTD, -1);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit position und radius bekommt er seine Werte zugewiesen.&lt;br /&gt;
Gezeichnet wird er mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawCircle(C: TCircle; aColor: TColor);&lt;br /&gt;
begin&lt;br /&gt;
  with Image1.Canvas do&lt;br /&gt;
  begin&lt;br /&gt;
    Pen.Color := aColor;&lt;br /&gt;
    Ellipse(round(C.position.x - C.radius), round(C.position.y - C.radius),&lt;br /&gt;
                          round(C.position.x + C.radius), round(C.position.y + C.radius));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 3 - Trennung von Polygonen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel wird ein Polygon mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  B.position := v2f_sub(B.position, MTD);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
verschoben, sodass die beiden Polygone sich nicht schneiden.&lt;br /&gt;
Es ließen sich auch beide um die hälfte des Vektors verschieben, dies hängt&lt;br /&gt;
von der Anwendung ab.&lt;br /&gt;
&lt;br /&gt;
'''Hier gibt es die Exe und den Code für die Trennung von Polygonen:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Trennung_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB):''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20295</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20295"/>
				<updated>2007-04-04T15:51:24Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Hinzugefügt: Kreis &amp;lt;&amp;gt; Polygon Kollision | Neue Struktur&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''von Polygonen mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Kollision zweier Polygone ==&lt;br /&gt;
&lt;br /&gt;
=== Die Theorie ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
=== Der Code ===&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei extendeds in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: extended;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Polygon Klasse&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    procedure SetVertex(n: integer; Value: TVector2f);// Setzt die Objektkoordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);                // Fügt ein Vertex hinzu&lt;br /&gt;
    procedure AddVertexAbs(v: TVector2f);             // Fügt ein Vertex mit Weltkoordinaten hinzu&lt;br /&gt;
    procedure RemoveVertex(n: integer);               // Entfernt ein Vertex&lt;br /&gt;
    property position: TVector2f read fposition write fposition;             // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex write SetVertex; // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;          // Vertex Weltkoordinaten&lt;br /&gt;
    property Count: integer read GetCount;                                   // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertexAbs(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v2f_sub(v, position);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.SetVertex(n: integer; Value: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  fvertices[n] := Value;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
== Kollision eines Kreises und eines Polygons ==&lt;br /&gt;
&lt;br /&gt;
=== Theorie ===&lt;br /&gt;
&lt;br /&gt;
Das Prinzip für die Kollision zweier Polygone ist denke ich jetzt klar geworden, doch was ist,&lt;br /&gt;
wenn wir einen Kreis haben, der mit einem Polygon kollidiert ?&lt;br /&gt;
Dieser Fall ist leicht abzuhandeln, ein Kreis hat unendlich viele Normalen, die man testen könnte,&lt;br /&gt;
uns reichen aber die, die die Vertices des Polygons schneiden würden, sprich: die Geraden, die vom Kreismittelpunkt zu den Ecken unseres Polygons führen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kreis_Quadrat.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die blauen Linien auf dem Bild sind wieder einmal die Geraden, bzw. die Achsen auf die wir projezieren, diese kommen zu den, die wir aus dem Polygon berechnen hinzu.&lt;br /&gt;
&lt;br /&gt;
=== Zusammenfassung ===&lt;br /&gt;
&lt;br /&gt;
*Wir berechnen also den Vektor vom Kreis-Mittelpunkt zum Vertex, dieser wird normalisiert.&lt;br /&gt;
*Dann projezieren wir das Polygon wie gehabt&lt;br /&gt;
*Der Kreis wird projeziert, indem der Vektor auf den wir multiplizieren mit dem Radius des Kreises skaliert (also skalar multipliziert) wird. Mit diesem wird dann genauso weiter verfahren. Dies ist dann der Max-Wert für unseren Kreis, der Min-Wert ist einfach der Max-Wert * -1, also -max.&lt;br /&gt;
&lt;br /&gt;
=== Der Code === &lt;br /&gt;
&lt;br /&gt;
Der Code bietet noch viel Spielraum für Optimierungen, so ist es zum Beispiel nicht nötig, für jedes Vertex eine Projektionsachse zu berechnen, sondern es reicht aus, das Vertex, bzw die Kante zu nutzen, die sich auch in Reichweite des Kreises befindet, da diese zwangsläufig geschnitten werden müssen.&lt;br /&gt;
Natürlich benötigen wir zunächst eine Kreis-Klasse:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TCircle = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;&lt;br /&gt;
    fradius: extended;&lt;br /&gt;
  public&lt;br /&gt;
    property position: TVector2f read fposition write fposition;&lt;br /&gt;
    property radius: extended read fradius write fradius;&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die Kollision zweier Kreise kann dann gleich mit implementiert werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CircleCircleIntersect(A, B: TCircle): boolean;&lt;br /&gt;
begin&lt;br /&gt;
  result := (sqr(A.position.x - B.position.x) + sqr(A.position.y - B.position.y)) &amp;lt; sqr(A.radius + B.radius);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Das sollte denke ich, soweit klar sein.&lt;br /&gt;
Nun folgt der Code zur Berechnung der Kreis &amp;lt;&amp;gt; Polygon Kollision. Es gibt nur eine äußere Schleife, da die Berechnungen für den Kreis gleich mit in dieser vorgenommen werden können. Ein bisschen Code ließe sich sicherlich auch noch auslagern, ich habe den Code so gelassen, weil ich denke, dass es der Übersicht sicherlich förderlich ist.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function CirclePolyIntersect(P: TPolygon; C: TCircle): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, pmin, pmax, cmin, cmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(P.position, C.position);&lt;br /&gt;
// P - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (P.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (P.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(P.vertices[l], P.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
//C - Alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
    proj := v2f_normalize(v2f_sub(C.position, P.vertices_abs[i]));&lt;br /&gt;
    // s.o.&lt;br /&gt;
    pmin := v2f_dotproduct(P.vertices[0], proj);&lt;br /&gt;
    pmax := pmin;&lt;br /&gt;
    for j := 1 to (P.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(P.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; pmin then&lt;br /&gt;
        pmin := dp;&lt;br /&gt;
      if dp &amp;gt; pmax then&lt;br /&gt;
        pmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    cmax := v2f_dotproduct(v2f_scale(proj, C.radius), proj);&lt;br /&gt;
    cmin := -cmax;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    pmin := pmin + foffset;&lt;br /&gt;
    pmax := pmax + foffset;&lt;br /&gt;
    d1 := pmin - cmax;&lt;br /&gt;
    d2 := cmin - pmax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
=== Beispiel 1 - Polygon &amp;lt;&amp;gt; Polygon ===&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
=== Beispiel 2 - Kreis &amp;lt;&amp;gt; Polygon === &lt;br /&gt;
&lt;br /&gt;
Für den Kreis ist die Verwendung im Prinzip die selbe, mit:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  C := TCircle.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
wird zunächst ein Kreis erzeugt und mit position und radius bekommt er seine Werte zugewiesen.&lt;br /&gt;
Gezeichnet wird er mittels:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawCircle(C: TCircle; aColor: TColor);&lt;br /&gt;
begin&lt;br /&gt;
  with Image1.Canvas do&lt;br /&gt;
  begin&lt;br /&gt;
    Pen.Color := aColor;&lt;br /&gt;
    Ellipse(round(C.position.x - C.radius), round(C.position.y - C.radius),&lt;br /&gt;
                          round(C.position.x + C.radius), round(C.position.y + C.radius));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt für die Kollision Kreis &amp;lt;&amp;gt; Polygon:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_Kreis_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB):''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:SAT_Kreis_Quadrat.jpg&amp;diff=20294</id>
		<title>Datei:SAT Kreis Quadrat.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:SAT_Kreis_Quadrat.jpg&amp;diff=20294"/>
				<updated>2007-04-04T15:33:32Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: *Beschreibung: Anwendung von SAT bei einem Kreis und einem Polygon&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;*Beschreibung: Anwendung von SAT bei einem Kreis und einem Polygon&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20293</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20293"/>
				<updated>2007-04-04T07:40:49Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Vectors Unit komplett auf Extended umgestellt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''zweier Polygone mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Der Code ==&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei extendeds in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: extended): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: extended;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): extended;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Polygon Klasse&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    procedure SetVertex(n: integer; Value: TVector2f);// Setzt die Objektkoordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);                // Fügt ein Vertex hinzu&lt;br /&gt;
    procedure AddVertexAbs(v: TVector2f);             // Fügt ein Vertex mit Weltkoordinaten hinzu&lt;br /&gt;
    procedure RemoveVertex(n: integer);               // Entfernt ein Vertex&lt;br /&gt;
    property position: TVector2f read fposition write fposition;             // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex write SetVertex; // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;          // Vertex Weltkoordinaten&lt;br /&gt;
    property Count: integer read GetCount;                                   // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertexAbs(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v2f_sub(v, position);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.SetVertex(n: integer; Value: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  fvertices[n] := Value;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB):''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20292</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20292"/>
				<updated>2007-04-03T18:00:22Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''zweier Polygone mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Der Code ==&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei Singles in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: Single;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Polygon Klasse&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    procedure SetVertex(n: integer; Value: TVector2f);// Setzt die Objektkoordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);                // Fügt ein Vertex hinzu&lt;br /&gt;
    procedure AddVertexAbs(v: TVector2f);             // Fügt ein Vertex mit Weltkoordinaten hinzu&lt;br /&gt;
    procedure RemoveVertex(n: integer);               // Entfernt ein Vertex&lt;br /&gt;
    property position: TVector2f read fposition write fposition;             // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex write SetVertex; // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;          // Vertex Weltkoordinaten&lt;br /&gt;
    property Count: integer read GetCount;                                   // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertexAbs(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v2f_sub(v, position);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.SetVertex(n: integer; Value: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  fvertices[n] := Value;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB):''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20291</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20291"/>
				<updated>2007-04-03T17:59:12Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''zweier Polygone mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Der Code ==&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei Singles in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: Single;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  // Polygon Klasse&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    procedure SetVertex(n: integer; Value: TVector2f);// Setzt die Objektkoordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);                // Fügt ein Vertex hinzu&lt;br /&gt;
    procedure AddVertexAbs(v: TVector2f);             // Fügt ein Vertex mit Weltkoordinaten hinzu&lt;br /&gt;
    procedure RemoveVertex(n: integer);               // Entfernt ein Vertex&lt;br /&gt;
    property position: TVector2f read fposition write fposition;                // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex write SetVertex;    // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;             // Vertex Weltkoordinaten&lt;br /&gt;
    property Count: integer read GetCount;                                      // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertexAbs(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v2f_sub(v, position);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.SetVertex(n: integer; Value: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  fvertices[n] := Value;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB):''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20290</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20290"/>
				<updated>2007-04-03T17:22:01Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''zweier Polygone mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Der Code ==&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei Singles in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: Single;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);&lt;br /&gt;
    procedure RemoveVertex(n: integer);&lt;br /&gt;
    property position: TVector2f read fposition write fposition;                // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex;                    // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;&lt;br /&gt;
    property Count: integer read GetCount;                                      // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB):''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20289</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20289"/>
				<updated>2007-04-03T17:21:08Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''zweier Polygone mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (kurz: SAT) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Der Code ==&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei Singles in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: Single;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);&lt;br /&gt;
    procedure RemoveVertex(n: integer);&lt;br /&gt;
    property position: TVector2f read fposition write fposition;                // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex;                    // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;&lt;br /&gt;
    property Count: integer read GetCount;                                      // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB)''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20288</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20288"/>
				<updated>2007-04-03T17:20:26Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''zweier Polygone mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [[Tutorial_Lineare_Algebra|Vektorrechnung]] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (im folgenden mit SAT abgekürzt) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Der Code ==&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei Singles in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: Single;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);&lt;br /&gt;
    procedure RemoveVertex(n: integer);&lt;br /&gt;
    property position: TVector2f read fposition write fposition;                // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex;                    // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;&lt;br /&gt;
    property Count: integer read GetCount;                                      // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB)''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20287</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20287"/>
				<updated>2007-04-03T17:11:21Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''zweier Polygone mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [wiki]Vektorrechnung[/wiki] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (im folgenden mit SAT abgekürzt) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Der Code ==&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei Singles in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: Single;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);&lt;br /&gt;
    procedure RemoveVertex(n: integer);&lt;br /&gt;
    property position: TVector2f read fposition write fposition;                // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex;                    // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;&lt;br /&gt;
    property Count: integer read GetCount;                                      // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB)''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20285</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20285"/>
				<updated>2007-04-03T17:10:52Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: hat SAT nach Separating Axis Theorem verschoben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [wiki]Vektorrechnung[/wiki] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (im folgenden mit SAT abgekürzt) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Der Code ==&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei Singles in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: Single;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);&lt;br /&gt;
    procedure RemoveVertex(n: integer);&lt;br /&gt;
    property position: TVector2f read fposition write fposition;                // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex;                    // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;&lt;br /&gt;
    property Count: integer read GetCount;                                      // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB)''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=SAT&amp;diff=20286</id>
		<title>SAT</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=SAT&amp;diff=20286"/>
				<updated>2007-04-03T17:10:52Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: hat SAT nach Separating Axis Theorem verschoben&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Separating Axis Theorem]]&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20284</id>
		<title>Tutorial Separating Axis Theorem</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Separating_Axis_Theorem&amp;diff=20284"/>
				<updated>2007-04-03T17:10:24Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: Kollisionserkennung zweier 2D-Polygone&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Kollisionserkennung=&lt;br /&gt;
''mit dem Separating Axis Theorem''&lt;br /&gt;
&lt;br /&gt;
== Vorwort ==&lt;br /&gt;
&lt;br /&gt;
In diesem Tutorial möchte ich eine schnelle Variante zur Kollision zweier ''konvexer'' Polygone erläutern. Diese kann nachträglich für ''konkave'' Polygone und andere Objekte wie Kreise und abgerundete Objekte verwendet werden.&lt;br /&gt;
Um den mathematischen Hintergrund zu verstehen, ist es sinnvoll ein wenig Kenntnis in [wiki]Vektorrechnung[/wiki] zu haben.&lt;br /&gt;
&lt;br /&gt;
== Die Theorie ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale.jpg|right]]&lt;br /&gt;
Das Separating Axis Theorem (im folgenden mit SAT abgekürzt) besagt, dass zwei Polygone sich nicht schneiden, wenn es möglich ist, eine Gerade zu finden, die zwischen den beiden liegt.&lt;br /&gt;
Nun gibt es unendlich viele Geraden die man testen könnte...&lt;br /&gt;
Glücklicherweise kann man sich hier auf eine überschaubare Zahl beschränken, denn man braucht nur die Anzahl der Seiten beider Polygone. Bei einem Viereck wären das vier, bei einem Dreieck drei, etc.&lt;br /&gt;
Hat man die Eckpunkte des Polygons als Vektoren (Ortsvektoren) gegeben, kann man durch Subtraktion zweier Ortsvektoren den Vektor bestimmen der zu der Seite gehört, die von den beiden Vektoren aufgespannt wird.&lt;br /&gt;
&lt;br /&gt;
Auf dem Bild rechts ist ein Beispiel zu sehen. Dort ist ein Quadrat, die grünen Striche bezeichnen die Ortsvektoren der Eckpunkte, der rote  Strich ist die berechnete Seite. Was wir aber brauchen ist der blaue  Strich, das ist die Normale der Seite.&lt;br /&gt;
Die Normale berechnet sich folgendermaßen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Normale_Formel.jpg]]&lt;br /&gt;
&lt;br /&gt;
die Koordinaten werden vertauscht und eine von beiden wird negiert.&lt;br /&gt;
Der Vektor muss dann noch normalisiert werden, sodass er die Länge 1 erhält.&lt;br /&gt;
Jetzt müssen beide Polygone auf diesen Vektor projeziert werden, denn dadurch haben wir ein Eindimensionales Abbild unserer Polygone und können mittels eines einfachen Vergleichs überprüfen, ob sich die beiden 1D-Strecken schneiden. Sollte ein Fall eintreffen bei dem kein Schnitt stattfindet, dann kollidieren die beiden Polygone nicht und die Prozedur kann abgebrochen werden.&lt;br /&gt;
Nun zur Projektion:&lt;br /&gt;
&lt;br /&gt;
[[Bild:SAT_Kollision.jpg]][[Bild:SAT_Keine_Kollision.jpg]]&lt;br /&gt;
&lt;br /&gt;
Auf dem linken Bild sieht man, wie beide Polygone auf die Gerade projeziert werden, der pinke Bereich zeigt die Schnittmenge an. In diesem Fall ist die Gerade die Normale der linken oder rechten Seite des Quadrats.&lt;br /&gt;
Auf dem Bild rechts ist der Fall dargestellt, dass keine Kollision stattfindet, demzufolge gibt es auch keine Schnittmenge auf der Geraden.&lt;br /&gt;
Dazu ist allerdings zu sagen, dass die Gerade keine räumliche Position hat. So wie Vektoren auch keine Positionen haben, Vektoren sind lediglich verschiebungsanweisungen und unsere &amp;quot;Gerade&amp;quot; wie ich sie hier nenne, ist auch nur ein Vektor, denn wo sie liegt ist letzten endes egal, da wir ja ein eindimensionales Ergebnis anstreben.&lt;br /&gt;
&lt;br /&gt;
Für die Projektion eines Vektors auf einen anderen verwenden wir das [[Standard_Skalarprodukt|Skalarprodukt]], bei diesem kommt ein Zahlenwert heraus, der die Position des Eckpunktes auf unserer 1D-Geraden darstellt.&lt;br /&gt;
Haben wir sämtliche Punkte projeziert, so müssen wir für die jeweiligen Polygone noch jeweils den kleinsten und größten Wert heraussuchen, damit wir zwei Strecken erhalten.&lt;br /&gt;
Diese werden dann auf Schnitt geprüft und das wars.&lt;br /&gt;
&lt;br /&gt;
== Zusammenfassung ==&lt;br /&gt;
&lt;br /&gt;
*Jedes der beiden Polygone durchgehen und alle nötigen Geraden aus den Normalen der Seitenflächen bestimmen&lt;br /&gt;
**Jeden Eckpunkt jedes Polygons auf diese Geraden Projezieren&lt;br /&gt;
**Die kleinsten und größten Werte ermitteln und auf Schnitt prüfen&lt;br /&gt;
*Tritt der Fall auf, dass kein Schnitt statt findet, so kann sofort abgebrochen werden, es findet keine Kollision statt.&lt;br /&gt;
&lt;br /&gt;
== Der Code ==&lt;br /&gt;
&lt;br /&gt;
Um bei so vielen Vektoroperationen nicht völlig durcheinander zu geraten und die Übersicht zu verlieren (was dabei durchaus mal passieren kann), ist es es sinnvoll, sich eine Unit zu schreiben, die einem die Vektorrechnung abnimmt. &lt;br /&gt;
Im weiteren Verlauf des Tutorials werde ich folgende Unit benutzen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
// Unit Vectors&lt;br /&gt;
(**************************************************&lt;br /&gt;
&lt;br /&gt;
- Enthält: TVector2f&lt;br /&gt;
&lt;br /&gt;
**************************************************)&lt;br /&gt;
&lt;br /&gt;
unit Vectors;&lt;br /&gt;
&lt;br /&gt;
interface&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  // 2D Vektor&lt;br /&gt;
  TVector2f = record&lt;br /&gt;
    X, Y: Extended;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  // Zwei Singles in einen TVector2f umwandeln&lt;br /&gt;
  function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
  // Zwei Vektoren addieren&lt;br /&gt;
  function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor von einem anderen subtrahieren&lt;br /&gt;
  function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
  // Einen Vektor skalieren&lt;br /&gt;
  function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
  // Ermittelt die Länge eines Vektors&lt;br /&gt;
  function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
  // Normalisiert einen Vektor (sodass v2f_length = 1)&lt;br /&gt;
  function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
  // Ermittelt ds Skalarprodukt&lt;br /&gt;
  function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
&lt;br /&gt;
implementation&lt;br /&gt;
&lt;br /&gt;
function To_v2f(X, Y: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := X;&lt;br /&gt;
  Result.Y := Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Add(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X + V2.X;&lt;br /&gt;
  Result.Y := V1.Y + V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Sub(V1, V2: TVector2f): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V1.X - V2.X;&lt;br /&gt;
  Result.Y := V1.Y - V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Scale(V: TVector2f; Scalar: Single): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  Result.X := V.X * Scalar;&lt;br /&gt;
  Result.Y := V.Y * Scalar;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Length(V: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := sqrt(V.X * V.X + V.Y * V.Y);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_Normalize(V: TVector2f): TVector2f;&lt;br /&gt;
var&lt;br /&gt;
  L: Single;&lt;br /&gt;
begin&lt;br /&gt;
  L := v2f_Length(V);&lt;br /&gt;
&lt;br /&gt;
  if L = 0 then&lt;br /&gt;
    L := 1;&lt;br /&gt;
&lt;br /&gt;
  Result := v2f_Scale(V, 1 / L);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function v2f_DotProduct(V1, V2: TVector2f): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := V1.X * V2.X + V1.Y * V2.Y;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Jedoch schadet es nicht, sich eine eigene zu schreiben, um seine Kenntnisse in Sachen Vektorrechnung ein wenig zu festigen.&lt;br /&gt;
Jetzt benötigen wir eine Klasse für unsere Polygone.&lt;br /&gt;
Die einzelnen Eckpunkte der Polygone werden nicht etwa absolut (also in Weltkoordinaten), sondern relativ zu einem Punkt angegeben, so fällt es leichter, das Polygon zu verschieben. Der absolute Wert kann jedoch ganz nützlich sein, um z.B. ein Polygon zu zeichnen. &lt;br /&gt;
Als erstes definieren wir ein Array von TVector2f, denn jeder Eckpunkt ist ein Vektor und unsere Polygone sollen ja beliebig viele davon besitzen können, also:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TV2fArray = array of TVector2f;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dann folgt die Definition unseres Polygons:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  TPolygon = class&lt;br /&gt;
  private&lt;br /&gt;
    fposition: TVector2f;                             // Position&lt;br /&gt;
    fvertices: TV2fArray;                             // Vertices (Objektkoordinaten)&lt;br /&gt;
    function GetVertex(n: integer): TVector2f;        // Liefert die Objektkoordinaten&lt;br /&gt;
    function GetVertexAbs(n: integer): TVector2f;     // Liefert die absoluten Koordinaten&lt;br /&gt;
    function GetCount: integer;                       // Liefert length(fvertices)&lt;br /&gt;
  public&lt;br /&gt;
    procedure AddVertex(v: TVector2f);&lt;br /&gt;
    procedure RemoveVertex(n: integer);&lt;br /&gt;
    property position: TVector2f read fposition write fposition;                // Position&lt;br /&gt;
    property vertices[n: integer]: TVector2f read GetVertex;                    // Vertex Koordinaten&lt;br /&gt;
    property vertices_abs[n: integer]: TVector2f read GetVertexAbs;&lt;br /&gt;
    property Count: integer read GetCount;                                      // siehe GetCount&lt;br /&gt;
  end;&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Unser Polygon hat jetzt eine Position und Eckpunkte, ebenfalls können wir auf absolute, sowie relative Koordinaten zugreifen. Count liefert uns die Anzahl der Ecken. [size=9][i](Eine &lt;br /&gt;
Ecke bezeichnet man auch als Vertex, der Plural von Vertex ist Vertices.)[/i][/size]&lt;br /&gt;
Hier sind die entsprechenden Funktionen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TPolygon.AddVertex(v: TVector2f);&lt;br /&gt;
begin&lt;br /&gt;
  setlength(fvertices, length(fvertices) + 1);&lt;br /&gt;
  fvertices[high(fvertices)] := v;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure TPolygon.RemoveVertex(n: integer);&lt;br /&gt;
var&lt;br /&gt;
  i: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := n to high(fvertices) - 1 do&lt;br /&gt;
    fvertices[i] := fvertices[i + 1];&lt;br /&gt;
  setlength(fvertices, length(fvertices) - 1);  &lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertex(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := fvertices[n];&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetVertexAbs(n: integer): TVector2f;&lt;br /&gt;
begin&lt;br /&gt;
  result := v2f_add(fvertices[n], fposition);&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function TPolygon.GetCount: integer;&lt;br /&gt;
begin&lt;br /&gt;
  result := length(fvertices);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Mit AddVertex können wir unsere Vertices hinzufügen, aber dazu später mehr.&lt;br /&gt;
Nun folgt die Kollisionserkennung an sich: &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
function PolyPolyIntersect(A, B: TPolygon): boolean;&lt;br /&gt;
var&lt;br /&gt;
  i, j, l: integer;&lt;br /&gt;
  tmp, proj, voffset: TVector2f;&lt;br /&gt;
  dp, amin, amax, bmin, bmax, d1, d2, foffset: extended;&lt;br /&gt;
begin&lt;br /&gt;
  // Offset berechnen&lt;br /&gt;
  voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
// A - alle Projektionsgeraden ermitteln und projezieren&lt;br /&gt;
  for i := 0 to (a.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (a.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    // Berechnung der Seitenfläche&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    // Berechnet die Normale der Seitenfläche&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    // Projeziert den ersten Wert&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    // Findet den kleinsten und größten projezierten Wert für die Gerade für A&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      // projezieren&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // s.o.&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    // B&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    // 1D Kollision&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    // Wenn es keine Überschneidung gibt, abbrechen -&amp;gt; keine Kollision&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
// B - alle Projektionsgeraden ermitteln und projezieren (s.o.)&lt;br /&gt;
  for i := 0 to (b.count - 1) do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (b.count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    tmp := v2f_sub(b.vertices[l], b.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    bmin := v2f_dotproduct(b.vertices[0], proj);&lt;br /&gt;
    bmax := bmin;&lt;br /&gt;
    for j := 1 to (b.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(b.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; bmin then&lt;br /&gt;
        bmin := dp;&lt;br /&gt;
      if dp &amp;gt; bmax then&lt;br /&gt;
        bmax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
  end;&lt;br /&gt;
  // Kollision&lt;br /&gt;
  result := true;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Wie man sieht, ist der zweite Teil des Codes, mit dem ersten sogut wie identisch, der einzige Unterschied besteht darin, dass dort die Geraden aus den Vertices von B berechnet werden. Nehmen wir den Code mal auseinander:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    tmp := v2f_sub(a.vertices[l], a.vertices[i]);&lt;br /&gt;
    proj := v2f_normalize(to_v2f(-tmp.y, tmp.x));&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier wird zunächst der Vektor berechnet, der für die Seitenfläche steht, durch die Schleife wird dies für alle Seitenflächen gemacht. Danach wird die Normale berechnet.&lt;br /&gt;
proj ist dann der Vektor auf den wir unsere Vertices projezieren.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    amin := v2f_dotproduct(a.vertices[0], proj);&lt;br /&gt;
    amax := amin;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier projezieren wir das erste Vertex von A und haben somit den ersten Punkt unserer Strecke.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    for j := 1 to (a.count - 1) do&lt;br /&gt;
    begin&lt;br /&gt;
      dp := v2f_dotproduct(a.vertices[j], proj);&lt;br /&gt;
      if dp &amp;lt; amin then&lt;br /&gt;
        amin := dp;&lt;br /&gt;
      if dp &amp;gt; amax then&lt;br /&gt;
        amax := dp;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Hier werden alle weiteren Vertices projeziert und der kleinste, sowie größte Wert gespeichert. &lt;br /&gt;
Das gleiche wird für B wiederholt.&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    foffset := v2f_dotproduct(voffset, proj);&lt;br /&gt;
    amin := amin + foffset;&lt;br /&gt;
    amax := amax + foffset;&lt;br /&gt;
    d1 := amin - bmax;&lt;br /&gt;
    d2 := bmin - amax;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Da es sich bei unseren Vertexkoordinaten um Objektkoordinaten handelt, müssen die projezierten Vertices nun um die Differenz beider Polygonpositionen verschoben werden.&lt;br /&gt;
Dies klingt zunächst einmal kompliziert, macht aber sinn. Die Alternative wäre, jeden Punkt in Weltkoordinaten (also absolute Koordinaten) umzuwandeln. Dadurch, dass wir am Anfang den Vektor zwischen den beiden Polygonen berechnen:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
voffset := v2f_sub(A.position, B.position);&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
und ihn danach Projezieren, können wir diese Verschiebung auf unserer Geraden nachträglich vornehmen und haben somit alles in einem Abwasch erledigt.  &lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
    if (d1 &amp;gt; 0) or (d2 &amp;gt; 0) then&lt;br /&gt;
    begin&lt;br /&gt;
      result := false;&lt;br /&gt;
      exit;&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Ohne einen Vergleich kommt auch diese Kollisionsabfrage nicht aus, hier jedoch nur auf eindimensionaler Ebene. Gibt es keine Überschneidung der beiden 1D-Strecken, so kann die Prozedur abgebrochen werden, denn es gibt keine Kollision. Ist die komplette Prozedur durchgelaufen ohne abzubrechen, so wird result auf true gesetzt und eine Kollision ist bestätigt.&lt;br /&gt;
&lt;br /&gt;
==Das Beispielprojekt ==&lt;br /&gt;
&lt;br /&gt;
Was wäre ein Tutorial doch ohne Beispiel ;)&lt;br /&gt;
Ich werde hier nur kurz die Verwendung des Codes erläutern und ein kleines&lt;br /&gt;
Beispielprogramm anhängen.&lt;br /&gt;
Ein Polygon muss natürlich erst einmal erzeugt werden:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
A := TPolygon.Create;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Die einfachste Möglichkeit es zu gestalten funktioniert so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
  with A do&lt;br /&gt;
  begin&lt;br /&gt;
    position := to_v2f(200, 200);&lt;br /&gt;
    AddVertex(to_v2f(50, -50));&lt;br /&gt;
    AddVertex(to_v2f(50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, 50));&lt;br /&gt;
    AddVertex(to_v2f(-50, -50));&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
Dies liefert ein Quadrat mit den Maßen 100*100 an der Position (200|200).&lt;br /&gt;
&lt;br /&gt;
Zeichnen kann man das Polygon ganz einfach so:&lt;br /&gt;
&amp;lt;pascal&amp;gt;&lt;br /&gt;
procedure TMainForm.DrawPolygon(A: TPolygon);&lt;br /&gt;
var&lt;br /&gt;
  i, l: integer;&lt;br /&gt;
begin&lt;br /&gt;
  for i := 0 to A.Count - 1 do&lt;br /&gt;
  begin&lt;br /&gt;
    l := i + 1;&lt;br /&gt;
    if l &amp;gt; (A.Count - 1) then&lt;br /&gt;
      l := 0;&lt;br /&gt;
    Image1.Canvas.MoveTo(round(A.vertices_abs[l].x), round(A.vertices_abs[l].y));&lt;br /&gt;
    Image1.Canvas.LineTo(round(A.vertices_abs[i].x), round(A.vertices_abs[i].y));&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/pascal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Und hier das Beispielprojekt:'''&lt;br /&gt;
&lt;br /&gt;
''Exe:'' http://www.exec-dev.de/SAT_Tutorial/SAT_exe.zip&lt;br /&gt;
&lt;br /&gt;
''Source:'' http://www.exec-dev.de/SAT_Tutorial/SAT_src.zip &lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
&lt;br /&gt;
=== Separating Axis Theorem ===&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng):''&lt;br /&gt;
http://www.harveycartel.org/metanet/tutorials/tutorialA.html&lt;br /&gt;
&lt;br /&gt;
''SAT-Tutorial(Eng / VB)''&lt;br /&gt;
http://gpwiki.org/index.php/VB:Tutorials:Building_A_Physics_Engine:Basic_Intersection_Detection&lt;br /&gt;
&lt;br /&gt;
== Nachwort ==&lt;br /&gt;
&lt;br /&gt;
Ich hoffe das Tutorial war nicht zu trocken und hat vielleicht auch ein wenig Spass gemacht und weitergeholfen. Für Fragen, Vorschläge, Ergänzungen, etc. bin ich selbstverständlich offen.&lt;br /&gt;
&lt;br /&gt;
mfg&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:SAT_Keine_Kollision.jpg&amp;diff=20283</id>
		<title>Datei:SAT Keine Kollision.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:SAT_Keine_Kollision.jpg&amp;diff=20283"/>
				<updated>2007-04-03T16:59:24Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: *Beschreibung: Dargestellt ist der Fall, dass beim Separating Axis Theorem keine Kollision auftritt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;*Beschreibung: Dargestellt ist der Fall, dass beim Separating Axis Theorem keine Kollision auftritt&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:SAT_Kollision.jpg&amp;diff=20282</id>
		<title>Datei:SAT Kollision.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:SAT_Kollision.jpg&amp;diff=20282"/>
				<updated>2007-04-03T16:58:47Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: *Beschreibung: Dargestellt ist der Fall einer Kollision beim Separating Axis Theorem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;*Beschreibung: Dargestellt ist der Fall einer Kollision beim Separating Axis Theorem&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:SAT_Normale_Formel.jpg&amp;diff=20281</id>
		<title>Datei:SAT Normale Formel.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:SAT_Normale_Formel.jpg&amp;diff=20281"/>
				<updated>2007-04-03T16:57:45Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: *Beschreibung: Dargestellt ist die Formel zur Berechnung der Normale eines Vektors&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;*Beschreibung: Dargestellt ist die Formel zur Berechnung der Normale eines Vektors&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:SAT_Normale.jpg&amp;diff=20280</id>
		<title>Datei:SAT Normale.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:SAT_Normale.jpg&amp;diff=20280"/>
				<updated>2007-04-03T16:56:42Z</updated>
		
		<summary type="html">&lt;p&gt;Seth: *Beschreibung: Dargestellt ist die Normale einer Seite des Polygons&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;*Beschreibung: Dargestellt ist die Normale einer Seite des Polygons&lt;/div&gt;</summary>
		<author><name>Seth</name></author>	</entry>

	</feed>