Как узнать, принадлежит ли точка определенной линии?
Примеры приветствуются, если это возможно.
Как узнать, принадлежит ли точка определенной линии?
Примеры приветствуются, если это возможно.
В простейшей форме просто подставьте координаты в уравнение линии и проверьте на равенство.
Данный:
Point p (X=4, Y=5)
Line l (Slope=1, YIntersect=1)
Подставьте X и Y:
Y = Slope * X + YIntersect
=> 5 = 1 * 4 + 1
=> 5 = 5
Так что да, дело в линии.
Если ваши линии представлены в форме (X1, Y1), (X2, Y2), вы можете рассчитать наклон с помощью:
Slope = (y1 - y2) / (x1-x2)
А затем получите Y-Intersect следующим образом:
YIntersect = - Slope * X1 + Y1;
Изменить: я исправил Y-пересечение (которое было X1/Y1...)
Вам нужно будет проверить, что x1 - x2
не является 0
. Если это так, то проверка того, находится ли точка на линии, — это простая проверка того, равно ли значение Y в вашей точке x1
или x2
. Кроме того, убедитесь, что X точки не равен «x1» или «x2».
Math.Atan2
как начальной, так и конечной точек сегмента с точкой объекта. Смотрите мой ответ ниже для примера. Не беспокойтесь о горизонтальных или вертикальных проблемах или насколько близко к нулю перед нулевым , который дает метод slope-intercept
.
- person IAbstract; 02.04.2016
Я только что написал функцию, которая обрабатывает несколько дополнительных требований, поскольку я использую эту проверку в приложении для рисования:
private const double SELECTION_FUZZINESS = 3;
internal override bool ContainsPoint(Point point)
{
LineGeometry lineGeo = geometry as LineGeometry;
Point leftPoint;
Point rightPoint;
// Normalize start/end to left right to make the offset calc simpler.
if (lineGeo.StartPoint.X <= lineGeo.EndPoint.X)
{
leftPoint = lineGeo.StartPoint;
rightPoint = lineGeo.EndPoint;
}
else
{
leftPoint = lineGeo.EndPoint;
rightPoint = lineGeo.StartPoint;
}
// If point is out of bounds, no need to do further checks.
if (point.X + SELECTION_FUZZINESS < leftPoint.X || rightPoint.X < point.X - SELECTION_FUZZINESS)
return false;
else if (point.Y + SELECTION_FUZZINESS < Math.Min(leftPoint.Y, rightPoint.Y) || Math.Max(leftPoint.Y, rightPoint.Y) < point.Y - SELECTION_FUZZINESS)
return false;
double deltaX = rightPoint.X - leftPoint.X;
double deltaY = rightPoint.Y - leftPoint.Y;
// If the line is straight, the earlier boundary check is enough to determine that the point is on the line.
// Also prevents division by zero exceptions.
if (deltaX == 0 || deltaY == 0)
return true;
double slope = deltaY / deltaX;
double offset = leftPoint.Y - leftPoint.X * slope;
double calculatedY = point.X * slope + offset;
// Check calculated Y matches the points Y coord with some easing.
bool lineContains = point.Y - SELECTION_FUZZINESS <= calculatedY && calculatedY <= point.Y + SELECTION_FUZZINESS;
return lineContains;
}
Лучший способ определить, лежит ли точка R = (rx, ry) на прямой, соединяющей точки P = (px, py) и Q = (qx, qy), — это проверить, соответствует ли определитель матрицы
{{qx - px, qy - py}, {rx - px, ry - py}},
а именно (qx - px) * (ry - py) - (qy - py) * (rx - px) близко к 0. Это решение имеет несколько связанных преимуществ по сравнению с другими опубликованными: во-первых, оно не требует специального случая для вертикальных линий , во-вторых, он не делится (обычно медленная операция), в-третьих, он не вызывает плохого поведения с плавающей запятой, когда линия почти, но не совсем вертикальна.
(0,0)
до (10,10)
может быть описана уравнением y = x
, и все точки, которые решают это уравнение, лежат на линии. (5.1, 5.1)
решает уравнение и, таким образом, лежит на прямой.
- person Tomas Aschan; 13.05.2014
Даны две точки на линии L0
и L1
и точка для проверки P
.
(L1 - L0) * (P - L0)
n = (P - L0) - --------------------- (L1 - L0)
(L1 - L0) * (L1 - L0)
Нормой вектора n
является расстояние точки P
от прямой, проходящей через L0
и L1
. Если это расстояние равно нулю или достаточно мало (в случае ошибок округления), точка лежит на прямой.
Символ *
представляет скалярное произведение.
Пример
P = (5, 5)
L0 = (0, 10)
L1 = (20, -10)
L1 - L0 = (20, -20)
P - L0 = (5, -5)
(20, -20) * (5, -5)
n = (5, -5) - --------------------- (20, -20)
(20, -20) * (20, -20)
200
= (5, -5) - --- (20, -20)
800
= (5, -5) - (5, -5)
= (0, 0)
n = (p - L0) - (p - L0)
и в каждом случае вы всегда будете получать n = (0, 0)
.
- person nenito; 07.01.2012
Я думаю, что г-н Патрик Макдональд дал почти правильный ответ, и это исправление его ответа:
public bool IsOnLine(Point endPoint1, Point endPoint2, Point checkPoint)
{
return (((double)checkPoint.Y - endPoint1.Y)) / ((double)(checkPoint.X - endPoint1.X))
== ((double)(endPoint2.Y - endPoint1.Y)) / ((double)(endPoint2.X - endPoint1.X));
}
и, конечно, есть много других правильных ответов, особенно мистер Джош, но я нашел, что это лучший.
Спасибо за всех.
y = m * x + c
Это уравнение прямой. x & y - координаты. Каждая линия характеризуется своим наклоном (m) и точкой пересечения с осью y (c).
Таким образом, учитывая m и c для линии, вы можете определить, находится ли точка (x1, y1) на линии, проверив, выполняется ли уравнение для x = x1 и y = y1
Двумерная линия обычно представляется с помощью уравнения с двумя переменными x и y, здесь хорошо известное уравнение
Теперь представьте, что ваша линия GDI+ нарисована от (0,0) до (100, 100), тогда значение m=(0-100)/(0-100) = 1, таким образом, уравнение для вашей линии y-0=1 *(х-0) => у=х
Теперь, когда у нас есть уравнение для рассматриваемой линии, легко проверить, принадлежит ли точка этой линии. Данная точка (x3, y3) принадлежит этой прямой, если она удовлетворяет уравнению прямой при подстановке x=x3 и y=y3. Например, точка (10, 10) принадлежит этой прямой, поскольку 10=10, но (10,12) не принадлежит этой прямой, поскольку 12 != 10.
ПРИМЕЧАНИЕ. Для вертикальной линии значение уклона (м) бесконечно, но в этом особом случае вы можете использовать уравнение для вертикальной линии непосредственно x=c, где c = x1 = x2.
Хотя я должен сказать, что не уверен, что это самый эффективный способ сделать это. Я постараюсь найти более эффективный способ, когда у меня будет больше времени.
Надеюсь это поможет.
Если у вас есть линия, определяемая ее конечными точками
PointF pt1, pt2;
и у вас есть пункт, который вы хотите проверить
PointF checkPoint;
то вы можете определить функцию следующим образом:
bool IsOnLine(PointF endPoint1, PointF endPoint2, PointF checkPoint)
{
return (checkPoint.Y - endPoint1.Y) / (endPoint2.Y - endPoint1.Y)
== (checkPoint.X - endPoint1.X) / (endPoint2.X - endPoint1.X);
}
и назовите его следующим образом:
if (IsOnLine(pt1, pt2, checkPoint) {
// Is on line
}
Однако вам нужно будет проверить деление на ноль.
Уравнение линии:
y = mx + c
Таким образом, точка (a, b) находится на этой линии, если она удовлетворяет этому уравнению, т.е. b = ma + c
Не могли бы вы быть более конкретным?
О каком языке программирования вы говорите?
О каком окружении вы говорите?
О каких "линиях" вы говорите? Текст? Какая точка? XY на экране?
В качестве альтернативы методу slope/y-intercept
я выбрал такой подход с использованием Math.Atan2
:
// as an extension method
public static bool Intersects(this Vector2 v, LineSegment s) {
// check from line segment start perspective
var reference = Math.Atan2(s.Start.Y - s.End.Y, s.Start.X - s.End.X);
var aTanTest = Math.Atan2(s.Start.Y - v.Y, s.Start.X - v.X);
// check from line segment end perspective
if (reference == aTanTest) {
reference = Math.Atan2(s.End.Y - s.Start.Y, s.End.X - s.Start.X);
aTanTest = Math.Atan2(s.End.Y - v.Y, s.End.X - v.X);
}
return reference == aTanTest;
}
Первая проверка reference
определяет arcTan от начальной точки отрезка до его конечной точки. Затем с точки зрения начальной точки мы определяем arcTan для вектора v
.
Если эти значения равны, мы проверяем с точки зрения конечной точки.
Простой и обрабатывает горизонтальные, вертикальные и все остальное между ними.