Найти, если точка лежит на отрезке - PullRequest
24 голосов
/ 13 августа 2011

У меня есть отрезок, определяемый двумя точками A (x1, y1, z1) и B (x2, y2, z2) и точкой p (x, y, z). Как я могу проверить, лежит ли точка на отрезке?

Ответы [ 11 ]

34 голосов
/ 11 июля 2013

Найдите расстояние точки P от обеих конечных точек A, B. Если AB = AP + PB, то P лежит на отрезке AB.

AB = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
AP = sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1));
PB = sqrt((x2-x)*(x2-x)+(y2-y)*(y2-y)+(z2-z)*(z2-z));
if(AB == AP + PB)
    return true;
20 голосов
/ 13 августа 2011

Если точка равна на линии, то:

(x - x1) / (x2 - x1) = (y - y1) / (y2 - y1) = (z - z1) / (z2 - z1)

Рассчитайте все три значения и, если они совпадают (с некоторой степенью допуска), ваша точка включеналиния.

Чтобы проверить, находится ли точка в сегменте, а не только на линии, вы можете проверить, что

x1 < x < x2, assuming x1 < x2, or
y1 < y < y2, assuming y1 < y2, or
z1 < z < z2, assuming z1 < z2
7 голосов
/ 13 августа 2011

Сначала возьмите перекрестное произведение AB и AP .Если они коллинеарны, то это будет 0.

В этот момент он все еще может находиться на большей линии, проходящей после B или перед A, поэтому я думаю, что вы должны просто проверить, является ли pzмежду az и bz.

Этот фактически является дубликатом , и, как упоминается в одном из ответов, он находится в Красивый код .

3 голосов
/ 11 февраля 2016

в случае, если кто-то ищет встроенную версию:

public static bool PointOnLine2D (this Vector2 p, Vector2 a, Vector2 b, float t = 1E-03f)
{
    // ensure points are collinear
    var zero = (b.x - a.x) * (p.y - a.y) - (p.x - a.x) * (b.y - a.y);
    if (zero > t || zero < -t) return false;

    // check if x-coordinates are not equal
    if (a.x - b.x > t || b.x - a.x > t)
        // ensure x is between a.x & b.x (use tolerance)
        return a.x > b.x
            ? p.x + t > b.x && p.x - t < a.x
            : p.x + t > a.x && p.x - t < b.x;

    // ensure y is between a.y & b.y (use tolerance)
    return a.y > b.y
        ? p.y + t > b.y && p.y - t < a.y
        : p.y + t > a.y && p.y - t < b.y;
}
3 голосов
/ 13 августа 2011

Ваш сегмент лучше всего определяется параметрическим уравнением

для всех точек вашего сегмента, имеет место следующее уравнение: x = x1 + (x2 - x1) * py = y1 + (y2 - y1) * pz =z1 + (z2 - z1) * p

Где p - это число в [0; 1]

Итак, если есть ар, такой что ваши координаты точки удовлетворяют этим 3 уравнениям, ваша точкана этой линии.И это р между 0 и 1 - это также на отрезке

2 голосов
/ 05 сентября 2014

Вот код C # для 2D-случая:

public static bool PointOnLineSegment(PointD pt1, PointD pt2, PointD pt, double epsilon = 0.001)
{
  if (pt.X - Math.Max(pt1.X, pt2.X) > epsilon || 
      Math.Min(pt1.X, pt2.X) - pt.X > epsilon || 
      pt.Y - Math.Max(pt1.Y, pt2.Y) > epsilon || 
      Math.Min(pt1.Y, pt2.Y) - pt.Y > epsilon)
    return false;

  if (Math.Abs(pt2.X - pt1.X) < epsilon)
    return Math.Abs(pt1.X - pt.X) < epsilon || Math.Abs(pt2.X - pt.X) < epsilon;
  if (Math.Abs(pt2.Y - pt1.Y) < epsilon)
    return Math.Abs(pt1.Y - pt.Y) < epsilon || Math.Abs(pt2.Y - pt.Y) < epsilon;

  double x = pt1.X + (pt.Y - pt1.Y) * (pt2.X - pt1.X) / (pt2.Y - pt1.Y);
  double y = pt1.Y + (pt.X - pt1.X) * (pt2.Y - pt1.Y) / (pt2.X - pt1.X);

  return Math.Abs(pt.X - x) < epsilon || Math.Abs(pt.Y - y) < epsilon;
}
0 голосов
/ 22 апреля 2017

