/// <summary> /// 点是否在共线的线段上 /// 1 = P is inside S; /// 0 = P is not inside S /// </returns> /// </summary> /// <param name="P">a point P</param> /// <param name="S">a collinear segment S</param> /// <returns></returns> public static int InSegment(RgPoint P, RgSegment S) { if (S.P0.X != S.P1.X) { // S is not vertical if (S.P0.X <= P.X && P.X <= S.P1.X) { return(1); } if (S.P0.X >= P.X && P.X >= S.P1.X) { return(1); } } else { // S is vertical, so test y coordinate if (S.P0.Y <= P.Y && P.Y <= S.P1.Y) { return(1); } if (S.P0.Y >= P.Y && P.Y >= S.P1.Y) { return(1); } } return(0); }
//=================================================================== // 点到线段距离 //dist_Point_to_Segment(): get the distance of a point to a segment // Input: a Point P and a Segment S (in any dimension) // Return: the shortest distance from P to S,返回到线段的最短距离 public static double dist_Point_to_Segment(Point3D P, RgSegment S) { Vector3d v = S.P1 - S.P0; Vector3d w = P - S.P0; double c1 = RgMath.dot(w, v); if (c1 <= 0) { return(RgMath.d(P, S.P0)); } double c2 = RgMath.dot(v, v); if (c2 <= c1) { return(RgMath.d(P, S.P1)); } double b = c1 / c2; RgPoint Pb = S.P0 + b * v; return(RgMath.d(P, Pb)); }
/// <summary> /// 点是否在线段上 /// </summary> /// <param name="P">任意的点</param> /// <param name="S">任意线段</param> /// <returns></returns> public static int In2D_Point_Segment(RgPoint P, RgSegment S) { return(0); }
//=================================================================== //3D空间两线段间的最短距离 //dist3D_Segment_to_Segment(): // Input: two 3D line segments S1 and S2 // Return: the shortest distance between S1 and S2 public static double Dist3D_Segment_to_Segment(RgSegment S1, RgSegment S2) { Vector3d u = S1.P1 - S1.P0; Vector3d v = S2.P1 - S2.P0; Vector3d w = S1.P0 - S2.P0; double a = RgMath.dot(u, u); // always >= 0 double b = RgMath.dot(u, v); double c = RgMath.dot(v, v); // always >= 0 double d = RgMath.dot(u, w); double e = RgMath.dot(v, w); double D = a * c - b * b; // always >= 0 double sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0 double tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0 // compute the line parameters of the two closest points if (D < RgMath.SMALL_NUM) { // the lines are almost parallel sN = 0.0; // force using point P0 on segment S1 sD = 1.0; // to prevent possible division by 0.0 later tN = e; tD = c; } else { // get the closest points on the infinite lines sN = (b * e - c * d); tN = (a * e - b * d); if (sN < 0.0) { // sc < 0 => the s=0 edge is visible sN = 0.0; tN = e; tD = c; } else if (sN > sD) { // sc > 1 => the s=1 edge is visible sN = sD; tN = e + b; tD = c; } } if (tN < 0.0) { // tc < 0 => the t=0 edge is visible tN = 0.0; // recompute sc for this edge if (-d < 0.0) { sN = 0.0; } else if (-d > a) { sN = sD; } else { sN = -d; sD = a; } } else if (tN > tD) { // tc > 1 => the t=1 edge is visible tN = tD; // recompute sc for this edge if ((-d + b) < 0.0) { sN = 0; } else if ((-d + b) > a) { sN = sD; } else { sN = (-d + b); sD = a; } } // finally do the division to get sc and tc sc = (Math.Abs(sN) < RgMath.SMALL_NUM ? 0.0 : sN / sD); tc = (Math.Abs(tN) < RgMath.SMALL_NUM ? 0.0 : tN / tD); // get the difference of the two closest points Vector3d dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc) return(RgMath.norm(dP)); // return the closest distance }
//线段与凸多边形相交 //intersect2D_SegPoly(): // Input: S = 2D segment to intersect with the convex polygon // n = number of 2D points in the polygon // V[] = array of n+1 vertex points with V[n]=V[0] // Note: The polygon MUST be convex and // have vertices oriented counterclockwise (ccw). // This code does not check for and verify these conditions. // Output: *IS = the intersection segment (when it exists) // Return: FALSE = no intersection // TRUE = a valid intersection segment exists int intersect2D_SegPoly(RgSegment S, RgPoint[] V, int n, RgSegment IS) { if (S.P0 == S.P1) { // the segment S is a single point // test for inclusion of S.P0 in the polygon IS = S; // same point if inside polygon return(RgTopologicRelationship.cn_PnPoly(S.P0, V, n)); // March 2001 Algorithm } float tE = 0; // the maximum entering segment parameter float tL = 1; // the minimum leaving segment parameter float t, N, D; // intersect parameter t = N / D Vector3d dS = S.P1 - S.P0; // the segment direction vector Vector3d e; // edge vector // Vector ne; // edge outward normal (not explicit in code) for (int i = 0; i < n; i++) // process polygon edge V[i]V[i+1] { RgPoint ePt = V[i + 1] - V[i]; e = new Vector3d(ePt.X, ePt.Y, 0); RgPoint temp = S.P0 - V[i]; N = (float)RgMath.perp(e, new Vector3d(temp.X, temp.Y, 0)); // = -dot(ne, S.P0-V[i]) D = (float)-RgMath.perp(e, dS); // = dot(ne, dS) if (Math.Abs(D) < RgMath.SMALL_NUM) { // S is nearly parallel to this edge if (N < 0) // P0 is outside this edge, so { return(0); // S is outside the polygon } else // S cannot cross this edge, so { continue; // ignore this edge } } t = N / D; if (D < 0) { // segment S is entering across this edge if (t > tE) { // new max tE tE = t; if (tE > tL) // S enters after leaving polygon { return(0); } } } else { // segment S is leaving across this edge if (t < tL) { // new min tL tL = t; if (tL < tE) // S leaves before entering polygon { return(0); } } } } // tE <= tL implies that there is a valid intersection subsegment IS.P0 = S.P0 + tE * dS; // = P(tE) = point where S enters polygon IS.P1 = S.P0 + tL * dS; // = P(tL) = point where S leaves polygon return(1); }
// perp product (2D) // intersect2D_2Segments(): the intersection of 2 finite 2D segments // Input: two finite segments S1 and S2 // Output: *I0 = intersect point (when it exists) // *I1 = endpoint of intersect segment [I0,I1] (when it exists) // Return: 0=disjoint (no intersect) // 1=intersect in unique point I0 // 2=overlap in segment from I0 to I1 public int Intersect2D_Segments(RgSegment S1, RgSegment S2, out Point3D I0, out Point3D I1) { Vector3d u = S1.P1 - S1.P0; Vector3d v = S2.P1 - S2.P0; Vector3d w = S1.P0 - S2.P0; double D = RgMath.perp(u, v); // test if they are parallel (includes either being a point)平行 if (Math.Abs(D) < RgMath.SMALL_NUM) { // S1 and S2 are parallel if (RgMath.perp(u, w) != 0 || RgMath.perp(v, w) != 0) { I0 = null; I1 = null; return(0); // they are NOT collinear不共线 } // they are collinear or degenerate两线段共线 // check if they are degenerate points double du = RgMath.dot2(u, u); double dv = RgMath.dot2(v, v); if (du == 0 && dv == 0) { // both segments are points if (S1.P0 != S2.P0) // they are distinct points不同的点 { I0 = null; I1 = null; return(0); } I0 = S1.P0; I1 = null;// they are the same point同一点 return(1); } if (du == 0) { // S1 is a single point if (RgTopologicRelationship.InSegment(S1.P0, S2) == 0) // but is not in S2 { I0 = null; I1 = null; return(0); } I0 = S1.P0; I1 = null; return(1); } if (dv == 0) { // S2 a single point if (RgTopologicRelationship.InSegment(S2.P0, S1) == 0) // but is not in S1 { I0 = null; I1 = null; return(0); } I0 = S2.P0; I1 = null; return(1); } // they are collinear segments - get overlap (or not) double t0, t1; // endpoints of S1 in eqn for S2 Vector3d w2 = S1.P1 - S2.P0; if (v.X != 0) { t0 = w.X / v.X; t1 = w2.X / v.X; } else { t0 = w.Y / v.Y; t1 = w2.Y / v.Y; } if (t0 > t1) { // must have t0 smaller than t1 double t = t0; t0 = t1; t1 = t; // swap if not } if (t0 > 1 || t1 < 0) { I0 = null; I1 = null; return(0); // NO overlap } t0 = t0 < 0 ? 0 : t0; // clip to min 0 t1 = t1 > 1 ? 1 : t1; // clip to max 1 if (t0 == t1) { // intersect is a point I0 = S2.P0 + t0 * v; I1 = null; return(1); } // they overlap in a valid subsegment I0 = S2.P0 + t0 * v; I1 = S2.P0 + t1 * v; return(2); } // the segments are skew and may intersect in a point // get the intersect parameter for S1 double sI = RgMath.perp(v, w) / D; if (sI < 0 || sI > 1) {// no intersect with S1 I0 = null; I1 = null; return(0); } // get the intersect parameter for S2 double tI = RgMath.perp(u, w) / D; if (tI < 0 || tI > 1) {// no intersect with S2 I0 = null; I1 = null; return(0); } I0 = S1.P0 + sI * u; // compute S1 intersect point { I1 = null; return(1); } }