Как проверить принадлежит ли точка отрезку
Как определить, принадлежит ли точка A(x,y) отрезку с концевыми точками B(x 1 ,y 1 ) и C(x 2 ,y 2 )?
Точки отрезка z можно описать уравнением
Если существует такое p, 0p
pOB+(1-p)OC=A,
то A лежит на отрезке, иначе — нет.
Равенство расписывается по координатно так:
px 1 +(1-p)x 2 =x
py 1 +(1-p)y 2 =y
Из первого уравнения находим p, подставляем во второе: если получаем равенство и
Рабочая реализация более общей функции есть в разделе структуры геометрических данных.
Как проверить, лежит ли точка на отрезке?
При работе с геометрическими фигурами, в том числе и отрезками, часто возникает необходимость проверить, принадлежит ли точка этому отрезку или нет. В данной статье мы рассмотрим методы и критерии для определения этого.
Что такое отрезок?
Отрезок — это часть прямой, ограниченная двумя точками. Он имеет начальную и конечную точки, а также длину, которая вычисляется как расстояние между этими двумя точками.
Важно знать:
- Отрезок может быть вертикальным (вертикальное положение) или горизонтальным (горизонтальное положение).
- Если начальная и конечная точки отрезка совпадают, то он называется нулевым отрезком.
- Если одна из точек находится за пределами прямой, то отрезок не существует.
Как проверить, лежит ли точка на отрезке?
Существует несколько способов проверки того, принадлежит ли точка отрезку или нет. Рассмотрим их подробнее.
1. Проверка по координатам
Для начала необходимо определить координаты начальной и конечной точек отрезка, а также координаты проверяемой точки. Затем можно использовать следующий критерий:
Важно знать:
- Если точка находится между начальной и конечной точками по оси X (горизонтальная ось), то ее координата X должна быть больше координаты X начальной точки и меньше координаты X конечной точки.
- Аналогично для оси Y (вертикальная ось) — координата Y должна быть больше координаты Y начальной точки и меньше координаты Y конечной точки.
Если оба условия выполняются, то можно сделать вывод, что точка лежит на отрезке.
2. Использование уравнения прямой
Еще один способ — использование уравнения прямой, проходящей через начальную и конечную точки отрезка. Если подставить координаты проверяемой точки в это уравнение и полученное значение будет равно нулю, то можно сделать вывод, что точка лежит на этой прямой и, следовательно, на отрезке.
3. Геометрический метод
Для этого способа необходимо построить отрезок и провести через него прямую, параллельную оси X или Y (в зависимости от положения отрезка). Затем нужно определить, на какой из двух получившихся частей лежит проверяемая точка. Если она находится на той же части, где и сам отрезок, то она лежит на нем.
Заключение
Теперь вы знаете несколько способов проверки того, лежит ли точка на отрезке или нет. Каждый из них имеет свои особенности и может быть использован в различных ситуациях. При работе с геометрическими фигурами всегда помните об этих критериях для более быстрой и точной проверки.
Статьи по этой теме
Как определить пересечение двух отрезков?
Пересечение двух отрезков — это точка или множество точек, которые принадлежат одновременно обоим отрезкам. Это важное понятие в геометрии и математике, так как оно помогает решать различные.
Как найти длину отрезка?
Длина отрезка — это расстояние между двумя точками на прямой. Это важное понятие в геометрии, которое используется для решения различных задач и построения фигур. В этой статье мы рассмотрим.
Как построить отрезок по заданным координатам его концов?
Построение отрезка по заданным координатам является одной из основных задач геометрии. Это важный навык, который используется не только в школьном курсе математики, но и в различных профессиях.
Как вычислить угол между двумя отрезками?
Угол — это геометрическая фигура, образованная двумя лучами с общим началом. В жизни мы часто сталкиваемся с необходимостью вычислять углы для решения различных задач. Например, при построении.
Как найти середину отрезка?
Середина отрезка – это точка, которая находится ровно посередине между двумя концами этого отрезка. На первый взгляд может показаться, что это очевидная задача и ее можно решить просто разделив.
Как определить, параллельны ли два отрезка?
Что такое параллельные отрезки?Параллельные отрезки — это два отрезка на плоскости, которые имеют одинаковое направление и расстояние между собой. Они никогда не пересекаются и всегда.
Как найти точку пересечения двух отрезков?
Точка пересечения – это место, где два отрезка на плоскости пересекаются и имеют общую координату. Найти эту точку может быть не так просто, особенно если отрезки имеют различную длину и.
Как вычислить площадь треугольника, образованного тремя отрезками?
ВведениеТреугольник — это одна из основных геометрических фигур, которая часто встречается в нашей повседневной жизни. Мы видим его в строительстве, дизайне, математике и других сферах.
Как определить, лежат ли два отрезка на одной прямой?
Понятие прямой и отрезка является основным в геометрии и широко используется в различных областях, таких как строительство, архитектура, физика и техника. Поэтому важно уметь определять.
© 2023. Весь текст предоставлен исключительно в ознакомительных целях и написан с использованием нейросетей. Мы не несем ответственности за его точность или достоверность.
Принадлежность точки отрезку. Почему не работает классика?
IP76 > Векторная графика > Принадлежность точки отрезку. Почему не работает классика?

