Grundlagen der Computergeometrie
Übung 3
1 Affinkombination von Punkten
Gegeben sei ein Affiner Raum ππ = (π«π«, π±π±). Wir haben in der letzten Übung gelernt, dass man
a) zwei Punkte subtrahieren kann. Das Ergebnis ist ein Vektor.
b) einen Punkt und einen Vektor addieren kann. Das Ergebnis ist eine Verschiebung des
Punktes.
Beide Möglichkeiten kann man aus den Axiomen für den Affinen Raum herleiten. Weitere
Operationen mit Punkten sind nicht möglich. Insbesondere kann man Punkte nicht addieren.
In der Vorlesung haben Sie aber eine Operation hergeleitet, die einer Addition von Punkten sehr
ähnlich sieht, nämlich die Affinkombination von Punkten. Dabei wird ein Punkt ππ β π«π« als gewichtete
Summe der ππ Punkte ππ1 , β¦ , ππππ β π«π« dargestellt. Die Gewichte sind die reellen Zahlen πΌπΌ1 , β¦ , πΌπΌππ β β.
ππ = πΌπΌ1 β ππ1 + β¦ + πΌπΌππ β ππππ
Für die Gewichte gilt dabei immer, dass ihre Summe gleich 1 ist.
πΌπΌ1 + β¦ + πΌπΌππ = 1
Für den Fall, dass ππ eine Affinkombination von nur zwei Punkten ist, gilt folgender Zusammenhang
bei den Gewichten.
πΌπΌ1 + πΌπΌ2 = 1
πΌπΌ1 = 1 β πΌπΌ2
Den Punkt ππ kann man dann wie folgt darstellen.
ππ = (1 β πΌπΌ2 ) β ππ1 + πΌπΌ2 β ππ2
Diese Gleichung kann man so umstellen, dass ππ als Verschiebung des Punktes ππ1 um das πΌπΌ2 -fache
des Vektors ππ2 β ππ1 dargestellt wird.
ππ = 1 β ππ1 β πΌπΌ2 β ππ1 + πΌπΌ2 β ππ2
Aufgabe
ππ = ππ1 + πΌπΌ2 β (ππ2 β ππ1 )
Gegeben seien die drei Punkte π΄π΄, π΅π΅, ππ β π«π«. Beschreiben Sie einen Algorithmus, der bestimmt, ob der
οΏ½οΏ½οΏ½οΏ½ liegt. (3 Punkte)
Punkt ππ auf der Strecke π΄π΄π΄π΄
Lösung
Der folgende Algorithmus basiert darauf, dass wir den Punkt ππ zunächst als Affinkombination der
Punkte π΄π΄ und π΅π΅ darstellen.
ππ = πΌπΌ β π΄π΄ + π½π½ β π΅π΅
Die Summe der Gewichte ist 1. Wir können damit eines der Gewichte, nämlich πΌπΌ, eliminieren und
den Punkt ππ als Verschiebung des Punktes π΄π΄ um das π½π½-fache des Vektors π΅π΅ β π΄π΄ darstellen.
ππ = (1 β π½π½) β π΄π΄ + π½π½ β π΅π΅
ππ = 1 β π΄π΄ β π½π½ β π΄π΄ + π½π½ β π΅π΅
ππ = π΄π΄ + π½π½ β (π΅π΅ β π΄π΄)
Im Hinblick auf die Aufgabenstellung gilt folgendes:
β’
β’
β’
β’
Wenn π½π½ = 0 ist, dann ist ππ = π΄π΄.
Wenn π½π½ = 1 ist, dann ist ππ = π΅π΅.
Wenn 0 < π½π½ < 1 ist, dann liegt ππ genau zwischen π΄π΄ und π΅π΅.
Wenn π½π½ < 0 oder π½π½ > 1 ist, dann liegt der Punkt nicht auf der Strecke οΏ½οΏ½οΏ½οΏ½
π΄π΄π΄π΄.
Wir müssen also den Wert von π½π½ berechnen und prüfen, ob dieser im Intervall [0,1] liegt. Dazu
betrachten wir zunächst die Gleichung für ππ.
πππ₯π₯
π΄π΄π₯π₯
π΅π΅π₯π₯ β π΄π΄π₯π₯
οΏ½ππ οΏ½ = οΏ½π΄π΄ οΏ½ + π½π½ β οΏ½π΅π΅ β π΄π΄ οΏ½
π¦π¦
π¦π¦
π¦π¦
π¦π¦
Faktisch haben wir hier ein Gleichungssystem mit zwei Gleichungen und einer Unbekannten. Dieses
gilt es zu lösen. Wie stellen die Gleichungen auf π½π½ um.
π½π½1 =
π½π½2 =
πππ₯π₯ β π΄π΄π₯π₯
οΏ½π΅π΅ β π΄π΄
π₯π₯
π₯π₯
πππ¦π¦ β π΄π΄π¦π¦
οΏ½π΅π΅ β π΄π΄
π¦π¦
π¦π¦
Wenn π½π½1 β π½π½2 ist, dann haben wir den Fall, dass der Punkt ππ nicht auf der Geraden liegt, die durch π΄π΄
und π΅π΅ geht. Wenn aber π½π½ = π½π½1 = π½π½2 ist, dann liegt ππ auf dieser Geraden. Wenn π½π½ außerdem im
Intervall [0,1] liegt, dann liegt ππ auch auf der Strecke οΏ½οΏ½οΏ½οΏ½
π΄π΄π΄π΄.
2 Baryzentrische Koordinaten
Gegeben sei ein Affiner Raum ππ = (π«π«, π±π±). Die Dimension von ππ sei ππ. Gegeben seien weiterhin
ππ + 1 Punkte ππ0 β¦ ππππ β π«π« und ππ + 1 Gewichte πΌπΌ0 β¦ πΌπΌππ β β mit πΌπΌ0 + β¦ + πΌπΌππ = 1. Der Punkt
ππ β π«π« sei die folgende Affinkombination.
ππ = πΌπΌ0 ππ0 + β¦ + πΌπΌππ ππππ
Das Besondere dabei ist, dass der Punkt ππ im Bezug auf die Punkte ππ0 β¦ ππππ eindeutig durch die
Gewichte πΌπΌ0 β¦ πΌπΌππ festgelegt ist. Letztere nennt man die baryzentrischen Koordinaten von ππ.
Wichtig ist, dass die Summe der baryzentrischen Koordinaten gleich 1 ist und dass die Anzahl der
Bezugspunkte genau um eins größer ist als die Dimension des Affinen Raums. Darüber hinaus
müssen die Bezugspunkte paarweise verschieden sein. Die Menge der ππ + 1 Bezugspunkte nennt
man einen ππ-Simplex.
Da wir in der Ebene drei Bezugspunkte benötigen, beziehen sich die baryzentrischen Koordinaten
eines Punktes in der Ebene immer auf ein bestimmtes Dreieck (2-Simplex) ππ0 ππ1 ππ2 . Entsprechend
beziehen sich die baryzentrischen Koordinaten eines Punktes im Raum immer auf einen bestimmten
Tetraeder (3-Simplex) ππ0 ππ1 ππ2 ππ3 .
Auch Vektoren kann man mittels baryzentrischer Koordinaten darstellen. Seien π½π½0 β¦ π½π½ππ β β die
baryzentrischen Koordinaten eines Vektors π£π£ β π±π± bezogen auf einen bestimmten ππ-Simplex. Dann
ist die Summe der Koordinaten π½π½0 + β¦ + π½π½ππ gleich 0.
Aufgabe
1
4
3
3
a) Gegeben seien die Punkte π΄π΄ = οΏ½ οΏ½, π΅π΅ = οΏ½ οΏ½, πΆπΆ = οΏ½ οΏ½ und ππ = οΏ½ οΏ½. Berechnen Sie die
2
1
7
3
baryzentrischen Koordinaten von ππ bezüglich des Dreiecks π΄π΄π΄π΄π΄π΄. (3 Punkte)
b) Nennen Sie einen Nachteil baryzentrischer Koordinaten gegenüber kartesischen
Koordinaten, insbesondere im Hinblick auf eine effiziente Implementierung. (1 Punkt)
c) Implementieren Sie die Methode Triangle2.GetBarycentricCoordinates(). Starten Sie
anschließend das Programm und evaluieren Sie, ob Ihre Implementierung korrekt ist.
Lösung
a) Für die Berechnung der baryzentrischen Koordinaten kann man die Cramersche Regel anwenden.
πππ₯π₯
det οΏ½πππ¦π¦
1
πππ΄π΄ =
π΄π΄π₯π₯
det οΏ½π΄π΄π¦π¦
1
π΄π΄π₯π₯
det οΏ½π΄π΄π¦π¦
1
πππ΅π΅ =
π΄π΄π₯π₯
det οΏ½π΄π΄π¦π¦
1
π΄π΄π₯π₯
det οΏ½π΄π΄π¦π¦
1
πππΆπΆ =
π΄π΄π₯π₯
det οΏ½π΄π΄π¦π¦
1
π΅π΅π₯π₯
π΅π΅π¦π¦
1
π΅π΅π₯π₯
π΅π΅π¦π¦
1
π΅π΅π₯π₯ πΆπΆπ₯π₯
3
π΅π΅π¦π¦ πΆπΆπ¦π¦ οΏ½ det οΏ½3
1
1
1 =
π΅π΅π₯π₯ πΆπΆπ₯π₯
1
π΅π΅π¦π¦ πΆπΆπ¦π¦ οΏ½ det οΏ½2
1
1
1
πππ₯π₯
πππ¦π¦
1
π΅π΅π₯π₯
π΅π΅π¦π¦
1
πΆπΆπ₯π₯
1
πΆπΆπ¦π¦ οΏ½ det οΏ½2
1
1 =
πΆπΆπ₯π₯
1
πΆπΆπ¦π¦ οΏ½ det οΏ½2
1
1
πππ₯π₯
1
πππ¦π¦ οΏ½ det οΏ½2
1
1 =
πΆπΆπ₯π₯
1
πΆπΆπ¦π¦ οΏ½ det οΏ½2
1
1
Es gilt offensichtlich πππ΄π΄ + πππ΅π΅ + πππΆπΆ = 1.
4
1
1
4
1
1
4
1
1
4
1
1
3
3
1
4
1
1
3
7οΏ½
1 = 4
3
17
7οΏ½
1
3
7οΏ½
1 = 8
3
17
7οΏ½
1
3
3οΏ½
1 = 1 β ππ β ππ = 5
π΄π΄
π΅π΅
3
17
7οΏ½
1
b) Die baryzentrischen Koordinaten eines Punktes oder Vektors im ππ-dimensionalen Raum bestehen
aus ππ + 1 reellen Zahlen. Die kartesischen Koordinaten bestehen dagegen nur aus ππ reellen Zahlen.
Letztere sind also theoretisch speichereffizienter. Andererseits reicht es aus, immer nur ππ
baryzentrische Koordinaten zu speichern. Da die Summe aller Koordinaten stets 1 ist, kann die nicht
gespeicherte Koordinate immer aus den gespeicherten ππ Koordinaten hergeleitet werden.
c) Für die Evaluierung sollte der Mauszeiger nacheinander auf die Punkte π΄π΄, π΅π΅ und πΆπΆ geschoben
werden. Die baryzentrischen Koordinaten des Punktes π΄π΄ sollten πππ΄π΄ = 1, πππ΅π΅ = 0 und πππΆπΆ = 0, die des
Punktes π΅π΅ sollten πππ΄π΄ = 0, πππ΅π΅ = 1 und πππΆπΆ = 0 und die des Punktes πΆπΆ sollten πππ΄π΄ = 0, πππ΅π΅ = 0 und
πππΆπΆ = 1 sein. Weiterhin sollten die baryzentrischen Koordinaten von Punkten innerhalb des Dreiecks
alle größer als 0 sein. Nur bei Punkten außerhalb des Dreiecks sollten einzelne Koordinaten negativ
sein. Bei Punkten auf dem Rand des Dreiecks, die keine Eckpunkte sind, ist stets eine Koordinate
gleich 0. Außerdem sollte die Summe der baryzentrischen Koordinaten in allen Fällen stets gleich 1
sein.
public struct Triangle2
{
// ...
/// <summary>
/// Berechnet die baryzentrischen Koordinaten eines
/// Punktes bezogen auf dieses Dreieck.
/// </summary>
/// <param name="P">
/// Der Punkt, dessen baryzentrische Koordinaten berechnet
/// werden sollen.
/// </param>
/// <returns>
/// Ein 3-Tupel mit den baryzentrischen Koordinaten von
/// <paramref name="P"/> bezogen auf dieses Dreieck.
/// </returns>
public Tuple3 GetBarycentricCoordinates(Point2 P)
{
// Anwendung der Cramerschen Regel.
// Determinante für die Nenner.
double detN = A.X * (B.Y - C.Y) + B.X * (C.Y - A.Y) + C.X * (A.Y - B.Y);
// Determinanten für die Zähler.
double detA = P.X * (B.Y - C.Y) + B.X * (C.Y - P.Y) + C.X * (P.Y - B.Y);
double detB = A.X * (P.Y - C.Y) + P.X * (C.Y - A.Y) + C.X * (A.Y - P.Y);
// Baryzentrische Koordinaten.
double l1 = detA / detN;
double l2 = detB / detN;
double l3 = 1.0 β l1 β l2;
}
}
// Tupel erzeugen und zurückgeben.
return new Tuple3(l1, l2, l3);
3 Punkttest für ebene Dreiecke
Der Punkttest gehört zu den wichtigsten Problemstellungen in der Computergeometrie. Dabei geht
es um die Frage, ob ein gegebener Punkt ππ auf einer Strecke, Kurve, Fläche oder in einem Dreieck,
Viereck, Fünfeck liegt oder zu einer wie auch immer beschaffenen Menge von Punkten gehört.
Für ein ebenes Dreieck π΄π΄π΄π΄π΄π΄ gibt es mehrere Möglichkeiten für den Punkttest. Eine Variante basiert
auf den Eigenschaften baryzentrischer Koordinaten. Dazu werden die baryzentrischen Koordinaten
des Punktes ππ bezüglich des Dreiecks π΄π΄π΄π΄π΄π΄ berechnet und geprüft, ob alle Koordinaten größer gleich
0 sind liegen. Wenn dem so ist, dann liegt der Punkt im Dreieck.
οΏ½οΏ½οΏ½οΏ½οΏ½β, ππππ
οΏ½οΏ½οΏ½οΏ½οΏ½β und β ππππ
οΏ½οΏ½οΏ½οΏ½οΏ½β , ππππ
οΏ½οΏ½οΏ½οΏ½οΏ½β.
οΏ½οΏ½οΏ½οΏ½οΏ½β , β ππππ
οΏ½οΏ½οΏ½οΏ½οΏ½β, ππππ
In einer anderen Variante berechnet man die Summe der Winkel β ππππ
Nur wenn diese Summe gleich 360° ist, liegt der Punkt ππ im Dreieck.
Aufgabe
a) Finden Sie heraus, welche der beiden genannten Varianten des Punkttests für ebene
Dreiecke effizienter ist. Gehen Sie dabei von den folgenden Annahmen aus. (3 Punkte)
β’ Der Vergleich zweier reeller Zahlen benötigt einen Rechentakt.
β’ Die Addition (bzw. Subtraktion) zweier reeller Zahlen benötigt ebenfalls einen
Rechentakt.
β’ Die Multiplikation (bzw. Division) zweier reeller Zahlen benötigt fünf Rechentakte.
β’ Alle sonstigen Funktionen (Quadratwurzel, Sinus, usw.) benötigen jeweils 20
Rechentakte.
b) Gegeben sei ein ebenes, überschneidungsfreies Viereck π΄π΄π΄π΄π΄π΄π΄π΄. Beschreiben Sie kurz einen
Algorithmus, der prüft, ob ein Punkt ππ in diesem Viereck liegt. (1 Punkt)
c) Implementieren Sie die Methode Triangle2.Contains().
Lösung
a) In der ersten Variante müssen β unter Anwendung der Cramerschen Regel β die baryzentrischen
Koordinaten wie folgt berechnet werden:
πππ₯π₯
det οΏ½πππ¦π¦
1
πππ΄π΄ =
π΄π΄π₯π₯
det οΏ½π΄π΄π¦π¦
1
π΄π΄π₯π₯
det οΏ½π΄π΄π¦π¦
1
πππ΅π΅ =
π΄π΄π₯π₯
det οΏ½π΄π΄π¦π¦
1
π΅π΅π₯π₯
π΅π΅π¦π¦
1
π΅π΅π₯π₯
π΅π΅π¦π¦
1
πππ₯π₯
πππ¦π¦
1
π΅π΅π₯π₯
π΅π΅π¦π¦
1
πΆπΆπ₯π₯
πΆπΆπ¦π¦ οΏ½
1
πΆπΆπ₯π₯
πΆπΆπ¦π¦ οΏ½
1
πΆπΆπ₯π₯
πΆπΆπ¦π¦ οΏ½
1
πΆπΆπ₯π₯
πΆπΆπ¦π¦ οΏ½
1
πππΆπΆ = 1 β πππ΄π΄ β πππ΅π΅
Es sind also zunächst drei verschiedene Determinanten von 3 × 3-Matrizen zu berechnen, deren
letzte Zeile nur aus Einsen besteht. Beispielhaft sei das im Folgenden für die Determinante
ausgeführt, die jeweils im Nenner steht.
π΄π΄π₯π₯
det οΏ½π΄π΄π¦π¦
1
π΅π΅π₯π₯
π΅π΅π¦π¦
1
πΆπΆπ₯π₯
πΆπΆπ¦π¦ οΏ½ = π΄π΄π₯π₯ β οΏ½π΅π΅π¦π¦ β πΆπΆπ¦π¦ οΏ½ + π΅π΅π₯π₯ β οΏ½πΆπΆπ¦π¦ β π΄π΄π¦π¦ οΏ½ + πΆπΆπ₯π₯ β οΏ½π΄π΄π¦π¦ β π΅π΅π¦π¦ οΏ½
1
Hier haben wir 3 Multiplikationen und 5 Additionen. Wir benötigen also pro Determinante 20
Rechentakte. Bei drei Determinanten macht das zusammen 60 Rechentakte. Für die Berechnung der
ersten zwei baryzentrischen Koordinaten sind außerdem noch zwei Divisionen nötig. Diese schlagen
mit weiteren 2 β 5 = 10 Rechentakten zu Buche, macht zusammen 70 Rechentakte. Die Berechnung
der dritten baryzentrischen Koordinate erfordert zwei Additionen, folglich zwei weitere Rechentakte.
Macht zusammen 72 Rechentakte. Für alle drei Koordinaten muss zum Schluss geprüft werden, ob
sie jeweils größer als 0 sind. Das sind zusätzlich 3 Vergleiche bzw. 3 Rechentakte. Für die erste
Variante des Punkttests sind also insgesamt 75 Rechentakte nötig.
οΏ½οΏ½οΏ½οΏ½οΏ½β, ππππ
οΏ½οΏ½οΏ½οΏ½οΏ½β berechnen. Das sind
οΏ½οΏ½οΏ½οΏ½οΏ½β und ππππ
Bei der zweiten Variante müssen wir zunächst die Vektoren ππππ
insgesamt 6 Additionen bzw. 6 Rechentakte. Anschließend berechnen wir die Längen der drei
Vektoren. Für jede Länge sind 2 Multiplikationen, eine Addition und eine Wurzel, also 31
Rechentakte nötig. Die Berechnung aller drei Längen erfordert also 93 Rechentakte. Danach
οΏ½ , ππππ
οΏ½ . Pro Vektor sind das 2
οΏ½ und ππππ
berechnen wir die Normierungen der Vektoren. Diese seien ππππ
Multiplikationen bzw. 10 Rechentakte. Die Normierung aller Vektoren erfordert also 30
Rechentakte.
Zusammengefasst benötigen wir bisher schon 129 Rechentakte für die Berechnung und
Normalisierung dreier Vektoren. Im nächsten Schritt müssen die drei Winkel berechnet werden. Für
jeden Winkel ist der Arkuskosinus aus dem Skalarprodukt zweier normierter Vektoren zu berechnen.
οΏ½ , ππππ
οΏ½ βͺοΏ½
πΎπΎ = acosοΏ½β©ππππ
Das sind zwei Multiplikationen (10 Rechentakte), eine Addition (1 Rechentakt) und ein Arkuskosinus
(20 Rechentakte) pro Winkel, zusammen also 31 Rechentakte pro Winkel und insgesamt 93
Rechentakte für drei Winkel. In der Zwischensumme liegen wir jetzt bei 222 Rechentakten. Die
Berechnung der Summe der Winkel erfordert zwei weitere Rechentakte und der Vergleich der
Summe mit dem Vollwinkel einen weiteren Rechentakt. Wir benötigen für die zweite Variante also
insgesamt 225 Rechentakte.
Zusammenfassend ist die erste Variante deutlich effizienter.
b) Die einfachste Möglichkeit ist die Zerlegung des Vierecks in zwei Dreiecke. Wenn der Punkt in
einem der beiden Dreieck liegt (oder auf dem Rand der gemeinsamen Seite beider Dreiecke), dann
liegt er auch im Viereck. Wir reduzieren also den Punkttest für ein Viereck auf zwei Punkttests für
Dreiecke.
c)
public struct Triangle2
{
// ...
/// <summary>
/// Prüft, ob dieses Dreieck einen bestimmten Punkt enthält.
/// </summary>
/// <param name="P">Der Punkt.</param>
/// <returns>
/// <see langword="true"/>, falls der Punkt <paramref name="P"/>
/// in diesem Dreieck liegt, sonst <see langword="false"/>.
/// </returns>
public bool Contains(Point2 P)
{
// baryzentrische Koordinaten berechnen.
Tuple3 Bary = GetBarycentricCoordinates(P);
//
if
if
if
}
}
Koordinaten müssen alle größer gleich 0 sein.
(Bary.A1 < 0) return false;
(Bary.A2 < 0) return false;
(Bary.A3 < 0) return false;
// Punkt liegt im Dreieck.
return true;
// ...
© Copyright 2025