2009-05-25 2 views
18

Как определить, принадлежит ли точка определенной строке?Как определить, принадлежит ли точка определенной строке?

При необходимости оцениваются примеры.

+0

Пожалуйста, будьте более конкретными. С какой информацией вы должны начать? У вас есть упорядоченная пара точки и уравнение? –

ответ

28

В простейшей форме , просто вставьте координаты в линейное уравнение и проверьте равенство.

Дано:

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; 

Edit: я установил Y-Intersect (которая была X1/Y1 ...)

Вы должны проверить, что x1 - x2 не 0. Если это так, то проверка того, находится ли точка на линии, является простым вопросом проверки того, равна ли значение Y в вашей точке x1 или x2. Кроме того, убедитесь, что X точки не является «x1» или «x2».

+0

В чем языковая библиотека? –

+2

Это не так - это просто псевдокод. – Eclipse

+23

Это даже не псевдокод - это просто математика. – configurator

0

Не могли бы вы уточнить?

О каком языке программирования вы говорите?

В какой среде вы говорите?

Какие «линии» вы говорите? Текст? Какой смысл? XY на экране?

+1

Извините, мне следовало прокомментировать исходный вопрос – joshcomley

+5

Вы по-прежнему можете удалить свое сообщение и оставить комментарий:) –

4
y = m * x + c 

Это уравнение линии. x & y - координаты. Каждая линия характеризуется ее наклоном (m) и где она пересекает ось y (c).

Поэтому, учитывая м & с для линии, можно определить, если точка (x1, y1) находится на линии, проверяя, если уравнение имеет место при х = х1 и у = y1

+0

За исключением того, что это уравнение не может описать вертикальную линию, и за исключением того, что вы не указали на возможность линия имеет отличную от нуля толщину. – ChrisW

+4

Линия не имеет толщины. –

+1

«Линия не имеет толщины» - она ​​делает, когда она нарисована на экране (т. Е. Когда это вопрос программирования): его толщина - по крайней мере один пиксель и может быть больше. – ChrisW

1

Уравнение линии:

y = mx + c 

Таким образом, точка (а, б) на этой линии, если она удовлетворяет этому уравнению, т.е.b = ma + c

2

2D-линии, как правило, представлено с помощью уравнения в двух переменных х и у здесь хорошо известное уравнение

y-y1 = (y1-y2)/(x1-x2) (x-x1)

Теперь представьте ваш GDI + линия рисуется от (0,0) до (100, 100), то значение m = (0-100)/(0-100) = 1, таким образом, уравнение для вашей линии равно y-0 = 1 * (x-0) => y = x

Теперь, когда у нас есть уравнение для рассматриваемой линии, его легко проверить, принадлежит ли точка этой строке. Данная точка (x3, y3) принадлежит этой строке, если она удовлетворяет линейному уравнению при подстановке x = x3 и y = y3. Например, точка (10, 10) принадлежит этой линии, так как 10 = 10, но (10,12) не принадлежит этой линии, так как 12! = 10.

ПРИМЕЧАНИЕ. Для вертикальной линии значение наклона (m) бесконечна, но для этого частного случая вы можете использовать уравнение для вертикальной прямой непосредственно x = c, где c = x1 = x2.

Хотя я должен сказать, что не уверен, что это самый эффективный способ сделать это. Я постараюсь найти более эффективный способ, когда у меня будет больше времени.

Надеюсь, это поможет.

3

Если у вас есть линия, определенный своими концами

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 
} 

Вам нужно будет проверить деление на ноль.

+0

Спасибо, очень очень. –

+3

Это не может быть правильно ... Поскольку координаты точек являются ints, у вас будет (критическая) потеря percision, когда контрольная точка будет близка к endPoint1 и далека от endPoint2. Возможно, если бы вы изменили ее на десятичную или двойную, это сработало бы хорошо для обеих сторон, но я все равно не буду доверять точности этого уклона. – configurator

+0

Fair Point (каламбур), изменил их на PointF –

5

Учитывая две точки на линии 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) 
+3

+1 для обозначения ошибок округления. Использование точного равенства в арифметике с плавающей запятой приведет к тому, что другие предлагаемые решения не удастся во многих случаях. Я не уверен в численной надежности предлагаемого алгоритма, но численная надежность достаточно сложна, что, если точность важна, то целесообразно рассмотреть научную литературу по этой теме. Или, по крайней мере, использовать библиотеку, где, вероятно, автор сделал исследование. –

+0

Я не думаю, что ваш пример верен, потому что после некоторых преобразований «n = (p - L0) - (p - L0)» и в каждом случае у вас всегда будет «n = (0, 0)», , – nenito

18

Лучший способ, чтобы определить, если точка Р = (Rx, Ry) лежит на линии, соединяющей точки Р = (рх, ру) и Q = (QX, QY) чтобы проверить, является ли определитель матрицы

{{qx - px, qy - py}, {rx - px, ry - py}}, 

а именно (QU - ПВ) близок к 0 - (рх гха) * (гу - р) - - (QY р) *.Это решение имеет ряд преимуществ по сравнению с остальными: во-первых, для вертикальных линий не требуется специальный случай, во-вторых, он не делит (как правило, медленную операцию), в-третьих, он не вызывает плохое поведение с плавающей запятой, когда линия почти, но не совсем вертикальная.

+0

Для линии от 0,0 до 10,10 с точкой 5.1, 5.1 детерминант равен нулю. Но дело не в линии. – Andy

+0

Что означает «близко к 0»? – Leggy7

+0

Это гораздо лучший ответ, чем «принятый». Единственное, чего не хватает, это определение «близко к». Это нужно понимать в контексте вычитаемых чисел: поскольку существует 5 вычитаний, существует 5 возможностей для «значительной потери точности», что означает, что на самом деле довольно сложно поставить хорошую спецификацию «ближе к». – Floris

5

Я думаю Mr.Patrick McDonald поставить почти правильный ответ, и это коррекция его ответа:

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)); 
} 

и, конечно, есть много других правильных ответов особенно Mr.Josh, но я нашел это лучший.

Thankx для evryone.

+0

Дает вам div на ноль, если checkPoint.x == endPoint.x или если конечные точки имеют одинаковое значение x – ThiefMaster

22

Я просто написал функцию, которая обрабатывает несколько дополнительных требований, поскольку я использую эту проверку в приложении для рисования:

  • размытость - Там должны быть некоторые места для ошибок, так как функция используется для выбора строк, нажав на них.
  • Линия получила EndPoint и StartPoint, без бесконечных линий.
  • Должен обрабатывать прямые вертикальные и горизонтальные линии, (x2 - x1) == 0 вызывает деление на ноль в других ответах.
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;    
} 
+5

Почему это не принято? Все остальные - просто математика и бла. Это реальный мир, боеспособная функция и должна быть предпочтительной. Я имею в виду, что это StackOverflow ради бога, а не MathOverflow. –

+0

это лучший ответ, потому что он работает. но что было бы лучшим значением для SELECTION_FUZZINESS ?? –

0

Как альтернатива методы 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.

Если эти значения равны, мы проверяем их с точки зрения конечной точки.

Простые и обрабатывающие горизонтальные, вертикальные и все остальное между ними.

Смежные вопросы