/// <summary> /// Returns the minimal distance between the polygon and the non- /// overlapping other supplied polygon. The minimal distance is /// always computed as the distance between a line segment and a /// point. The indices of the minimal distance configuration are /// returned in the out parameter, as the indices of points on the /// two polygons, and wether the line segement was on this or the /// other polygon. O(n). The returned index of the line segment is /// the lower point index (except in case of wraparound). /// </summary> public static double MinDistanceTo( this Polygon2d polygon, Polygon2d polygon1, out int pi0, out int pi1, out bool lineOnThis) { var p0a = polygon.m_pointArray; var p1a = polygon1.m_pointArray; var p0c = polygon.m_pointCount; var p1c = polygon1.m_pointCount; var e0a = polygon.GetEdgeArray(); var e1a = polygon1.GetEdgeArray(); int i0 = p0a.IndexOfMinY(p0c), i1 = p1a.IndexOfMaxY(p1c); V2d p0 = p0a[i0], e0 = e0a[i0], p1 = p1a[i1], e1 = e1a[i1]; int start0 = i0, start1 = i1; var dir = V2d.XAxis; var d = V2d.Distance(p0, p1); var bestValue = double.MaxValue; int bpi0 = -1, bpi1 = -1; var bLineOnThis = true; do { var s0 = Fun.Atan2(e0.Dot90(dir), e0.Dot(dir)); var s1 = Fun.Atan2(e1.Dot270(dir), e1.Dot180(dir)); if (s0 <= s1) { dir = e0a[i0]; int i0n = (i0 + 1) % p0c; var p0n = p0a[i0]; var dn = V2d.Distance(p0n, p1); var dist = DistanceToLine(p1, p0, p0n, d, dn); if (dist < bestValue) { bestValue = dist; bLineOnThis = true; bpi0 = i0; bpi1 = i1; } i0 = i0n; p0 = p0n; e0 = e0a[i0]; d = dn; } else { dir = e0a[i1].Rot180; int i1n = (i1 + 1) % p1c; var p1n = p1a[i1]; var dn = V2d.Distance(p0, p1n); var dist = DistanceToLine(p0, p1, p1n, d, dn); if (dist < bestValue) { bestValue = dist; bLineOnThis = false; bpi0 = i0; bpi1 = i1; } i1 = i1n; p1 = p1n; e1 = e1a[i1]; d = dn; } }while (i0 != start0 || i1 != start1); lineOnThis = bLineOnThis; pi0 = bpi0; pi1 = bpi1; return(bestValue); }
private static double DistanceToLine(V2d query, V2d p0, V2d p1, double d0, double d1) { var p0p1 = p1 - p0; var p0q = query - p0; var t = V2d.Dot(p0q, p0p1); if (t <= 0) { return(d0); } var denom = p0p1.LengthSquared; if (t >= denom) { return(d1); } t /= denom; return(V2d.Distance(query, p0 + t * p0p1)); }