Определить принадлежность точки отрезку, казалось бы, вполне себе тривиальная задача из школьного курса геометрии. Однако, есть определенные нюансы, которые заставляют усомниться в верности классической формулы:
Содержание скрыть
Причины и постановка задачи
Запросы «как найти принадлежность точки отрезку» уводят на страницу «Пересечение прямых, угол и координаты пересечения», где есть пункт «Принадлежность точки отрезку». В нем рассматривается факт принадлежности точки отрезку, уже после того, как мы определили точку пересечения прямых. То есть точка уже принадлежит прямым, и это абсолютно точно. Осталось только определиться, точка в отрезке между двумя точками отрезка, либо где-то на прямой мимо них.
Людям свойственно искать готовые решения, и код, представленный в статье вряд ли удовлетворит запросу «как найти принадлежность точки отрезку, заданный двумя точками«. Поэтому здесь задачу так и сформулируем:
Есть отрезок, заданный точками P1(x1,y1) и P2 (x2,y2) . Необходимо определить, принадлежит ли точка P(x,y) этому отрезку.
Классическое уравнение
Предположим, вы делаете векторный редактор. Необходимо по курсору мыши определить попадает ли точка в ранее нарисованный отрезок. В этом многотрудном деле такая задача возникает всегда.
Для совместимости с Delphi 7 введем тип вещественной точки:
TxPoint = record
TxPoint = TPointF ;
Почему бы не сделать сразу TPointF вместо типа TxPoint? Просто у меня гора старых исходников, где используется этот тип, а никакого TPointF не было ни в помине, ни в планах. Delphi 7 казалась вершиной инженерной мысли на тот момент.
В предложение uses дописываем следующее (ради TPointF, и чтобы компилятор XE не доставал хинтами):
Windows , SysUtils , Classes , Graphics , Controls , Forms ,
, System . Types
Почему именно XE5? Если честно, нет возможности проверить, не ставить же ради этого всю линейку дельфей. Но в XE5 вещественная точка точно есть, а в Delphi 7 ее точно нет. Вот этим и объясняется выбор версии компилятора в директиве. Одни говорят, что TPointF появился в XE2, другие — аж в Delphi 2010. Короче, с таким директивным условием будет работать везде и точка.
Пишем небольшую функцию, которая использует классическое уравнение прямой, проходящей через две различные точки на плоскости, представленное выше.
function PtInSegment ( const P1 , P2 , P : TxPoint ; const Epsilon : extended ;
var res : TxPoint ) : Integer ;
Result : = 0 ;
// проверка Y-координаты
SameValue ( Abs ( p1 . Y — p . Y ) + Abs ( p2 . Y — p . Y ) , Abs ( p2 . Y — p1 . Y ) , Epsilon ) and
// проверка X-координаты
SameValue ( Abs ( p1 . X — p . X ) + Abs ( p2 . X — p . X ) , Abs ( p2 . X — p1 . X ) , Epsilon ) and
// используется классическая формула
SameValue ( ( p . x — p1 . x ) * ( p2 . y — p1 . y ) — ( p . y — p1 . y ) * ( p2 . x — p1 . x ) , 0 , Epsilon )
Result : = 3 ;
SameValue — сравнивает два вещественных числа с учетом погрешности Epsilon. Находится в модуле Math, который надо подключить в предложении uses секции implementation.
Что происходит. Вначале проверяется допустимость координаты точки внутри координат отрезка. Условие необходимое, но недостаточное. Если координата может принадлежать отрезку, третьим условием проверяем нахождение точки на прямой, проходящей через точки отрезка.