Пусть V1 - вектор (BA), а V2 = (pA), нормализуют оба V1 и V2.

Если V1 == (- V2), то точка p находится на прямой, но предшествуетА, и, следовательно, не в сегменте.Если V1 == V2, точка p находится на прямой.Получите длину (pA) и убедитесь, что она меньше или равна длине (BA), если это так, точка находится на отрезке, иначе она прошла B. B. 1003 *

0 голосов
/ 10 июля 2016

Я использую это для вычисления расстояния AB между точками a и b.

static void Main(string[] args)
{
        double AB = segment(0, 1, 0, 4);
        Console.WriteLine("Length of segment AB: {0}",AB);
}

static double segment (int ax,int ay, int bx, int by)
{
    Vector a = new Vector(ax,ay);
    Vector b = new Vector(bx,by);
    Vector c = (a & b);
    return Math.Sqrt(c.X + c.Y);
}

struct Vector
{
    public readonly float X;
    public readonly float Y;

    public Vector(float x, float y)
    {
        this.X = x;
        this.Y = y;
    }
    public static Vector operator &(Vector a, Vector b)  
    {
        return new Vector((b.X - a.X) * (b.X - a.X), (b.Y - a.Y) * (b.Y - a.Y));
    }
}

на основе Вычисление точки вдоль линии AB на заданном расстоянии от A

0 голосов
/ 21 марта 2016

Вы можете проверить, находится ли точка между двумя плоскостями, определенными точкой1 и точкой2, и направлением линии:

///  Returns the closest point from @a point to this line on this line.
vector3 <Type>
line3d <Type>::closest_point (const vector3 <Type> & point) const
{
    return this -> point () + direction () * dot (point - this -> point (), direction ());
}

///  Returns true if @a point lies between point1 and point2.
template <class Type>
bool
line_segment3 <Type>::is_between (const vector3 <Type> & point) const
{
    const auto closest = line () .closest_point (point);
    return abs ((closest - point0 ()) + (closest - point1 ())) <= abs (point0 () - point1 ());
}
0 голосов
/ 29 апреля 2013

Основываясь на ответе Константина, приведенном выше, приведем код C, чтобы определить, действительно ли точка находится на отрезке линии FINITE.Это учитывает горизонтальные / вертикальные отрезки.Это также учитывает, что числа с плавающей точкой никогда не бывают действительно «точными» при сравнении их друг с другом.Эпсилон по умолчанию 0,001f будет достаточным в большинстве случаев.Это для 2D линий ... добавление "Z" было бы тривиально.Класс PointF из GDI +, который в основном просто: struct PointF{float X,Y};

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

#define DEFFLEQEPSILON 0.001
#define FLOAT_EQE(x,v,e)((((v)-(e))<(x))&&((x)<((v)+(e))))

static bool Within(float fl, float flLow, float flHi, float flEp=DEFFLEQEPSILON){
    if((fl>flLow) && (fl<flHi)){ return true; }
    if(FLOAT_EQE(fl,flLow,flEp) || FLOAT_EQE(fl,flHi,flEp)){ return true; }
    return false;
}

static bool PointOnLine(const PointF& ptL1, const PointF& ptL2, const PointF& ptTest, float flEp=DEFFLEQEPSILON){
    bool bTestX = true;
    const float flX = ptL2.X-ptL1.X;
    if(FLOAT_EQE(flX,0.0f,flEp)){
        // vertical line -- ptTest.X must equal ptL1.X to continue
        if(!FLOAT_EQE(ptTest.X,ptL1.X,flEp)){ return false; }
        bTestX = false;
    }
    bool bTestY = true;
    const float flY = ptL2.Y-ptL1.Y;
    if(FLOAT_EQE(flY,0.0f,flEp)){
        // horizontal line -- ptTest.Y must equal ptL1.Y to continue
        if(!FLOAT_EQE(ptTest.Y,ptL1.Y,flEp)){ return false; }
        bTestY = false;
    }
    // found here: http://stackoverflow.com/a/7050309
    // x = x1 + (x2 - x1) * p
    // y = y1 + (y2 - y1) * p
    // solve for p:
    const float pX = bTestX?((ptTest.X-ptL1.X)/flX):0.5f;
    const float pY = bTestY?((ptTest.Y-ptL1.Y)/flY):0.5f;
    return Within(pX,0.0f,1.0f,flEp) && Within(pY,0.0f,1.0f,flEp);
}
...