Es sieht so aus, als hätten fast alle anderen auf StackOverflow eine Antwort abgegeben (bisher 23 Antworten), also hier ist mein Beitrag für C#. Dies basiert größtenteils auf der Antwort von M. Katz, die wiederum auf der Antwort von Grumdrig basiert.
public struct MyVector
{
private readonly double _x, _y;
// Konstruktor
public MyVector(double x, double y)
{
_x = x;
_y = y;
}
// Entfernung von diesem Punkt zu einem anderen Punkt, quadriert
private double DistanceSquared(MyVector otherPoint)
{
double dx = otherPoint._x - this._x;
double dy = otherPoint._y - this._y;
return dx * dx + dy * dy;
}
// Finde die Entfernung von diesem Punkt zu einem Linienabschnitt (der nicht dasselbe ist wie von diesem
// Punkt zu irgendwo auf einer unendlichen Linie). Gibt auch den nächsten Punkt zurück.
public double DistanceToLineSegment(MyVector lineSegmentPoint1, MyVector lineSegmentPoint2,
out MyVector closestPoint)
{
return Math.Sqrt(DistanceToLineSegmentSquared(lineSegmentPoint1, lineSegmentPoint2,
out closestPoint));
}
// Das gleiche wie oben, aber vermeiden Sie die Verwendung von Sqrt(), spart ein paar Nanosekunden in Fällen, in denen Sie nur mehrere Entfernungen vergleichen möchten, um die kleinste oder größte zu finden, aber die Entfernung nicht benötigen
public double DistanceToLineSegmentSquared(MyVector lineSegmentPoint1,
MyVector lineSegmentPoint2, out MyVector closestPoint)
{
// Länge des Linienabschnitts berechnen (quadriert) und den besonderen Fall von koinzidenten Punkten behandeln
double segmentLengthSquared = lineSegmentPoint1.DistanceSquared(lineSegmentPoint2);
if (segmentLengthSquared < 1E-7f) // Beliebter "gut genug für Regierungsarbeit" Wert
{
closestPoint = lineSegmentPoint1;
return this.DistanceSquared(closestPoint);
}
// Verwenden Sie die magische Formel, um die "Projektion" dieses Punktes auf die unendliche Linie zu berechnen
MyVector lineSegment = lineSegmentPoint2 - lineSegmentPoint1;
double t = (this - lineSegmentPoint1).DotProduct(lineSegment) / segmentLengthSquared;
// Behandeln Sie die beiden Fälle, in denen die Projektion nicht auf dem Linienabschnitt liegt, und den Fall, in dem
// die Projektion auf dem Segment liegt
if (t <= 0)
closestPoint = lineSegmentPoint1;
else if (t >= 1)
closestPoint = lineSegmentPoint2;
else
closestPoint = lineSegmentPoint1 + (lineSegment * t);
return this.DistanceSquared(closestPoint);
}
public double DotProduct(MyVector otherVector)
{
return this._x * otherVector._x + this._y * otherVector._y;
}
public static MyVector operator +(MyVector leftVector, MyVector rightVector)
{
return new MyVector(leftVector._x + rightVector._x, leftVector._y + rightVector._y);
}
public static MyVector operator -(MyVector leftVector, MyVector rightVector)
{
return new MyVector(leftVector._x - rightVector._x, leftVector._y - rightVector._y);
}
public static MyVector operator *(MyVector aVector, double aScalar)
{
return new MyVector(aVector._x * aScalar, aVector._y * aScalar);
}
// Hinzugefügt mit ReSharper aufgrund von CodeAnalysis-Mahnungen
public bool Equals(MyVector other)
{
return _x.Equals(other._x) && _y.Equals(other._y);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is MyVector && Equals((MyVector) obj);
}
public override int GetHashCode()
{
unchecked
{
return (_x.GetHashCode()*397) ^ _y.GetHashCode();
}
}
public static bool operator ==(MyVector left, MyVector right)
{
return left.Equals(right);
}
public static bool operator !=(MyVector left, MyVector right)
{
return !left.Equals(right);
}
}
Und hier ist ein kleines Testprogramm.
public static class JustTesting
{
public static void Main()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 10000000; i++)
{
TestIt(1, 0, 0, 0, 1, 1, 0.70710678118654757);
TestIt(5, 4, 0, 0, 20, 10, 1.3416407864998738);
TestIt(30, 15, 0, 0, 20, 10, 11.180339887498949);
TestIt(-30, 15, 0, 0, 20, 10, 33.541019662496844);
TestIt(5, 1, 0, 0, 10, 0, 1.0);
TestIt(1, 5, 0, 0, 0, 10, 1.0);
}
stopwatch.Stop();
TimeSpan timeSpan = stopwatch.Elapsed;
}
private static void TestIt(float aPointX, float aPointY,
float lineSegmentPoint1X, float lineSegmentPoint1Y,
float lineSegmentPoint2X, float lineSegmentPoint2Y,
double expectedAnswer)
{
// Katz
double d1 = DistanceFromPointToLineSegment(new MyVector(aPointX, aPointY),
new MyVector(lineSegmentPoint1X, lineSegmentPoint1Y),
new MyVector(lineSegmentPoint2X, lineSegmentPoint2Y));
Debug.Assert(d1 == expectedAnswer);
/*
// Katz using squared distance
double d2 = DistanceFromPointToLineSegmentSquared(new MyVector(aPointX, aPointY),
new MyVector(lineSegmentPoint1X, lineSegmentPoint1Y),
new MyVector(lineSegmentPoint2X, lineSegmentPoint2Y));
Debug.Assert(Math.Abs(d2 - expectedAnswer * expectedAnswer) < 1E-7f);
*/
/*
// Matti (optimiert)
double d3 = FloatVector.DistanceToLineSegment(new PointF(aPointX, aPointY),
new PointF(lineSegmentPoint1X, lineSegmentPoint1Y),
new PointF(lineSegmentPoint2X, lineSegmentPoint2Y));
Debug.Assert(Math.Abs(d3 - expectedAnswer) < 1E-7f);
*/
}
private static double DistanceFromPointToLineSegment(MyVector aPoint,
MyVector lineSegmentPoint1, MyVector lineSegmentPoint2)
{
MyVector closestPoint; // Nicht verwendet
return aPoint.DistanceToLineSegment(lineSegmentPoint1, lineSegmentPoint2,
out closestPoint);
}
private static double DistanceFromPointToLineSegmentSquared(MyVector aPoint,
MyVector lineSegmentPoint1, MyVector lineSegmentPoint2)
{
MyVector closestPoint; // Nicht verwendet
return aPoint.DistanceToLineSegmentSquared(lineSegmentPoint1, lineSegmentPoint2,
out closestPoint);
}
}
Wie Sie sehen können, habe ich versucht, den Unterschied zwischen der Verwendung der Version, die die Methode Sqrt() vermeidet und der normalen Version zu messen. Meine Tests zeigen, dass Sie vielleicht etwa 2,5% sparen können, aber ich bin mir nicht einmal sicher darüber - die Variationen innerhalb der verschiedenen Testläufe waren in derselben Größenordnung. Ich habe auch versucht, die Version zu messen, die von Matti veröffentlicht wurde (plus einer offensichtlichen Optimierung), und diese Version scheint etwa 4% langsamer zu sein als die Version, die auf dem Katz/Grumdrig-Code basiert.
Bearbeitet: Übrigens habe ich auch versucht, eine Methode zu messen, die die Entfernung zu einer unendlichen Linie (nicht zu einem Linienabschnitt) mit einem Kreuzprodukt (und einem Sqrt()) findet, und sie ist etwa 32% schneller.
0 Stimmen
Ich weiß nicht, wie du Linien und Punkte darstellst, aber hier findest du die gesamte Mathematik, die du benötigst, um anzufangen. Es sollte nicht allzu schwer sein, herauszufinden, was du tun musst.
0 Stimmen
Kann die Antwort auf diese Frage behoben/geändert werden? Derzeit bezieht sie sich nicht auf die Frage (den Abschnitt), sondern auf eine Zeile.
4 Stimmen
@ArthurKalliokoski: Dieser Link ist tot, aber ich habe eine Kopie gefunden: paulbourke.net/geometry/pointline
0 Stimmen
Muss das selbst suchen und bin zufällig auf dies von Google gestoßen - wenn jemand nach einer Implementierung sucht und mit Python gehen kann, hat Shapely dies. Du suchst nach der
LineString
Klasse für den Pfad.12 Stimmen
@GuntherStruyf: Dieser Link ist auch tot, aber dieser ähnliche Link funktioniert: paulbourke.net/geometry/pointlineplane
1 Stimmen
Wenn jemand nach dem Abstand zwischen einem Punkt und einer Linie sucht, nicht zwischen einem Punkt und einem Liniensegment, sehen Sie sich diesen Link an: gist.github.com/rhyolight/2846020
1 Stimmen
Der obige Link ist tot. Hier ist Pseudocode und ein C++ Beispiel, erklärt und so ausführlich wie in einem Lehrbuch abgeleitet, geomalgorithms.com/a02-_lines.html
0 Stimmen
brilliant.org/wiki/…