public static RectInt RotateRectInt(RectInt ri, Vector2Int pivot, int quarterTurnsClockwise) { // Get the corners var a = ri.position; var trueMax = ri.TrueMax(); var b = new Vector2Int(trueMax.x, ri.position.y); var c = new Vector2Int(ri.position.x, trueMax.y); var d = trueMax; // Rotate each one. a = Rotate(a, pivot, quarterTurnsClockwise); b = Rotate(b, pivot, quarterTurnsClockwise); c = Rotate(c, pivot, quarterTurnsClockwise); d = Rotate(d, pivot, quarterTurnsClockwise); // Rebuild RectInt ri = GrokRectInt(a, b, c, d); return(ri); }
// TODO: mimic logical & operation from Phil.Core.RectInt public static bool TryGetRectIntersection(RectInt a, RectInt b, out RectInt intersection) { if (!a.Overlaps(b)) { intersection = new RectInt(0, 0, 0, 0); return(false); } else { var aMax = a.TrueMax(); var bMax = b.TrueMax(); int maxLeft = Mathf.Max(a.xMin, b.xMin); int minRight = Mathf.Min(aMax.x, bMax.x); int minTop = Mathf.Min(aMax.y, bMax.y); int maxBot = Mathf.Max(a.yMin, b.yMin); int width = minRight - maxLeft + 1; int height = minTop - maxBot + 1; intersection = new RectInt(maxLeft, maxBot, width, height); return(true); } }
public static bool RectIntCast(RectInt origin, Vector2Int delta, RectInt obstruction, out RectInt dst, out Vector2Int contactNormal, out RectInt overlapIntersection, bool debug = false) { if (delta == Vector2Int.zero) { contactNormal = Vector2Int.zero; if (TryGetRectIntersection(origin, obstruction, out overlapIntersection)) { dst = origin; return(true); } else { dst = origin; overlapIntersection = new RectInt(Vector2Int.zero, Vector2Int.zero); return(false); } } float strideWidth = (float)origin.width / 2; float strideHeight = (float)origin.height / 2; int slices = Mathf.Max( Mathf.CeilToInt((float)Mathf.Abs(delta.x) / strideWidth), Mathf.CeilToInt((float)Mathf.Abs(delta.y) / strideHeight) ); Vector2 floatStride = new Vector2(delta.x, delta.y) / slices; // Debug.LogFormat("float stride: {0}", floatStride); RectInt?overlapRect = null; RectInt coarseRect = new RectInt(0, 0, 0, 0); for (int i = 0; i < slices + 1; i++) { Vector2Int position = origin.position + Vector2Int.RoundToInt(i * floatStride); RectInt iterRect = new RectInt(position, origin.size); if (iterRect.Overlaps(obstruction)) { TryGetRectIntersection(iterRect, obstruction, out RectInt ol); overlapRect = ol; coarseRect = iterRect; break; } } if (overlapRect.HasValue == false) { dst = new RectInt(origin.position + delta, origin.size); contactNormal = Vector2Int.zero; overlapIntersection = new RectInt(); return(false); } var overlap = overlapRect.Value; overlapIntersection = overlap; if (debug) { Debug.LogFormat("Coarse rect: {0}", coarseRect); } if (debug) { Debug.LogFormat("Overlap rect: {0}", overlap); } // At this point, one of our rects overlapped // Use our delta, coarse rect, and overlap rect to back-out of overlapping Vector2Int backTrack = Vector2Int.zero; // fine-tune contact normal? right now just returns a cardinal dir or zero. contactNormal = Vector2Int.zero; { Vector2Int backtrackFromHorz = Vector2Int.zero; Vector2Int contactNormalFromHorz = Vector2Int.one; if (delta.x != 0) { float slope = (float)delta.y / delta.x; if (-delta.x > 0) { int rightResolve = 1 + overlap.TrueMax().x - coarseRect.x; backtrackFromHorz.x = rightResolve; backtrackFromHorz.y = Mathf.RoundToInt(rightResolve * slope); if (debug) { Debug.LogFormat("Right resolve: {0}. backtrackFromHorz: {1}", rightResolve, backtrackFromHorz); } contactNormalFromHorz = Vector2Int.right; } else { int leftResolve = -Mathf.Abs(coarseRect.TrueMax().x - overlap.x + 1); backtrackFromHorz.x = leftResolve; backtrackFromHorz.y = Mathf.RoundToInt(leftResolve * slope); if (debug) { Debug.LogFormat("Left resolve: {0}. backtrackFromHorz: {1}", leftResolve, backtrackFromHorz); } contactNormalFromHorz = Vector2Int.left; } } Vector2Int backtrackFromVert = Vector2Int.zero; Vector2Int contactNormalFromVert = Vector2Int.zero; if (delta.y != 0) { // Pure vertical float invSlope = (float)delta.x / delta.y; if (delta.y > 0) { int downResolve = -Mathf.Abs(coarseRect.TrueMax().y - overlap.y + 1); backtrackFromVert.y = downResolve; backtrackFromVert.x = Mathf.RoundToInt(downResolve * invSlope); if (debug) { Debug.LogFormat("Down resolve: {0}. backtrackFromVert: {1}.", downResolve, backtrackFromVert); } contactNormalFromVert = Vector2Int.down; } else { int upResolve = 1 + overlap.TrueMax().y - coarseRect.y; backtrackFromVert.y = upResolve; backtrackFromVert.x = Mathf.RoundToInt(upResolve * invSlope); if (debug) { Debug.LogFormat("Up resolve: {0}. backtrackFromVert: {1}", upResolve, backtrackFromVert); } contactNormalFromVert = Vector2Int.up; } } bool useVert = (Mathf.Abs(delta.y) > Mathf.Abs(delta.x)); backTrack = useVert ? backtrackFromVert : backtrackFromHorz; contactNormal = useVert ? contactNormalFromVert : contactNormalFromHorz; } // Note: we don't handle corner-to-corner collisions here^. if (debug) { Debug.LogFormat("backtrack: {0}", backTrack); } Vector2Int finalRectPos = coarseRect.position + backTrack; dst = new RectInt(finalRectPos, origin.size); if (debug) { Debug.LogFormat("Final rect: {0}", finalRectPos); } return(true); }