public static bool SweepIntersects(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, Vector2 l1, Vector2 l2, out Vector2 intersection, out float percent, float accuracy = 1) { intersection = Vector2.zero; percent = 0; Vector2 lineDelta = l2 - l1; Vector2 point = l2; b1 += -lineDelta; b2 += -lineDelta; Vector2[] poly = { a1, a2, b2, b1 }; FlatBounds bounds = new FlatBounds(poly); if (!bounds.Contains(l1)) { return(false); } // bounds.DrawDebug(Color.yellow); Vector2 pointRight = point + new Vector2(Mathf.Max(bounds.width, bounds.height), 0); // Vector2 pointRight = point - lineDelta * bounds.width * bounds.height; // Debug.DrawLine(ToV3(point), ToV3(pointRight), Color.cyan); int numberOfPolyPoints = poly.Length; int numberOfCrossOvers = 0; for (int i = 0; i < numberOfPolyPoints; i++) { Vector2 p0 = poly[i]; Vector2 p1 = poly[(i + 1) % numberOfPolyPoints]; // Debug.DrawLine(ToV3(p0), ToV3(p1), Color.blue); if (FastLineIntersection(point, pointRight, p0, p1)) { numberOfCrossOvers++; } } if (numberOfCrossOvers % 2 == 0) { return(false);//point not within shape } bounds.DrawDebug(Color.green); Vector2 delta1 = b1 - a1; Vector2 delta2 = b2 - a2; float maxDelta = Mathf.Max(delta1.magnitude, delta2.magnitude); int iterations = Mathf.CeilToInt(Mathf.Sqrt(maxDelta / accuracy)); for (int i = 0; i < iterations; i++) { Vector2 c1 = Vector2.Lerp(a1, b1, 0.5f); Vector2 c2 = Vector2.Lerp(a2, b2, 0.5f); if (!Ccw(c1, c2, point)) { a1 = c1; a2 = c2; percent = Mathf.Lerp(percent, 1, 0.5f); } else { b1 = c1; b2 = c2; percent = Mathf.Lerp(0, percent, 0.5f); } } // Vector2 x1 = Vector2.Lerp(a1, b1, 0.5f); // Vector2 x2 = Vector2.Lerp(a2, b2, 0.5f); // float dist1 = Vector2.Distance(x1, point); // float dist2 = Vector2.Distance(x2, point); // float xpercent = dist1 / (dist1 + dist2); // intersection = Vector2.Lerp(x1, x2, xpercent); intersection = Vector2.Lerp(l1, l2, percent);//translate the point to the real movement point Debug.DrawLine(ToV3(intersection), ToV3(intersection) + Vector3.up * 5, Color.red); return(true); }
public static bool SweepIntersects2(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2, Vector2 l1, Vector2 l2, out Vector2 intersection, out float percent, float accuracy = 1, bool debug = false) { intersection = Vector2.zero; percent = 0; Vector2[] poly = { a1, a2, b2, b1 }; FlatBounds edgeBounds = new FlatBounds(poly); FlatBounds lineBounds = new FlatBounds(new [] { l1, l2 }); if (!edgeBounds.Overlaps(lineBounds, true)) { if (debug) { edgeBounds.DrawDebug(Color.cyan); } if (debug) { lineBounds.DrawDebug(Color.green); } if (debug) { Debug.DrawLine(ToV3(l1), ToV3(l2), Color.cyan); } return(false); } int numberOfPolyPoints = poly.Length; bool lineIntersectsShape = false; for (int i = 0; i < numberOfPolyPoints; i++) { Vector2 p0 = poly[i]; Vector2 p1 = poly[(i + 1) % numberOfPolyPoints]; if (debug) { Debug.DrawLine(ToV3(p0), ToV3(p1), Color.blue); } if (FastLineIntersection(p0, p1, l1, l2)) { lineIntersectsShape = true; break; } } if (!lineIntersectsShape)//line never crosses shape { Vector2 right = new Vector2(Mathf.Max(edgeBounds.width, edgeBounds.height), 0); int shapeIntersections = 0; for (int i = 0; i < numberOfPolyPoints; i++) { Vector2 p0 = poly[i]; Vector2 p1 = poly[(i + 1) % numberOfPolyPoints]; if (debug) { Debug.DrawLine(ToV3(p0) + Vector3.up * 5, ToV3(p1) + Vector3.up * 5, Color.blue); } if (FastLineIntersection(l1, l1 + right, p0, p1)) { if (debug) { Debug.DrawLine(ToV3(l1), ToV3(l1) + Vector3.up * 5, Color.magenta); } shapeIntersections++; } if (FastLineIntersection(l2, l2 + right, p0, p1)) { if (debug) { Debug.DrawLine(ToV3(l1), ToV3(l1) + Vector3.up * 5, Color.magenta); } shapeIntersections++; break; } } if (shapeIntersections % 2 == 0) { return(false);//line not within shape } } if (debug) { edgeBounds.DrawDebug(Color.green); } Vector2 delta1 = b1 - a1; Vector2 delta2 = b2 - a2; float maxDelta = Mathf.Max(delta1.magnitude, delta2.magnitude); int iterations = Mathf.CeilToInt(maxDelta / accuracy); bool initalState = Ccw(a1, a2, l1); for (int i = 1; i < iterations; i++) { percent = i / (iterations - 1f); Vector2 e1 = Vector2.Lerp(a1, b1, percent); Vector2 e2 = Vector2.Lerp(a2, b2, percent); if (debug) { Debug.DrawLine(ToV3(e1), ToV3(e2), new Color(1, 0, 1, 0.5f)); } Vector2 p = Vector2.Lerp(l1, l2, percent); bool currentState = Ccw(e1, e2, p); if (currentState != initalState || i == iterations - 1) { float dist1 = Vector2.Distance(e1, p); float dist2 = Vector2.Distance(e2, p); float xpercent = dist1 / (dist1 + dist2); intersection = Vector2.Lerp(e1, e2, xpercent); if (debug) { Debug.DrawLine(ToV3(e1), ToV3(e2), Color.red); } if (debug) { Debug.DrawLine(ToV3(intersection), ToV3(intersection) + Vector3.up * 10, Color.red); } break; } } return(true); }
/// <summary> /// Return a shape with a defined shape cut out of it. /// Will test find the best closest non intersectional cut to make in the base shape /// Assumes the cut doesn't intersect the shape lines and is inside the base shape /// </summary> /// <param name="baseShape"></param> /// <param name="cut"></param> /// <returns></returns> public static Vector2[] Execute(Vector2[] baseShape, List <Vector2[]> cuts) { bool dbg = false; Vector2[] cut = (Vector2[])cuts[0].Clone();//todo multiple cuts int baseCount = baseShape.Length; int cutCount = cut.Length; int outputCount = baseCount + cutCount + 2; Vector2[] output = new Vector2[outputCount]; FlatBounds bounds = new FlatBounds(cut); if (dbg) { bounds.DrawDebug(Color.magenta); } Vector2 center = bounds.center; float nrest = Mathf.Infinity; int nearestIndex = 0; Array.Reverse(cut);//reverse winding to create cut for (int b = 0; b < baseCount; b++) { float sqrMag = (baseShape[b] - center).sqrMagnitude; if (sqrMag < nrest) { Vector2 a1 = center; Vector2 a2 = baseShape[b]; bool intersectsShape = false; for (int x = 0; x < baseCount; x++) { if (b == x) { continue; } int x2 = (x + 1) % baseCount; if (b == x2) { continue; } Vector2 b1 = baseShape[x]; Vector2 b2 = baseShape[x2]; if (dbg) { Debug.DrawLine(ToV3(b1), ToV3(b2), Color.yellow); } if (FastLineIntersection(a1, a2, b1, b2)) { intersectsShape = true; break; } } if (!intersectsShape) { nearestIndex = b; nrest = sqrMag; } //intersection check } } //find nearest cut point to base point int nearestCutIndex = 0; float nearestCut = Mathf.Infinity; Vector2 baseCut = baseShape[nearestIndex]; for (int i = 0; i < cutCount; i++) { float sqrMag = (cut[i] - baseCut).sqrMagnitude; if (sqrMag < nearestCut) { nearestCutIndex = i; nearestCut = sqrMag; } } if (dbg) { Debug.Log(nearestIndex); Debug.DrawLine(ToV3(baseShape[nearestIndex]), ToV3(center), Color.red); } for (int o = 0; o < outputCount; o++) { if (o <= nearestIndex) { output[o] = baseShape[o]; if (dbg && o > 0) { Debug.DrawLine(ToV3(output[o]), ToV3(output[o - 1]) + Vector3.up, Color.blue, 60); } if (dbg) { Debug.Log("0x " + baseCount + " " + cutCount + " " + output.Length + " " + o); } } else if (o > nearestIndex && o <= nearestIndex + cutCount + 1) { int cutIndex = (nearestCutIndex + o - nearestIndex - 1) % cutCount; output[o] = cut[cutIndex]; if (dbg && o > 0) { Debug.DrawLine(ToV3(output[o]), ToV3(output[o - 1]) + Vector3.up, Color.blue, 60); } if (dbg) { Debug.Log("1x " + cutIndex + " " + baseCount + " " + cutCount + " " + output.Length + " " + o); } } else { int finalIndex = (o - cutCount - 2 + baseCount) % baseCount; if (dbg) { Debug.Log("2x " + finalIndex + " " + baseCount + " " + cutCount + " " + output.Length + " " + o); } output[o] = baseShape[finalIndex]; if (dbg && o > 0) { Debug.DrawLine(ToV3(output[o]), ToV3(output[o - 1]) + Vector3.up, Color.blue, 60); } } } return(output); }