查找点是否位于线段上

我有由两个点A(x1,y1,z1)和B(x2,y2,z2)和点p(x,y,z)定义的线段。 如何检查该点是否位于线段上?

如果该点在线上则:

(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 

从线端点A,B找到点P的距离。如果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; 

首先考虑AB和AP的交叉产品 。 如果它们是共线的,则它将为0。

此时,它仍然可以在延伸超过B或A之前的更大线上,因此我认为您应该能够检查pz是否介于az和bz之间。

实际上,这似乎是重复的 ,并且作为答案中的一个提及,它在美丽的代码中 。

您的线段最好由参数方程定义

对于您的线段上的所有点,以下等式成立:x = x1 +(x2 – x1)* p y = y1 +(y2 – y1)* p z = z1 +(z2 – z1)* p

其中p是[0; 1]中的数字

因此,如果存在ap,使得您的点坐标满足这3个方程式,那么您的点就在这一行上。 并且p在0和1之间 – 它也在线段上

以下是2D案例的一些C#代码:

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

如果有人寻找内联版本:

 public static bool PointOnLine2D (this Vector2 p, Vector2 a, Vector2 b, float t = 1E-03f) { // ensure points are collinear var zero = (bx - ax) * (py - ay) - (px - ax) * (by - ay); if (zero > t || zero < -t) return false; // check if x-coordinates are not equal if (ax - bx > t || bx - ax > t) // ensure x is between ax & bx (use tolerance) return ax > bx ? px + t > bx && px - t < ax : px + t > ax && px - t < bx; // ensure y is between ay & by (use tolerance) return ay > by ? py + t > by && py - t < ay : py + t > ay && py - t < by; } 

交叉积(B – A)×(p – A)应比B – A短得多。理想情况下,叉积为零,但在有限精度浮点硬件上这不太可能。

根据Konstantin上面的答案,这里有一些C代码可以找出一个点实际上是否在FINITE线段上。 这考虑了水平/垂直线段。 这也考虑到浮点数在彼此比较时从不真正“精确”。 在大多数情况下,0.001f的默认epsilon就足够了。 这适用于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 

我用它来计算点a和b之间的距离AB。

 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(cX + cY); } 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((bX - aX) * (bX - aX), (bY - aY) * (bY - aY)); } } 

基于计算距离A的给定距离处的AB线的点

设V1为矢量(BA),V2 =(pA),将V1和V2归一化。

如果V1 ==( – V2)则点p在线上,但在A之前,因此不在线段中。 如果V1 == V2,则点p在线上。 得到(pA)的长度,并检查它是否小于或等于(BA)的长度,如果是,则该点在该段上,否则它超过B.

您可以检查点是否位于由point1和point2定义的两个平面与线方向之间:

 /// Returns the closest point from @a point to this line on this line. vector3  line3d ::closest_point (const vector3  & point) const { return this -> point () + direction () * dot (point - this -> point (), direction ()); } /// Returns true if @a point lies between point1 and point2. template  bool line_segment3 ::is_between (const vector3  & point) const { const auto closest = line () .closest_point (point); return abs ((closest - point0 ()) + (closest - point1 ())) <= abs (point0 () - point1 ()); }