Если мы попытаемся по координатам курсора мыши определить, попала ли точка в отрезок, нас ждет фиаско. Складывается ощущение, что формула не работает, алгебра — отстой, все в жизни не так.
Расширенная классика
Для начала навесим на функцию еще пару условий, чтобы определить попадание в точки, задающие отрезок.
// сравнить две точки с учетом погрешности
function PtEqual ( const P1 , P2 : TxPoint ;
const Epsilon : extended = 0.0 ) : Boolean ;
Result : = SameValue ( P1 . X , P2 . X , Epsilon ) and
SameValue ( P1 . Y , P2 . Y , Epsilon ) ;
// классика с учетом попадания на точки P1 и P2
// режим нахождения на отрезке: 0 — мимо, 1 — p1, 2 — p2, 3 — между p1 и p2
function PtInSegmentEx ( const P1 , P2 , P : TxPoint ; const Epsilon : extended ;
var res : TxPoint ) : Integer ;
Result : = 0 ;
if PtEqual ( P1 , P , Epsilon ) then
Result : = 1
if PtEqual ( P2 , P , Epsilon ) then
Result : = 2
if SameValue ( Abs ( p1 . Y — p . Y ) + Abs ( p2 . Y — p . Y ) , Abs ( p2 . Y — p1 . Y ) , Epsilon ) and
SameValue ( Abs ( p1 . X — p . X ) + Abs ( p2 . X — p . X ) , Abs ( p2 . X — p1 . X ) , Epsilon ) and
SameValue ( ( p . x — p1 . x ) * ( p2 . y — p1 . y ) — ( p . y — p1 . y ) * ( p2 . x — p1 . x ) , 0 , Epsilon )
Result : = 3 ;
Ну, во-первых, вот и разгадка, куда делись значения 1 и 2 из результатов предыдущей функции. Во-вторых, теперь в конечные точки отрезка попадает отлично, но между ними по-прежнему не хочет работать.
На самом деле — математика по-прежнему царица наук, а мы пытаемся повенчать розу белую с черной жабой.
Выведем в интерфейс значения dx = (p2.x-p1.x), dy = (p2.y-p1.y) и т.д. Плюс результат работы функции (p.x-p1.x)*(p2.y-p1.y) — (p.y-p1.y)*(p2.x-p1.x). И убедимся, что при самых казалось бы максимально возможных приближениях к отрезку, результат ошеломляет своей двух- или трехзначной непохожестью на ноль.

Конечно, используя операцию умножения вместо деления, мы избегаем деления на ноль, укорачиваем код. Но при этом надо помнить, что умножение даже 1 на 12, это уже далеко от нуля, а если появляется еще и минус в разницах, то от нуля мы улетаем очень быстро и очень ощутимо.
На рисунке 2 прицел точно на линии, но разность координат, которую получаем из классического уравнения, и которая должна быть равна нулю, между тем равна:
Функция применима в точных расчетах, но не в векторном редакторе.
Модификация уравнения
Очевидно, надо вычислять как-то иначе. Например вычислять Y по имеющейся координате X и сравнивать с имеющейся координатой Y. Если разница меньше заданного Epsilon — точка принадлежит отрезку. Выразим Y из используемого уравнения прямой. Итак, дано:
Выразим Y:
И напишем еще одну функцию, в которой учтем ситуацию, когда (X2-X1) может быть равно нулю. Это ситуация вертикальной (или почти вертикальной) прямой.
function PtInSeg ( const P1 , P2 , P : TxPoint ; const Epsilon : extended ;
var res : TxPoint ) : Integer ;
Result : = 0 ;
// сравнить с точкой P1
if PtEqual ( P1 , P , Epsilon ) then
Result : = 1 ;
// сравнить с точкой P2
if PtEqual ( P2 , P , Epsilon ) then
Result : = 2
// проверить на вхождение в координатный допуск отрезка
if SameValue ( Abs ( p1 . Y — p . Y ) + Abs ( p2 . Y — p . Y ) , Abs ( p2 . Y — p1 . Y ) , Epsilon ) and
SameValue ( Abs ( p1 . X — p . X ) + Abs ( p2 . X — p . X ) , Abs ( p2 . X — p1 . X ) , Epsilon ) then
Result : = 3 ;
// это почти вертикальная линия, Y уже проверен условием выше
if SameValue ( p1 . X , p2 . X , Epsilon ) then
res . x : = p1 . X + ( p2 . X — p1 . X ) / 2 ;
// посчитать Y и сравнить с точкой P
res . Y : = ( p . X — p1 . x ) * ( p2 . Y — p1 . y ) / ( p2 . X — p1 . x ) + p1 . Y ;
if SameValue ( p . Y , res . y , Epsilon ) then
Result : = 0 ;
Epsilon уже выступает, и как точность вычислений, и как допуск, при котором мы считаем, что точка на отрезке. Невозможно скрупулезно попасть мышкой в нужную точку отрезка, которая сама по себе уже есть огромное приближение к действительности. Все мы помним и любим Брезенхэма.

