/// <summary> /// Checks a ray against a circle with a given origin and square radius. /// </summary> internal static bool CircleRayCast( VoltShape shape, Vector2 shapeOrigin, float sqrRadius, ref VoltRayCast ray, ref VoltRayResult result) { Vector2 toOrigin = shapeOrigin - ray.origin; if (toOrigin.sqrMagnitude < sqrRadius) { result.SetContained(shape); return true; } float slope = Vector2.Dot(toOrigin, ray.direction); if (slope < 0) return false; float sqrSlope = slope * slope; float d = sqrRadius + sqrSlope - Vector2.Dot(toOrigin, toOrigin); if (d < 0) return false; float dist = slope - Mathf.Sqrt(d); if (dist < 0 || dist > ray.distance) return false; // N.B.: For historical raycasts this normal will be wrong! // Must be either transformed back to world or invalidated later. Vector2 normal = (dist * ray.direction - toOrigin).normalized; result.Set(shape, dist, normal); return true; }
/// <summary> /// Checks a ray against a circle with a given origin and square radius. /// </summary> internal static bool CircleRayCast( VoltShape shape, Vector2 shapeOrigin, float sqrRadius, ref VoltRayCast ray, ref VoltRayResult result) { Vector2 toOrigin = shapeOrigin - ray.origin; if (toOrigin.sqrMagnitude < sqrRadius) { result.SetContained(shape); return(true); } float slope = Vector2.Dot(toOrigin, ray.direction); if (slope < 0) { return(false); } float sqrSlope = slope * slope; float d = sqrRadius + sqrSlope - Vector2.Dot(toOrigin, toOrigin); if (d < 0) { return(false); } float dist = slope - Mathf.Sqrt(d); if (dist < 0 || dist > ray.distance) { return(false); } // N.B.: For historical raycasts this normal will be wrong! // Must be either transformed back to world or invalidated later. Vector2 normal = (dist * ray.direction - toOrigin).normalized; result.Set(shape, dist, normal); return(true); }
private bool CircleCastEdges( ref VoltRayCast bodySpaceRay, float radius, ref VoltRayResult result) { int foundIndex = -1; bool couldBeContained = true; // Pre-compute and initialize values float shortestDist = float.MaxValue; Vector2 v3 = bodySpaceRay.direction.Left(); // Check the edges -- this will be different from the raycast because // we care about staying within the ends of the edge line segment for (int i = 0; i < this.countBody; i++) { Axis curAxis = this.bodyAxes[i]; // Push the edges out by the radius Vector2 extension = curAxis.Normal * radius; Vector2 a = this.bodyVertices[i] + extension; Vector2 b = this.bodyVertices[(i + 1) % this.countBody] + extension; // Update the check for containment if (couldBeContained == true) { float proj = Vector2.Dot(curAxis.Normal, bodySpaceRay.origin) - curAxis.Width; // The point lies outside of the outer layer if (proj > radius) { couldBeContained = false; } // The point lies between the outer and inner layer else if (proj > 0.0f) { // See if the point is within the center Vornoi region of the edge float d = VoltMath.Cross(curAxis.Normal, bodySpaceRay.origin); if (d > VoltMath.Cross(curAxis.Normal, a)) { couldBeContained = false; } if (d < VoltMath.Cross(curAxis.Normal, b)) { couldBeContained = false; } } } // For the cast, only consider rays pointing towards the edge if (Vector2.Dot(curAxis.Normal, bodySpaceRay.direction) >= 0.0f) { continue; } // See: // https://rootllama.wordpress.com/2014/06/20/ray-line-segment-intersection-test-in-2d/ Vector2 v1 = bodySpaceRay.origin - a; Vector2 v2 = b - a; float denominator = Vector2.Dot(v2, v3); float t1 = VoltMath.Cross(v2, v1) / denominator; float t2 = Vector2.Dot(v1, v3) / denominator; if ((t2 >= 0.0f) && (t2 <= 1.0f) && (t1 > 0.0f) && (t1 < shortestDist)) { // See if the point is outside of any of the axes shortestDist = t1; foundIndex = i; } } // Report results if (couldBeContained == true) { result.SetContained(this); return(true); } else if (foundIndex >= 0 && shortestDist <= bodySpaceRay.distance) { result.Set( this, shortestDist, this.bodyAxes[foundIndex].Normal); return(true); } return(false); }
protected override bool ShapeRayCast( ref VoltRayCast bodySpaceRay, ref VoltRayResult result) { int foundIndex = -1; float inner = float.MaxValue; float outer = 0; bool couldBeContained = true; for (int i = 0; i < this.countBody; i++) { Axis curAxis = this.bodyAxes[i]; // Distance between the ray origin and the axis/edge along the // normal (i.e., shortest distance between ray origin and the edge) float proj = Vector2.Dot(curAxis.Normal, bodySpaceRay.origin) - curAxis.Width; // See if the point is outside of any of the axes if (proj > 0.0f) { couldBeContained = false; } // Projection of the ray direction onto the axis normal (use // negative normal because we want to get the penetration length) float slope = Vector2.Dot(-curAxis.Normal, bodySpaceRay.direction); if (slope == 0.0f) { continue; } float dist = proj / slope; // The ray is pointing opposite the edge normal (towards the edge) if (slope > 0.0f) { if (dist > inner) { return(false); } if (dist > outer) { outer = dist; foundIndex = i; } } // The ray is pointing along the edge normal (away from the edge) else { if (dist < outer) { return(false); } if (dist < inner) { inner = dist; } } } if (couldBeContained == true) { result.SetContained(this); return(true); } else if (foundIndex >= 0 && outer <= bodySpaceRay.distance) { result.Set( this, outer, this.bodyAxes[foundIndex].Normal); return(true); } return(false); }
private bool CircleCastEdges( ref VoltRayCast bodySpaceRay, float radius, ref VoltRayResult result) { int foundIndex = -1; bool couldBeContained = true; // Pre-compute and initialize values float shortestDist = float.MaxValue; Vector2 v3 = bodySpaceRay.direction.Left(); // Check the edges -- this will be different from the raycast because // we care about staying within the ends of the edge line segment for (int i = 0; i < this.countBody; i++) { Axis curAxis = this.bodyAxes[i]; // Push the edges out by the radius Vector2 extension = curAxis.Normal * radius; Vector2 a = this.bodyVertices[i] + extension; Vector2 b = this.bodyVertices[(i + 1) % this.countBody] + extension; // Update the check for containment if (couldBeContained == true) { float proj = Vector2.Dot(curAxis.Normal, bodySpaceRay.origin) - curAxis.Width; // The point lies outside of the outer layer if (proj > radius) { couldBeContained = false; } // The point lies between the outer and inner layer else if (proj > 0.0f) { // See if the point is within the center Vornoi region of the edge float d = VoltMath.Cross(curAxis.Normal, bodySpaceRay.origin); if (d > VoltMath.Cross(curAxis.Normal, a)) couldBeContained = false; if (d < VoltMath.Cross(curAxis.Normal, b)) couldBeContained = false; } } // For the cast, only consider rays pointing towards the edge if (Vector2.Dot(curAxis.Normal, bodySpaceRay.direction) >= 0.0f) continue; // See: // https://rootllama.wordpress.com/2014/06/20/ray-line-segment-intersection-test-in-2d/ Vector2 v1 = bodySpaceRay.origin - a; Vector2 v2 = b - a; float denominator = Vector2.Dot(v2, v3); float t1 = VoltMath.Cross(v2, v1) / denominator; float t2 = Vector2.Dot(v1, v3) / denominator; if ((t2 >= 0.0f) && (t2 <= 1.0f) && (t1 > 0.0f) && (t1 < shortestDist)) { // See if the point is outside of any of the axes shortestDist = t1; foundIndex = i; } } // Report results if (couldBeContained == true) { result.SetContained(this); return true; } else if (foundIndex >= 0 && shortestDist <= bodySpaceRay.distance) { result.Set( this, shortestDist, this.bodyAxes[foundIndex].Normal); return true; } return false; }
protected override bool ShapeRayCast( ref VoltRayCast bodySpaceRay, ref VoltRayResult result) { int foundIndex = -1; float inner = float.MaxValue; float outer = 0; bool couldBeContained = true; for (int i = 0; i < this.countBody; i++) { Axis curAxis = this.bodyAxes[i]; // Distance between the ray origin and the axis/edge along the // normal (i.e., shortest distance between ray origin and the edge) float proj = Vector2.Dot(curAxis.Normal, bodySpaceRay.origin) - curAxis.Width; // See if the point is outside of any of the axes if (proj > 0.0f) couldBeContained = false; // Projection of the ray direction onto the axis normal (use // negative normal because we want to get the penetration length) float slope = Vector2.Dot(-curAxis.Normal, bodySpaceRay.direction); if (slope == 0.0f) continue; float dist = proj / slope; // The ray is pointing opposite the edge normal (towards the edge) if (slope > 0.0f) { if (dist > inner) { return false; } if (dist > outer) { outer = dist; foundIndex = i; } } // The ray is pointing along the edge normal (away from the edge) else { if (dist < outer) { return false; } if (dist < inner) { inner = dist; } } } if (couldBeContained == true) { result.SetContained(this); return true; } else if (foundIndex >= 0 && outer <= bodySpaceRay.distance) { result.Set( this, outer, this.bodyAxes[foundIndex].Normal); return true; } return false; }