/// <summary> /// Given a transform, compute the associated axis aligned bounding box for a child shape. /// </summary> /// <param name="aabb">The aabb results.</param> /// <param name="transform">The world transform of the shape.</param> /// <param name="childIndex">The child shape index.</param> public override void ComputeAABB(out AABB aabb, ref Transform transform, int childIndex) { Vector2 v1 = MathUtils.Multiply(ref transform, _vertex1); Vector2 v2 = MathUtils.Multiply(ref transform, _vertex2); Vector2 lower = Vector2.Min(v1, v2); Vector2 upper = Vector2.Max(v1, v2); Vector2 r = new Vector2(Radius, Radius); aabb.LowerBound = lower - r; aabb.UpperBound = upper + r; }
/// <summary> /// Given a transform, compute the associated axis aligned bounding box for a child shape. /// </summary> /// <param name="aabb">The aabb results.</param> /// <param name="transform">The world transform of the shape.</param> /// <param name="childIndex">The child shape index.</param> public override void ComputeAABB(out AABB aabb, ref Transform transform, int childIndex) { Vector2 lower = MathUtils.Multiply(ref transform, Vertices[0]); Vector2 upper = lower; for (int i = 1; i < Vertices.Count; ++i) { Vector2 v = MathUtils.Multiply(ref transform, Vertices[i]); lower = Vector2.Min(lower, v); upper = Vector2.Max(upper, v); } Vector2 r = new Vector2(Radius, Radius); aabb.LowerBound = lower - r; aabb.UpperBound = upper + r; }
/// <summary> /// Given a transform, compute the associated axis aligned bounding box for a child shape. /// </summary> /// <param name="aabb">The aabb results.</param> /// <param name="transform">The world transform of the shape.</param> /// <param name="childIndex">The child shape index.</param> public override void ComputeAABB(out AABB aabb, ref Transform transform, int childIndex) { Debug.Assert(childIndex < Vertices.Count); int i1 = childIndex; int i2 = childIndex + 1; if (i2 == Vertices.Count) { i2 = 0; } Vector2 v1 = MathUtils.Multiply(ref transform, Vertices[i1]); Vector2 v2 = MathUtils.Multiply(ref transform, Vertices[i2]); aabb.LowerBound = Vector2.Min(v1, v2); aabb.UpperBound = Vector2.Max(v1, v2); }
public static Vector2 Clamp(Vector2 a, Vector2 low, Vector2 high) { return(Vector2.Max(low, Vector2.Min(a, high))); }
/// <summary> /// Ray-cast against the proxies in the tree. This relies on the callback /// to perform a exact ray-cast in the case were the proxy contains a Shape. /// The callback also performs the any collision filtering. This has performance /// roughly equal to k * log(n), where k is the number of collisions and n is the /// number of proxies in the tree. /// </summary> /// <param name="callback">A callback class that is called for each proxy that is hit by the ray.</param> /// <param name="input">The ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).</param> public void RayCast(Func <RayCastInput, int, float> callback, ref RayCastInput input) { Vector2 p1 = input.Point1; Vector2 p2 = input.Point2; Vector2 r = p2 - p1; Debug.Assert(r.sqrMagnitude > 0.0f); r.Normalize(); // v is perpendicular to the segment. Vector2 absV = MathUtils.Abs(new Vector2(-r.y, r.x)); // Separating axis for segment (Gino, p80). // |dot(v, p1 - c)| > dot(|v|, h) float maxFraction = input.MaxFraction; // Build a bounding box for the segment. AABB segmentAABB = new AABB(); { Vector2 t = p1 + maxFraction * (p2 - p1); VectorMath.Min(ref p1, ref t, out segmentAABB.LowerBound); VectorMath.Max(ref p1, ref t, out segmentAABB.UpperBound); } _stack.Clear(); _stack.Push(_root); while (_stack.Count > 0) { int nodeId = _stack.Pop(); if (nodeId == NullNode) { continue; } DynamicTreeNode <T> node = _nodes[nodeId]; if (AABB.TestOverlap(ref node.AABB, ref segmentAABB) == false) { continue; } // Separating axis for segment (Gino, p80). // |dot(v, p1 - c)| > dot(|v|, h) Vector2 c = node.AABB.Center; Vector2 h = node.AABB.Extents; float separation = Math.Abs(Vector2.Dot(new Vector2(-r.y, r.x), p1 - c)) - Vector2.Dot(absV, h); if (separation > 0.0f) { continue; } if (node.IsLeaf()) { RayCastInput subInput; subInput.Point1 = input.Point1; subInput.Point2 = input.Point2; subInput.MaxFraction = maxFraction; float value = callback(subInput, nodeId); if (value == 0.0f) { // the client has terminated the raycast. return; } if (value > 0.0f) { // Update segment bounding box. maxFraction = value; Vector2 t = p1 + maxFraction * (p2 - p1); segmentAABB.LowerBound = Vector2.Min(p1, t); segmentAABB.UpperBound = Vector2.Max(p1, t); } } else { _stack.Push(node.Child1); _stack.Push(node.Child2); } } }