Но, даже если мы упростили себе процесс «попадания» в отрезок, мы должны знать точные координаты на отрезке. Для этого у нас и появился тип вещественной точки TxPoint и возвращаемый параметр res. В этой версии функции мы производим расчет реальной точки на отрезке.
На рисунке 3 расчетная точка и ее координаты выделена коричневым цветом.
Однако, все равно есть нюанс. Если линия сильно вертикальна, то есть расстояние (X2-X1) невелико, попадать в линию все равно трудно.

Связано с тем, что при уменьшении делителя, коим разность по X выступает в нашем случае, сильно вырастает результат, и чем расстояние (X2-X1) меньше, тем труднее попасть в Epsilon.
Итоговая функция
В стремлении к совершенству, всегда что-то незамысловатое, в пару строк кода, разрастается в какую-то все учитывающую портянку листинга.
Давайте проверять, что больше (X2-X1) или (Y2-Y1), и в зависимости от результата, будем высчитывать либо Y, либо X. Формулу для X не привожу, он очевидна.
function PtInSegEx ( const P1 , P2 , P : TxPoint ; const Epsilon : extended ;
var res : TxPoint ) : Integer ;
dx , dy , px , py : Single ;
Result : = 0 ;
if PtEqual ( P1 , P , Epsilon ) then
Result : = 1
if PtEqual ( P2 , P , Epsilon ) then
Result : = 2
// просто для понятности кода
dx : = ( p2 . X — p1 . X ) ;
dy : = ( p2 . Y — p1 . Y ) ;
px : = ( p . X — p1 . X ) ;
py : = ( p . Y — p1 . Y ) ;
// линия почти вертикальна
if SameValue ( dx , 0 , Epsilon ) then
// во избежание деления на ноль.
// ситуация мифическая, т.к. проверена уже выше в точках, но.
if SameValue ( dy , 0 ) then
res . X : = p1 . X + dx / 2
res . X : = py * dx / dy + p1 . x ;
// сравнить X точки с расчетным значением
if SameValue ( p . x , res . x , Epsilon ) and
// и проверить координату Y, которая должна быть в диапазон Y1..Y2
SameValue ( Abs ( p1 . Y — p . Y ) + Abs ( p2 . Y — p . Y ) , Abs ( p2 . Y — p1 . Y ) , Epsilon )
Result : = 3 ;
// линия почти горизонтальна
if SameValue ( dy , 0 , Epsilon ) then
// dx=0 уже отработан условием выше, деления на 0 не боимся
res . Y : = px * dy / dx + p1 . Y ;
if SameValue ( p . y , res . y , Epsilon ) and
SameValue ( Abs ( p1 . x — p . x ) + Abs ( p2 . x — p . x ) , Abs ( p2 . x — p1 . x ) , Epsilon )
Result : = 3 ;
// проверка координат точки на валидность координатам отрезка
if SameValue ( Abs ( p1 . Y — p . Y ) + Abs ( p2 . Y — p . Y ) , Abs ( p2 . Y — p1 . Y ) , Epsilon ) and
SameValue ( Abs ( p1 . X — p . X ) + Abs ( p2 . X — p . X ) , Abs ( p2 . X — p1 . X ) , Epsilon ) then
// x2-x1 больше подходит в качестве делителя,
// считаем и сравниваем Y
if ( abs ( dx ) > abs ( dy ) ) then
res . Y : = px * dy / dx + p1 . Y ;
if SameValue ( p . Y , res . Y , Epsilon ) then
Result : = 3 ;
// иначе считаем и сравниваем X
res . X : = py * dx / dy + p1 . x ;
if SameValue ( p . x , res . X , Epsilon ) then
Result : = 3 ;

Почему такая большая функция получилась?
В функции помимо факта принадлежности точки отрезку, также осуществляется проверка на конечные точки — чтобы можно было менять их расположение мышкой. Также, функция возвращает «истинную» точку на отрезке, полученную из приближенной, содержащую погрешность Epsilon.
Можно сократить, не считать конечные точки, не анализировать «вертикальность» и «горизонтальность». Можно взять за настоящую ту точку, которую анализируем и не считать «истинную». Код в этом случае сильно сократиться. Поэтому лучше иметь полный комплект, из которого можно удалить «лишнее» на ваш взгляд.
Зачем нужны такие ощутимо большие проверки на вертикальность и горизонтальность. Ну, во-первых мы освобождаем от условий последний блок вычислений, во-вторых, если убрать, скажем, проверку на dy, погрешность станет в два раза меньше. Потому что отработает это условие: Abs(p1.Y-p.Y) + Abs(p2.Y-p.Y). Имея идеальную горизонтальную линию, подведя курсор на Epsilon допустимый интервал, мы получим в итоге Epsilon + Epsilon = 2 * Epsilon и условие конечно не сработает. Сработает, если подведем на расстояние в два раза меньшее Epsilon.
Если всех этих тонкостей не требуется, можно смело использовать либо эту, либо вообще эту функцию.
Классика всегда в моде или Математика — царица наук
Теперь давайте полученную в результате предыдущей функции вещественную точку res подставим в первую функцию. И убедимся, что теоретическая принадлежность точки отрезку работает прекрасно, просто в пространстве грубых целочисленных точек мы не в состоянии гарантированно получить такую точку, которая удовлетворила бы уравнению. Но если мы ее рассчитаем и получим значения с плавающей запятой — все заработает как надо.

