Ich habe einen Code geschrieben, der den Schnittpunkt zweier Liniensegmente in der Ebene testet. Ich werde dich nicht mit allen Details belästigen.Probleme mit der arithmetischen Genauigkeit beim Testen auf den Schnittpunkt zweier Liniensegmente
Der Code benötigt zwei Liniensegmente, die jeweils durch zwei Endpunkte beschrieben werden, und passt dann jedes Segment an eine Linie an, indem a
und b
in y = a*x + b
angepasst werden. Dann findet es den Schnittpunkt der beiden Linien durch x = (b2 - b1)/(a2 - a1)
. Zuletzt testet es, ob der Schnittpunkt x
in den beiden Liniensegmenten enthalten ist.
Der relevante Teil sieht wie folgt aus:
# line parameterization by a = Delta y/Delta x, b = y - a*x
a1 = (line1.edge2.y - line1.edge1.y)/(line1.edge2.x - line1.edge1.x)
b1 = line1.edge1.y - a1 * line1.edge1.x
a2 = (line2.edge2.y - line2.edge1.y)/(line2.edge2.x - line2.edge1.x)
b2 = line2.edge1.y - a2 * line2.edge1.x
# The intersection's x
x = - (b2 - b1)/(a2 - a1)
# If the intersection x is within the interval of each segment
# then there is an intersection
if (isininterval(x, line1.edge1.x, line1.edge2.x) and
isininterval(x, line2.edge1.x, line2.edge2.x)):
return True
else:
return False
Der Kürze halber ich eine Menge Tests fallen gelassen besonderen Fällen wie Handhabung, wenn die Kanten sind parallel zueinander (a1==a2
), wenn sie auf der gleichen Linie sind, wenn eine Kante mit der Länge 0 ist, wenn die Kante entlang der vertikalen Achse (a
dann unendlich wird) usw.
die Funktion ist einfach isininterval
def isininterval(x0, x1, x2):
"""Tests if x0 is in the interval x1 to x2"""
if x1 <= x0 <= x2 or x2 <= x0 <= x1:
return True
else:
return False
Nun die Frage: Ich finde, dass der Test aufgrund von Rundungsfehlern zu falschen Ergebnissen führt, wenn der Schnittpunkt mit der Segmentkante übereinstimmt.
Zum Beispiel, mit line1 zwischen (0,0) und (3,5) und line2 zwischen (3,5) und (7,1) der resultierende Schnittpunkt x ist 2.9999999999999996
, die die falsche Antwort gibt. Sollte gewesen sein 3.
Können Sie bitte eine Lösung vorschlagen?
Verwenden Sie die Dezimalklasse: 'von Dezimalimport Dezimal '. http://stackoverflow.com/questions/2986150/python-floating-number. Auch Ihre "isininterval" -Funktion könnte einfach zurückgeben: 'return x1 <= x0 <= x2 oder x2 <= x0 <= x1' – Bahrom
Die Standardmethode zum Schreiben boolescher Bedingungen mit Fließkommazahlen besteht darin, eine Fehlertoleranz in die Bedingung aufzunehmen. Zum Beispiel, ersetze 'x1 <= x0 <= x1' durch' x1 - eps <= x0 <= x2 + eps' wo 'eps' etwas wie 0.000001 ist –
An erster Stelle, haben Sie einen guten Grund, sich über 2.9999999999999996 Sorgen zu machen nicht 3 sein? –