Berechnen Sie den Schnittbereich zwischen einem Kreis und einem Dreieck?
Wie macht man berechne die Fläche der Schnittpunkt zwischen einem Dreieck (angegeben als drei (X,Y) - Paare) und ein Kreis (X,Y,R)? Ich habe getan, einige suchen ohne Erfolg. Dies ist für die Arbeit, nicht die Schule. 🙂
Sähe es so etwas in C#:
struct { PointF vert[3]; } Triangle;
struct { PointF center; float radius; } Circle;
//returns the area of intersection, e.g.:
//if the circle contains the triangle, return area of triangle
//if the triangle contains the circle, return area of circle
//if partial intersection, figure that out
//if no intersection, return 0
double AreaOfIntersection(Triangle t, Circle c)
{
...
}
InformationsquelleAutor der Frage Mark Maxham | 2009-02-12
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn Sie möchten, eine exakte Lösung (oder zumindest so genau, wie Sie erhalten können mit floating-point-Arithmetik) dann wird beinhalten eine Menge Lauferei, denn es gibt so viele Fälle zu betrachten.
Zähle ich neun verschiedene Fälle (kategorisiert in der folgenden Abbildung durch die Anzahl der Eckpunkte des Dreiecks in den Kreis, und die Anzahl der Kanten des Dreiecks, die sich schneiden oder die enthalten sind, in den Kreis):
(Allerdings ist diese Art der Aufzählung von geometrischen Fällen bekannte tückisch sein, und es würde mich nicht überraschen, überhaupt, wenn ich verpasst einen oder zwei!)
Also der Ansatz ist:
Bestimmen Sie für jeden Scheitelpunkt des Dreiecks, wenn es im inneren des Kreises. Ich nehme an, Sie wissen, wie zu tun.
Bestimmen für jede Kante des Dreiecks, wenn es schneidet den Kreis. (Schrieb ich eine Methode hier, oder zu sehen "computational geometry" - Buch.) Sie müssen berechnen, den Punkt oder die Schnittpunkte (falls vorhanden) für die Verwendung in Schritt 4.
Bestimmen, welche von den neun Fällen, die Sie haben.
Berechnen Sie die Fläche der Kreuzung. Die Fälle 1, 2 und 9 sind einfach. In den übrigen sechs Fällen habe ich gezeichnet mit gestrichelten Linien zu zeigen, wie man partition Bereich der Kreuzung in Dreiecke und kreisförmige Segmente auf der Grundlage der ursprünglichen Eckpunkte des Dreiecks, und an den Schnittpunkten der Sie berechnet in Schritt 2.
Dieser Algorithmus wird sehr empfindlich und anfällig für Fehler, betreffen nur einer der Fälle, so stellen Sie sicher, dass Sie Testfälle für alle neun Fällen (und ich schlage vor, permuting die Eckpunkte der test Dreiecke). Achten Sie insbesondere auf die Fälle, in denen einer der Eckpunkte des Dreiecks auf dem Rand des Kreises.
Wenn Sie nicht brauchen, eine exakte Lösung, dann Rastern Sie die zahlen und das zählen der Pixel in dem Schnittpunkt (wie vorgeschlagen von ein paar anderen Befragten) scheint wie ein viel einfacher Ansatz, um code, und sind entsprechend weniger anfällig für Fehler.
InformationsquelleAutor der Antwort Gareth Rees
Zuerst will ich uns daran erinnern, wie man die Fläche eines Polygons. Sobald wir dies getan haben, ist der Algorithmus zum finden der Schnittmenge zwischen einem polygon und einem Kreis sollte leicht zu verstehen.
Wie finden Sie die Fläche eines Polygons
Betrachten wir den Fall eines Dreiecks, da alle wesentlichen Logik erscheint es. Nehmen wir an wir haben ein Dreieck mit den Eckpunkten (x1,y1), (x2,y2), (x3,y3) wie gehen Sie um das Dreieck gegen den Uhrzeigersinn, wie in der folgenden Abbildung dargestellt:
Dann können Sie berechnen Sie die Fläche, die durch die Formel
A=(x1 y2 + x2 y3 + x3 y1 - x2y1 - x3 y2 - x1y3)/2.
Zu sehen, warum diese Formel funktioniert, lassen Sie uns zu verschieben, so ist es in der form
A=(x1 y2 - x2 y1)/2 + (x2 y3 - x3 y2)/2 + (x3 y1 - x1y3 )/2.
Nun der erste Begriff ist die folgende Fläche, die positiv in unserem Fall:
Wenn es ist nicht klar, dass die Gegend der grünen region ist in der Tat (x1 y2 - x2 y1)/2, dann Lesen Sie diese.
Der zweite Begriff ist das Gebiet, das ist wieder positiv:
Und der Dritte Bereich ist in der folgenden Abbildung dargestellt. Diese Zeit, die Fläche ist negativ
Hinzufügen dieser drei oben erhalten wir das folgende Bild
Sehen wir, dass der grüne Bereich wurde außerhalb des Dreiecks ist die Kündigung durch den roten Bereich, so dass die Netto-Fläche wird nur die Fläche eines Dreiecks, und dies zeigt, warum unsere Formel war in diesem Fall true.
Was ich oben sagte war die intuitive Erklärung, warum der Bereich Formel korrekt war. Eine genauere Erklärung wäre zu beachten, dass bei der Berechnung der Fläche von einer Kante, dem Gebiet, das wir bekommen, ist der gleiche Bereich, den wir erhalten würden, die sich aus der integration von r^2dθ/2, so haben wir effektiv die Integration von r^2dθ/2 um die Grenze des Polygons, und durch die stokes-theorem, das gibt das gleiche Ergebnis wie die Integration rdrdθ über die region begrenzt das polygon. Da die Integration rdrdθ über die region begrenzt durch die polygon gibt den Bereich, schließen wir, dass unser Verfahren müssen richtig geben der Gegend.
Bereich des Schnittpunktes eines Kreises mit einem polygon
Lassen Sie uns jetzt besprechen, wie es um den Bereich zu finden der den Schnittpunkt von einem Kreis mit radius R mit einem polygon, wie in der folgenden Abbildung:
Wir sind daran interessiert, finden Sie den Bereich der grünen region. Wir können, genau wie im Fall des einzigen polygon, brechen unsere Berechnung in der Suche nach einer Fläche für jede Seite des Polygons, und fügen Sie dann diese Bereiche.
Unsere erste Bereich wird wie folgt Aussehen:
Den zweiten Bereich Aussehen wird
Und der Dritte Bereich wird
Wieder, die ersten zwei Bereiche sind positiv, in unserem Fall, während die Dritte negativ sein wird. Hoffentlich werden die Stornierungen wird die Arbeit aus, so dass die Netto-Fläche ist in der Tat das Gebiet, in dem wir interessiert sind. Mal sehen.
In der Tat die Summe der Bereiche wird ein Bereich, den wir interessiert sind.
Wieder, die wir geben können, eine genauere Erklärung, warum das funktioniert. Lassen ich der region, definiert durch den Schnittpunkt und sei P das polygon. Dann aus der bisherigen Diskussion wissen wir, dass wir wollen, dass computer das integral von r^2dθ/2 entlang der Grenze des I. dies Jedoch schwer zu tun, weil es erfordert die Suche nach der Schnittmenge.
Stattdessen haben wir ein integral über das polygon. Wir integrierten max(r,R)^2 dθ/2 über die Grenze des Polygons. Um zu sehen, warum dies gibt die richtige Antwort, definieren wir eine Funktion π, die einen Punkt in Polarkoordinaten (r,θ) auf den Punkt (max(r,R),θ). Es sollte nicht verwirrend sein, zu finden, die die Koordinaten-Funktionen von π(r)=max(r,R) und π(θ)=θ. Dann, was wir Taten, war, sich zu integrieren π(r)^2 dθ/2 über die Grenze des Polygons.
Auf der anderen Seite, da π(θ)=θ, dies ist die gleiche wie die Integration von π(r)^2 dn(θ)/2 über die Grenze des Polygons.
Wird jetzt eine änderung der Variablen, finden wir, dass wir die gleiche Antwort erhalten, wenn wir integrierte r^2 dθ/2 über die Begrenzung von π(P), wobei π(P) ist das Bild von P unter π.
Mithilfe der Stokes-theorem noch einmal, wir wissen, dass die Integration von r^2 dθ/2 über die Begrenzung von π(P) gibt uns die Umgebung von π(P). In anderen Worten, es gibt die gleiche Antwort wie die Integration dxdy über π(P).
Durch eine änderung von Variablen wieder, die wir wissen, dass Integration dxdy über π(P) ist das gleiche wie Integration Jdxdy über P, wo J ist die Jacobi-π.
Nun wir teilen das integral der Jdxdy in zwei Bereiche: der Teil in der Kreis-und der Teil außerhalb des Kreises. Nun π lässt Punkte in den Kreis allein, so dass J=1 gibt, so dass der Beitrag von diesem Teil von P ist der Bereich, der Teil von P, der sich in den Kreis, d.h., der Bereich von der Kreuzung. Die zweite region ist die region außerhalb des Kreises. Es J=0, da π kollabiert dieses Teil nach unten, auf die Grenze des Kreises.
So, was wir berechnen, ist in der Tat der Bereich der Kreuzung.
Nun, wir sind relativ sicher, dass wir wissen, konzeptionell wie um den Bereich zu finden, sprechen wir genauer darüber, wie die Berechnung des Beitrags von einem einzigen segment. Lassen Sie uns beginnen, indem Sie sich ein segment in dem, was ich nennen das "standard-geometrie". Es ist unten dargestellt.
In standard-geometrie, die Kante geht horizontal von Links nach rechts. Es ist beschrieben durch drei zahlen: xi, x-Koordinate, wo der Rand beginnt, xf, x-Koordinate, wo der Rand endet, und y, der y-Koordinate der Kante.
Nun sehen wir, dass falls |y| < R, wie in der Abbildung, dann die Kante schneidet den Kreis in den Punkten (-xint,y) und (xint,y), wo xint = (R^2-y^2)^(1/2). Dann den Bereich, den wir brauchen, um zu berechnen, aufgeteilt in drei Stücke gekennzeichnet in der Abbildung. Um die Gebiete der Regionen 1 und 3, die wir verwenden können, arctan, um die Winkel der verschiedenen Punkte und dann gleichsetzen, der Bereich R^2 Δθ/2. So zum Beispiel würden wir θi = atan2(y,xi) und θl = atan2(y,-xint). Dann wird die Fläche der region ist R^2 (θl-θi)/2. Wir erhalten das Gebiet der region 3 ähnlich.
Bereich der region 2 ist die Fläche eines Dreiecks. Jedoch, wir müssen vorsichtig sein, über Zeichen. Wir wollen uns die Gegend gezeigt, positiv zu sein, so werden wir sagen, das Gebiet ist -(xint - (-xint))y/2.
Andere Sache im Auge zu behalten ist, dass, im Allgemeinen, xi-nicht weniger als-xint und xf nicht größer sein, als xint.
Den anderen Fall zu betrachten ist |y| > R. in Diesem Fall ist einfacher, denn es gibt nur ein Stück, das ähnlich wie in region 1 in der Abbildung.
Nun, dass wir wissen, wie zur Berechnung der Fläche von einer Kante in standard-geometrie, die einzige Sache Links zu tun ist, beschreiben Sie, wie Sie verwandeln jede Kante in standard-geometrie.
Aber dies nur eine einfache änderung der Koordinaten. Da einige mit den ersten Eckpunkt vi und final vertex vf, die neue x-TEN Einheitsvektor wird das Gerät zeigenden Vektor von vi zu vf. Dann ist xi ist nur die Verschiebung des vi aus der Mitte des Kreises, gepunktet in x-und xf ist nur xi plus die Distanz zwischen vi und vf. Unterdessen y ist gegeben durch das wedge-Produkt von x mit der Verschiebung von vi aus der Mitte des Kreises.
Code
Das vervollständigt die Beschreibung des Algorithmus, nun ist es Zeit, code zu schreiben. Ich verwende java.
First off, da wir mit Kreisen, wir sollten einen Kreis Klasse
Für Polygone, verwende ich java
Shape
Klasse.Shape
s haben einePathIterator
dass ich verwenden können, um zu Durchlaufen und die Kanten des Polygons.Nun für die eigentliche Arbeit. Ich werde trennen Sie die Logik des Durchlaufens der Kanten, setzen die Kanten in standard-geometrie etc, aus der Logik des computing der Bereich sobald dies geschehen ist. Der Grund dafür ist, dass Sie möglicherweise in der Zukunft berechnen möchten, etwas anderes neben oder zusätzlich zu Bereich und Sie wollen in der Lage sein, den code wiederverwenden zu müssen, befassen sich mit Durchlaufen der Kanten.
So habe ich eine generische Klasse, die berechnet werden, eine Eigenschaft der Klasse
T
über unsere polygon-Kreis-Schnittpunkt.public abstract class CircleShapeIntersectionFinder<T> {
Es hat drei statische Methoden, die nur helfen, berechnen geometrie:
Gibt es zwei Instanz-Felder, ein
Circle
die einfach immer eine Kopie der Kreis, und diecurrentSquareRadius
hält eine Kopie von dem Quadrat des radius. Das mag jetzt seltsam klingen, aber die Klasse die ich verwende, ist eigentlich ausgestattet, um die Bereiche der eine ganze Sammlung von Kreis-polygon-Schnittpunkte. Deshalb beziehe ich mich auf einen der Kreise, die als "aktuell".Weiter geht die Methode für die Berechnung, was wir ausrechnen wollen:
initialize()
undgetValue()
sind Abstrakt.initialize()
würde die variable setzen, die insgesamt die Fläche auf null, undgetValue()
würde nur wieder das Gebiet. Die definition fürprocessCircleShape
istWerfen wir einen zweiten Blick auf
initializeForNewCirclePrivate
schnell. Diese Methode stellt nur die Instanz-Felder und ermöglicht es der abgeleiteten Klasse speichern keine Eigenschaft des Kreises. Seine definition istinitializeForNewCircle
ist Abstrakt und eine Umsetzung wäre für Sie zum speichern der Kreise radius zu vermeiden Quadratwurzeln. Eh wiederprocessCircleShape
. Nach dem AufrufinitializeForNewCirclePrivate
überprüfen wir, ob das polygonnull
(was ich interpretieren als ein leeres polygon), und wir kehren zurück, wenn esnull
. In diesem Fall ist der berechnete Bereich wäre null. Wenn das polygon nichtnull
dann erhalten wir diePathIterator
des Polygons. Das argument dergetPathIterator
Methode, die ich nennen ist eine affine transformation, die angewendet werden können, um den Pfad. Ich will nicht zu bewerben, obwohl, so dass ich nur weitergebennull
.Nächstes erkläre ich den
double[]
s, die wird verfolgen die Eckpunkte. Ich muss daran denken, den ersten Eckpunkt, weil diePathIterator
nur gibt mir jede Kante einmal, also ich habe zurück zu gehen, nachdem es mir das Letzte Scheitelpunkt, und bilden eine Kante mit diesem letzten Eckpunkt und dem ersten.Den
currentSegment
Methode in der nächsten Zeile setzt den nächsten Eckpunkt in seiner Argumentation. Es gibt einen code, der Ihnen mitteilt, wenn es außerhalb der Scheitelpunkte. Dies ist der Grund, warum die Kontrolle Ausdruck für meine while-Schleife ist, was es ist.Meisten der rest der code dieser Methode ist uninteressant Logik bezogen auf das Durchlaufen der Eckpunkte. Das wichtigste ist, dass einmal pro iteration der while-Schleife rufe ich
processSegment
und dann rufe ichprocessSegment
wieder am Ende der Methode zur Verarbeitung des Kante verbindet, dass Sie den letzten Eckpunkt zu den ersten vertex.Schauen wir uns den code für
processSegment
:In dieser Methode implementiere ich die Schritte, die zur Transformation einer Kante in der standard-geometrie, wie oben beschrieben. Zuerst berechne ich
segmentDisplacement
die Verschiebung von der ersten Ecke der abschließenden vertex. Dies definiert die x-Achse in der standard-geometrie. Ich mache eine baldige Rückkehr, wenn diese Verschiebung ist null.Nächstes berechne ich die Länge der Verschiebung an, da diese notwendig ist, um den x-TEN Einheitsvektor. Sobald ich diese Informationen haben, berechne ich die Verschiebung aus der Mitte des Kreises, um den ersten Eckpunkt. Das Skalarprodukt dieser mit
segmentDisplacement
gibt mirleftX
die ich hatte, wurden rufe xi. DannrightX
, die ich hatte, wurden rufe xf, ist nurleftX + segmentLength
. Schließlich mache ich das wedge-Produkt zu bekommeny
wie oben beschrieben.Nun, dass ich umgewandelt haben, das problem in der standard-geometrie, wird es leicht sein, Angebot mit. Das ist das, was die
processSegmentStandardGeometry
Methode. Schauen wir uns den codeDen ersten
if
unterscheidet die Fälle, in deneny
ist klein genug, dass der Rand möglicherweise schneiden Sie den Kreis. Wenny
ist groß und es gibt keine Möglichkeit der Kreuzung, dann rufe ich die Methode zu behandeln, der Fall. Ansonsten habe ich den Fall behandeln, wo die Kreuzung ist möglich.Wenn Kreuzung ist möglich, ich berechne die x-Koordinate der Schnittpunkt
intersectionX
, und ich Teile die Kante in drei Teile, die den Regionen 1, 2 und 3 der standard-geometrie Abbildung oben. Ersten ich handle region 1.Verarbeiten region 1, ich überprüfen, ob
leftX
ist in der Tat weniger als-intersectionX
denn sonst würde es keine region 1. Wenn es eine region-1 -, dann muss ich wissen, Wann es endet. Es endet mit dem minimum vonrightX
und-intersectionX
. Nachdem ich diese gefunden haben x-Koordinaten, beschäftige ich mich mit diesem non-intersection region.Ich nicht eine ähnliche Sache zu behandeln, die region 3.
Für region 2, ich habe zu tun, etwas Logik, um zu überprüfen, dass
leftX
undrightX
wirklich Halterung einer region zwischen-intersectionX
undintersectionX
. Nach der Feststellung der region, ich brauche nur die Länge der region undy
, so dass ich übergeben Sie diese zwei zahlen auf einer abstrakten Methode, die Griffe der region 2.Nun schauen wir uns den code für
processNonIntersectingRegion
Ich einfach verwenden
atan2
zur Berechnung der Differenz im Winkel zwischenleftX
undrightX
. Dann ich fügen Sie code hinzu, den Umgang mit der Diskontinuität inatan2
, aber dies ist wahrscheinlich unnötig, weil die Diskontinuität tritt auf, entweder bei 180 Grad oder 0 Grad. Dann gebe ich den Unterschied im Winkel auf einer abstrakten Methode. Schließlich, wir haben nur abstrakte Methoden und Getter:Schauen wir uns jetzt an die Verlängerung der Klasse
CircleAreaFinder
}
Es hat ein Feld
area
zu verfolgen, das Gebiet.initialize
sets-Bereich auf null, wie erwartet. Wenn wir eine nicht schneidende Kante, erhöhen wir den Bereich von R^2 Δθ/2 als wir zu dem Schluss wir sollten oben. Für eine schneidende Kante, wir Dekrementieren der Gegend vony*length/2
. Das war so, dass negative Werte füry
entsprechen positiven Bereiche, als wir beschlossen Sie sollte.Nun ist die saubere Sache ist, wenn wir wollen, zu verfolgen, den Umfang, die wir nicht zu tun haben, dass viel mehr Arbeit. Für mich ein
AreaPerimeter
Klasse:und jetzt brauchen wir nur noch verlängern unsere abstrakte Klasse wieder mit
AreaPerimeter
als der Typ.Haben wir eine variable
perimeter
zu verfolgen, den Umfang, wir erinnern uns an den Wert derradius
zu vermeiden, rufen SieMath.sqrt
eine Menge, und wir delegieren die Berechnung der Fläche, um unsereCircleAreaFinder
. Wir können sehen, dass die Formeln für den Umfang sind einfach.Referenz hier ist der vollständige code der
CircleShapeIntersectionFinder
Sowieso, das ist meine Beschreibung des Algorithmus. Ich denke, es ist schön, weil es genau ist und es sind nicht wirklich viele Fälle zu prüfen.
InformationsquelleAutor der Antwort Brian Moths
Ich bin fast ein Jahr und eine Hälfte spät, aber ich dachte, vielleicht sind die Leute interessiert code hier, dass ich schrieb was ich denke, tut dies richtig. Suchen in-Funktion IntersectionArea in der Nähe der Unterseite. Der Allgemeine Ansatz ist zu wählen aus der konvex-polygon umschrieben, die durch den Kreis, und dann deal mit dem kleinen kreisförmigen caps.
InformationsquelleAutor der Antwort Victor Liu
Vorausgesetzt, Sie reden integer-Pixel, die nicht real, die naive Implementierung würde, um eine Schleife durch jedes pixel des Dreiecks und prüfen Sie den Abstand von der Mitte des Kreises gegen seinen radius.
Ist es nicht eine nette Formel, oder besonders schnell, aber es tut den job zu erledigen.
InformationsquelleAutor der Antwort lc.
versuchen computational geometry
Hinweis: dies ist kein triviales problem, ich hoffe, es ist keine Hausaufgabe 😉
InformationsquelleAutor der Antwort Steven A. Lowe
Wenn Sie eine GPU zur Verfügung, die Sie nutzen könnten diese Technik für den Erhalt einer Pixelzahl von der Kreuzung..
InformationsquelleAutor der Antwort codelogic
Ich denke, Sie sollten nicht annähernd Kreis als einen Satz von Dreiecken, anstatt dass Sie annähernd seine Form mit einem polygon.
Der naive Algorithmus kann wie folgt Aussehen:
Können Sie zur Optimierung dieses Algorithmus durch die Kombination von Schritt 2 und Schritt 3, in einer einzigen Funktion.
Lesen dieses links:
Bereich der konvexen polygon
Schnittmenge von konvexen Polygonen
InformationsquelleAutor der Antwort okutane
Da Ihre Formen, die konvex sind, können Sie mithilfe der Monte-Carlo-area-Schätzung.
Zeichnen Sie ein Rechteck um den Kreis und das Dreieck.
Wählen Sie zufällige Punkte in der box und halten Sie zählen, wie viele fallen in den Kreis, und wie viele fallen in den Kreis und das Dreieck.
Bereich der Kreuzung ≅ Gebiet von Kreis * # Punkte im Kreis und im Dreieck /# Punkte im Kreis
Stoppen der Auswahl Punkten, wenn die geschätzte Fläche ändert sich nicht durch mehr als einen bestimmten Betrag über eine bestimmte Anzahl von Runden, oder wählen Sie einfach eine Feste Anzahl von Punkten auf die Fläche der box. Der Bereich schätzen sollten konvergieren Recht schnell, es sei denn, eine Ihrer Formen, hat sehr wenig Fläche.
Hinweis: Hier ist, wie Sie bestimmen, ob ein Punkt in einem Dreieck: Barycentric coordinates
InformationsquelleAutor der Antwort Imran
Wie genau müssen Sie sein? Wenn Sie die Annäherung an den Kreis mit einfacher Formen können Sie vereinfachen das problem. Es wäre nicht schwer zu modellieren, ein Kreis als eine Menge von sehr schmalen Dreiecken, treffen in der Mitte, zum Beispiel.
InformationsquelleAutor der Antwort Mark Ransom
Wenn nur eine der Dreiecks-Linie Segmente schneidet der Kreis, die rein mathematische Lösung ist nicht allzu schwer. Sobald Sie wissen, Wann die beiden Schnittpunkte sind, können Sie den Abstand Formel zu finden, die Sehnenlänge.
Laut diese Gleichungen:
wobei c die Sehnenlänge, r der radius, ϑ wird der Winkel durch die Mitte, und A ist die Fläche. Beachten Sie, dass diese Lösung bricht, wenn mehr als die Hälfte der Kreis abgeschnitten wird.
Ist es wahrscheinlich nicht der Mühe Wert, wenn Sie nur eine Annäherung, denn es macht einige Annahmen über das, was die eigentliche Kreuzung aussieht.
InformationsquelleAutor der Antwort Nikhil Chelliah
Mein Erster Instinkt würde sein, die alles verwandelt, so dass der Kreis zentriert am Ursprung, trans das Dreieck zu polaren Koordinaten und lösen nach der Kreuzung (oder encompassment) der das Dreieck mit dem Kreis. Ich habe noch nicht wirklich gearbeitet, es durch auf dem Papier noch, aber so ist es nur eine Vermutung.
InformationsquelleAutor der Antwort Crashworks