/// <summary>Test for intersection between two rectangles.</summary> /// <param name="a">First rectangle.</param> /// <param name="b">Second rectangle.</param> /// <returns></returns> public static bool Intersects(this TRectangle a, TRectangle b) { #if FARMATH // Move second rectangle to local coordinate system of first rectangle and // do a normal float check, for faster computation. Math.RectangleF la; la.X = 0; la.Y = 0; la.Width = a.Width; la.Height = a.Height; Math.RectangleF lb; lb.X = (float)(b.X - a.X); lb.Y = (float)(b.Y - a.Y); lb.Width = b.Width; lb.Height = b.Height; return(la.Intersects(lb)); #else var aLeft = a.X; var aTop = a.Y; var aRight = aLeft + a.Width; var aBottom = aTop + a.Height; var bLeft = b.X; var bTop = b.Y; var bRight = bLeft + b.Width; var bBottom = bTop + b.Height; return(aLeft <= bRight && aTop <= bBottom && aRight >= bLeft && aBottom >= bTop); #endif }
/// <summary>Reset the component to its initial state, so that it may be reused without side effects.</summary> public override void Reset() { base.Reset(); _indexId = 0; _bounds = WorldBounds.Empty; }
/// <summary>Initialize with the specified values.</summary> /// <param name="bounds">The bounds of the component.</param> /// <param name="indexId">The index.</param> /// <returns>This component.</returns> public Indexable Initialize(WorldBounds bounds, int indexId = 0) { Bounds = bounds; IndexId = indexId; return(this); }
/// <summary>Updates this fixtures position in the index structure used for the broad phase.</summary> /// <param name="transform1">The previous world transform of the body.</param> /// <param name="transform2">The new world transform of the body.</param> internal void Synchronize(WorldTransform transform1, WorldTransform transform2) { // Compute an AABB that covers the swept shape (may miss some rotation effect). var bounds = WorldBounds.Union(ComputeBounds(transform1), ComputeBounds(transform2)); // Compute the displacement of the shape. // ReSharper disable RedundantCast Necessary for FarPhysics. var delta = (Vector2)(transform2.Translation - transform1.Translation); // ReSharper restore RedundantCast // Update the index. IndexBoundsChanged message; message.Component = this; message.Bounds = bounds; message.Delta = delta; Manager.SendMessage(message); }
/// <summary>Test for intersection between rectangle and circle.</summary> /// <param name="rectangle">The rectangle.</param> /// <param name="center">The center.</param> /// <param name="radius">The radius.</param> /// <returns></returns> /// <remarks> /// This method assumes the bounds of the circle intersect the rectangle. It will still work otherwise, but it /// takes no steps to optimize in that regard, as it's normally assumed this is known and thus would be unnecessary /// work to check for. /// </remarks> public static bool Intersects(this TRectangle rectangle, TPoint center, float radius) { #if FARMATH // Translate rectangle to circle's local coordinate system and do normal // float check for faster computation. Math.RectangleF translated; translated.X = (float)(rectangle.X - center.X); translated.Y = (float)(rectangle.Y - center.Y); translated.Width = (float)rectangle.Width; translated.Height = (float)rectangle.Height; var zero = Microsoft.Xna.Framework.Vector2.Zero; return(translated.Intersects(zero, radius)); #else var boundsLeft = rectangle.X; var boundsTop = rectangle.Y; var boundsRight = boundsLeft + rectangle.Width; var boundsBottom = boundsTop + rectangle.Height; // Check for unaligned separation. var closest = center; if (closest.X < boundsLeft) { closest.X = boundsLeft; } else if (closest.X > boundsRight) { closest.X = boundsRight; } if (closest.Y < boundsTop) { closest.Y = boundsTop; } else if (closest.Y > boundsBottom) { closest.Y = boundsBottom; } // Got a closest point, check the distance. var distanceX = closest.X - center.X; var distanceY = closest.Y - center.Y; return((distanceX * distanceX + distanceY * distanceY) <= radius * radius); #endif }
/// <summary>Renders a graphical representation of this tree's cells using the specified shape renderer.</summary> /// <param name="tree">The tree to render.</param> /// <param name="shape">The shape renderer to paint with.</param> /// <param name="translation">The translation to apply to all draw operation.</param> public static void Draw <T>(this DynamicQuadTree <T> tree, AbstractShape shape, TPoint translation) { var screenBounds = new TRectangle(-5000, -5000, 10000, 10000); foreach (var node in tree.GetNodeEnumerable()) { var bounds = node.Item1; bounds.Offset(translation); // ReSharper disable RedundantCast Necessary for FarCollections. var center = (Vector2)bounds.Center; // ReSharper restore RedundantCast if (screenBounds.Intersects(bounds) && !bounds.Contains(screenBounds)) { shape.SetCenter(center.X, center.Y); shape.SetSize((int)bounds.Width - 1, (int)bounds.Height - 1); shape.Draw(); } // Check entries. foreach (var entry in node.Item2) { bounds = tree[entry]; bounds.Offset(translation); // ReSharper disable RedundantCast Necessary for FarCollections. center = (Vector2)bounds.Center; // ReSharper restore RedundantCast if (screenBounds.Intersects(bounds) && !bounds.Contains(screenBounds)) { shape.SetCenter(center.X, center.Y); shape.SetSize((int)bounds.Width, (int)bounds.Height); shape.Draw(); } } } }
/// <summary>Test for intersection between a rectangle and a line.</summary> /// <param name="rectangle">The rectangle.</param> /// <param name="a">Start of the line.</param> /// <param name="b">End of the line.</param> /// <param name="t">The fraction of the line to consider.</param> /// <param name="tHit">The fraction at which the intersection occurred.</param> /// <returns></returns> public static bool Intersects(this TRectangle rectangle, TPoint a, TPoint b, float t, out float tHit) { #if FARMATH // Move points to local coordinate system of rectangle and do normal float // check for faster computation. Math.RectangleF lr; lr.X = 0; lr.Y = 0; lr.Width = (float)rectangle.Width; lr.Height = (float)rectangle.Height; Microsoft.Xna.Framework.Vector2 la; la.X = (float)(a.X - rectangle.X); la.Y = (float)(a.Y - rectangle.Y); Microsoft.Xna.Framework.Vector2 lb; lb.X = (float)(b.X - rectangle.X); lb.Y = (float)(b.Y - rectangle.Y); return(lr.Intersects(la, lb, t, out tHit)); #else const float e = 1.192092896e-07f; tHit = 0f; var tMin = float.MinValue; var tMax = float.MaxValue; var left = rectangle.X; var right = left + rectangle.Width; // ReSharper disable RedundantCast Necessary for FarCollections. var dx = (float)(b.X - a.X); // ReSharper restore RedundantCast var parallelToYAxis = dx >= 0 ? (dx < e) : (dx > -e); if (parallelToYAxis) { // Parallel along the x axis, see if we're left or right of the rectangle. if (a.X < left || a.X > right) { // Outside the box. return(false); } } else { var inverseDistanceX = 1f / dx; // ReSharper disable RedundantCast Necessary for FarCollections. var t1 = (float)(left - a.X) * inverseDistanceX; var t2 = (float)(right - a.X) * inverseDistanceX; // ReSharper restore RedundantCast if (t1 > t2) { var tmp = t1; t1 = t2; t2 = tmp; } // Push the min up. if (t1 > tMin) { tMin = t1; } // Pull the max down. if (t2 < tMax) { tMax = t2; } if (tMin > tMax) { return(false); } } var top = rectangle.Y; var bottom = top + rectangle.Height; // ReSharper disable RedundantCast Necessary for FarCollections. var dy = (float)(b.Y - a.Y); // ReSharper restore RedundantCast var parallelToXAxis = dy >= 0 ? (dy < e) : (dy > -e); if (parallelToXAxis) { // Parallel along the y axis, see if we're above or below of the rectangle. if (a.Y < top || a.Y > bottom) { // Outside the box. return(false); } } else { var inverseDistanceY = 1f / dy; // ReSharper disable RedundantCast Necessary for FarCollections. var t1 = (float)(top - a.Y) * inverseDistanceY; var t2 = (float)(bottom - a.Y) * inverseDistanceY; // ReSharper restore RedundantCast if (t1 > t2) { var tmp = t1; t1 = t2; t2 = tmp; } // Push the min up. if (t1 > tMin) { tMin = t1; } // Pull the max down. if (t2 < tMax) { tMax = t2; } if (tMin > tMax) { return(false); } } // Set out value to intersection value. tHit = tMin; // See if we hit something in the allowed interval. return(tMin >= 0.0f && tMin < t); #endif }