Проверка сегмента линии находится на расстоянии от точки
У меня есть две точки A и B, которые определяют сегмент линии на экране устройства плюс другую точку C. Используя эффективный и короткий алгоритм, который легко кодировать (желательно с использованием стандартной математической библиотеки), как проверить, является ли сегмент линии AB находится на расстоянии R от C?
Я знаю, что есть простой способ найти кратчайшее расстояние от точки до линии, но предполагается, что линия бесконечно длинная. У меня есть сегмент линии с двумя конечными точками.
Я посчитал, что размещаю это в Math SE, но решил не делать этого, так как я не хочу получать всю эту длинную математическую формулу в качестве ответа, как в https://math.stackexchange.com/info/2837/how-to-tell-if-a-line-segment-intersects-with-a-circle. Мне нужен эффективный и читаемый компьютерный алгоритм, а не формальная математическая теорема.
p/s: у меня есть следующий скелет метода Objective-C, который необходимо реализовать:
typedef struct {
CGPoint a;
CGPoint b;
} CGLineSegment;
+ (BOOL)isLineSegment:(CGLineSegment)line withinRadius:(CGFloat)radius fromPoint:(CGPoint)point {
}
РЕДАКТИРОВАТЬ С РЕШЕНИЕМ:
благодаря ответу veredesmarald (который я уже принял), я внедрил этот метод, поставленный здесь как ссылка для других людей:
+ (BOOL)isLineSegment:(CGLineSegment)line withinRadius:(CGFloat)radius fromPoint:(CGPoint)point {
CGPoint v = CGPointMake(line.b.x - line.a.x, line.b.y - line.a.y);
CGPoint w = CGPointMake(point.x - line.a.x, point.y - line.a.y);
CGFloat c1 = dotProduct(w, v);
CGFloat c2 = dotProduct(v, v);
CGFloat d;
if (c1 <= 0) {
d = distance(point, line.a);
}
else if (c2 <= c1) {
d = distance(point, line.b);
}
else {
CGFloat b = c1 / c2;
CGPoint Pb = CGPointMake(line.a.x + b * v.x, line.a.y + b * v.y);
d = distance(point, Pb);
}
return d <= radius;
}
CGFloat distance(const CGPoint p1, const CGPoint p2) {
return sqrt(pow(p2.x - p1.x, 2) + pow(p2.y - p1.y, 2));
}
CGFloat dotProduct(const CGPoint p1, const CGPoint p2) {
return p1.x * p2.x + p1.y * p2.y;
}
Ответы
Ответ 1
Когда мне пришлось реализовать метод определения расстояния от точки до интервала для графического назначения, я нашел эту страницу очень информативной: О линиях и Расстояние от точки до линии
В частности, вам интересен раздел Расстояние точки к лучу или сегменту.
Псевдокод из статьи (где ·
- точечный продукт, а d()
- расстояние между двумя точками):
distance( Point P, Segment P0:P1 )
{
v = P1 - P0
w = P - P0
if ( (c1 = w·v) <= 0 )
return d(P, P0)
if ( (c2 = v·v) <= c1 )
return d(P, P1)
b = c1 / c2
Pb = P0 + bv
return d(P, Pb)
}
Этот метод полагается на точечный продукт, чтобы определить, находится ли основание перпендикуляра в пределах интервала, а если нет, какая конечная точка ближе.