//线段与凸多边形相交 //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); } }