На рисунке 5 добавлен результат функции f(x,y)=(x-x1) * (y2-y1) — (y-y1) * (x2-x1) для рассчитанной точки на отрезке. Он равен, как и следовало ожидать, нулю. А также результат вызова первой функции, которая использует это уравнение и возвращает 3, если точка принадлежит отрезку. Что мы воочию и видим.
1)Поэтому в графике надо избегать типов TPoint, даже если это вызывает необходимость постоянно их округлять для функций GDI.
2)Поэтому функция правильная, классическая формула работает, просто в пространстве компьютерных упрощений надо использовать ту же самую формулу, но в другом качестве.
Скачать
Друзья, спасибо за внимание!
Надеюсь, материал был полезен.
Не пропустите новых интересных штуковин, подписывайтесь на телегу. )))
Если есть вопросы, с удовольствием отвечу.
Исходники и исполняемый файл для GDI и Delphi 7. Проверен в XE 7, XE 10.
Исходники (Delphi 7, XE7, XE10) 11 Кб
Исполняемый файл (zip) 213 Кб
Как подключить GDI+ в Delphi 7 и без проблем скомпилировать в XE 7, XE 10 читаем в этой статье. Там же забираем исходники.
Чтобы нарисовать отрезок, нажмите мышь и, не отпуская, ведите курсор. При отпускании отрезок зафиксируется. При повторном нажатии начнет рисоваться новый отрезок.
За концы отрезка можно таскать. Если попали на отрезок, т.е. видна коричневая точка, можно таскать весь отрезок.
Исходники намеренно выложены в D7 варианте.
При компиляции в XE10 следует снять галочку с Enable High-DPI
Как правильно определить, находится ли точка на отрезке и почему эта информация важна для математики и геометрии
При работе с геометрическими фигурами часто возникает задача определения, принадлежит ли заданная точка некоторому отрезку. Это может понадобиться, например, при построении графиков, определении пересечений или нахождении решений задач на расстояния. В данной статье мы рассмотрим несколько методов, позволяющих проверить, лежит ли точка на отрезке.
Один из наиболее простых подходов заключается в использовании координатной плоскости. Для начала необходимо задать координаты начала и конца отрезка, а также координаты исследуемой точки. Далее можно воспользоваться одним из следующих методов проверки.
Первый метод основан на вычислении расстояния от точки до начала и конца отрезка, а также расстояния между началом и концом отрезка. Если сумма расстояний от точки до начала и конца отрезка равна расстоянию между началом и концом отрезка, то можно с уверенностью сказать, что точка лежит на отрезке. В противном случае точка не принадлежит отрезку.
Как определить принадлежность точки отрезку
Для того чтобы проверить, принадлежит ли точка отрезку, можно использовать несколько способов.
1. Способ 1: Координатные вычисления
Предположим, у нас есть отрезок с координатами (x1, y1) и (x2, y2), и точка с координатами (x, y). Чтобы определить принадлежность точки отрезку, нужно проверить выполнение следующих условий:
— x находится между x1 и x2 (т.е. x1 ≤ x ≤ x2 или x2 ≤ x ≤ x1)
— y находится между y1 и y2 (т.е. y1 ≤ y ≤ y2 или y2 ≤ y ≤ y1)
Если оба условия выполняются, то точка принадлежит отрезку.
2. Способ 2: Векторные вычисления
Если имеются векторы AB и AC, где A — начальная точка отрезка, B — конечная точка отрезка, C — проверяемая точка, то можно проверить принадлежность точки отрезку следующим образом:
— Вычислить векторное произведение AB x AC.
— Если полученный векторный результат равен нулю и скалярное произведение AB * AC ≥ 0, то точка C лежит на прямой, содержащей отрезок AB.
— Если скалярное произведение AB * AC