/// <summary> /// Indicates whether or not the given shape is contained entirely within this cylinder (no part of the <paramref name="other"/> /// shape may be outside this one). /// </summary> /// <param name="other">The shape to check.</param> /// <returns>True if the other shape is completely within this cylinder, false if any part of it /// is outside the cylinder.</returns> public bool Contains(Cuboid other) { float halfHeight = Height / 2f; float errorMargin = MathUtils.FlopsErrorMargin; return(Contains(other.GetCorner(Cuboid.CuboidCorner.FrontTopLeft)) && Contains(other.GetCorner(Cuboid.CuboidCorner.FrontTopRight)) && Contains(other.GetCorner(Cuboid.CuboidCorner.BackTopLeft)) && Contains(other.GetCorner(Cuboid.CuboidCorner.BackTopRight)) && other.FrontBottomLeft.Y + other.Height <= Center.Y + halfHeight + errorMargin && other.FrontBottomLeft.Y + errorMargin >= Center.Y - halfHeight); }
/// <summary> /// Indicates whether the <paramref name="cuboid"/> intersects (crosses) this plane at any point. /// </summary> /// <param name="cuboid">The cuboid to test.</param> /// <returns>True if the cuboid intersects this plane (or touches it), false if not.</returns> public bool Intersects(Cuboid cuboid) { PointPlaneRelationship firstPointLocation = LocationOf(cuboid.GetCorner((Cuboid.CuboidCorner) 0)); for (int i = 1; i < Cuboid.NUM_CORNERS; ++i) { if (LocationOf(cuboid.GetCorner((Cuboid.CuboidCorner)i)) != firstPointLocation) { return(true); } } return(false); }
/// <summary> /// Indicates the shortest distance from the edge of the given shape to the edge of this sphere. /// </summary> /// <param name="other">The shape to check.</param> /// <returns>The shortest distance connecting the outer-edges of both shapes. /// If the shapes intersect, <c>0f</c> will be returned.</returns> public float DistanceFrom(Cuboid other) { if (Intersects(other)) { return(0f); } float distanceX = Math.Max(Math.Abs( Center.X - (float)MathUtils.Clamp(Center.X, other.FrontBottomLeft.X, other.FrontBottomLeft.X + other.Width)) - Radius, 0f); float distanceY = Math.Max(Math.Abs( Center.Y - (float)MathUtils.Clamp(Center.Y, other.FrontBottomLeft.Y, other.FrontBottomLeft.Y + other.Height)) - Radius, 0f); float distanceZ = Math.Max(Math.Abs( Center.Z - (float)MathUtils.Clamp(Center.Z, other.FrontBottomLeft.Z, other.FrontBottomLeft.Z + other.Depth)) - Radius, 0f); return((float)Math.Sqrt(distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ)); }
/// <summary> /// Indicates whether or not the given shape is contained entirely within this sphere (no part of the <paramref name="other"/> /// shape may be outside this one). /// </summary> /// <param name="other">The shape to check.</param> /// <returns>True if the other shape is completely within this sphere, false if any part of it /// is outside the sphere.</returns> public bool Contains(Cuboid other) { float errorMarginSq = MathUtils.FlopsErrorMargin; errorMarginSq *= errorMarginSq; float radiusSq = Radius * Radius; for (int i = 0; i < Cuboid.NUM_CORNERS; ++i) { if (Vector3.DistanceSquared(Center, other.GetCorner((Cuboid.CuboidCorner)i)) > radiusSq + errorMarginSq) { return(false); } } return(true); }
/// <summary> /// Gets the shortest distance from this plane to the <paramref name="cuboid"/>'s outer edge. /// </summary> /// <param name="cuboid">The cuboid to get the distance to.</param> /// <returns>The distance of the shortest path from the cuboid's edge (not its centre) to this plane, or /// <c>0f</c> if there is an intersection.</returns> public float DistanceFrom(Cuboid cuboid) { if (Intersects(cuboid)) { return(0f); } float min = Single.MaxValue; for (int i = 0; i < Cuboid.NUM_CORNERS; ++i) { min = Math.Min(min, DistanceFrom(cuboid.GetCorner((Cuboid.CuboidCorner)i))); } return(min); }
/// <summary> /// Indicates whether or not the given shape is contained entirely within this cone (no part of the <paramref name="other"/> /// shape may be outside this one). /// </summary> /// <param name="other">The shape to check.</param> /// <returns>True if the other shape is completely within this cone, false if any part of it /// is outside the cone.</returns> public bool Contains(Cuboid other) { float errorMargin = MathUtils.FlopsErrorMargin; if (other.FrontBottomLeft.Y + errorMargin < TopCenter.Y - Height || other.FrontBottomLeft.Y + other.Height > TopCenter.Y + errorMargin) { return(false); } if (BottomRadius > TopRadius) { return(Contains(other.GetCorner(Cuboid.CuboidCorner.FrontTopLeft)) && Contains(other.GetCorner(Cuboid.CuboidCorner.BackTopRight))); } else { return(Contains(other.GetCorner(Cuboid.CuboidCorner.FrontBottomLeft)) && Contains(other.GetCorner(Cuboid.CuboidCorner.BackBottomRight))); } }
/// <summary> /// Indicates whether any portion of this cylinder and the <paramref name="other"/> shape overlap. /// </summary> /// <param name="other">The shape to check against this one.</param> /// <returns>True if any part of both shapes overlap, false if they are entirely separate.</returns> public bool Intersects(Cuboid other) { return(other.Intersects(this)); }
/// <summary> /// Determines the first point on the cuboid that is touched by this ray. /// </summary> /// <param name="other">The cuboid to test for intersection with this ray.</param> /// <returns>A <see cref="Vector3"/> indicating the first point on the cuboid edge touched by this ray, /// or <c>null</c> if no intersection occurs.</returns> // Based on "Fast Ray-Box Intersection" algorithm by Andrew Woo, "Graphics Gems", Academic Press, 1990 public unsafe Vector3?IntersectionWith(Cuboid other) { const int NUM_DIMENSIONS = 3; Assure.Equal(NUM_DIMENSIONS, 3); // If that value is ever changed, this algorithm will need some maintenance const byte QUADRANT_MIN = 0; const byte QUADRANT_MAX = 1; const byte QUADRANT_BETWEEN = 2; // Step 1: Work out which direction from the start point to test for intersection for all 3 dimensions, and the distance byte * quadrants = stackalloc byte[NUM_DIMENSIONS]; float *candidatePlanes = stackalloc float[NUM_DIMENSIONS]; float *cuboidMinPoints = stackalloc float[NUM_DIMENSIONS]; float *cuboidMaxPoints = stackalloc float[NUM_DIMENSIONS]; bool startPointIsInsideCuboid = true; cuboidMinPoints[0] = other.FrontBottomLeft.X; cuboidMinPoints[1] = other.FrontBottomLeft.Y; cuboidMinPoints[2] = other.FrontBottomLeft.Z; cuboidMaxPoints[0] = other.FrontBottomLeft.X + other.Width; cuboidMaxPoints[1] = other.FrontBottomLeft.Y + other.Height; cuboidMaxPoints[2] = other.FrontBottomLeft.Z + other.Depth; for (byte i = 0; i < NUM_DIMENSIONS; ++i) { if (StartPoint[i] < cuboidMinPoints[i]) { quadrants[i] = QUADRANT_MIN; candidatePlanes[i] = cuboidMinPoints[i]; startPointIsInsideCuboid = false; } else if (StartPoint[i] > cuboidMaxPoints[i]) { quadrants[i] = QUADRANT_MAX; candidatePlanes[i] = cuboidMaxPoints[i]; startPointIsInsideCuboid = false; } else { quadrants[i] = QUADRANT_BETWEEN; } } if (startPointIsInsideCuboid) { return(StartPoint); } // Step 2: Find farthest dimension from cuboid float maxDistance = Single.NegativeInfinity; byte maxDistanceDimension = 0; for (byte i = 0; i < NUM_DIMENSIONS; ++i) { // ReSharper disable once CompareOfFloatsByEqualityOperator Exact check is desired here: Anything other than 0f is usable if (quadrants[i] != QUADRANT_BETWEEN && Orientation[i] != 0f) { float thisDimensionDist = (candidatePlanes[i] - StartPoint[i]) / Orientation[i]; if (thisDimensionDist > maxDistance) { maxDistance = thisDimensionDist; maxDistanceDimension = i; } } } float errorMargin = MathUtils.FlopsErrorMargin; if (maxDistance < 0f || maxDistance - Length > errorMargin) { return(null); } // Step 3: Find potential intersection point float *intersectionPoint = stackalloc float[NUM_DIMENSIONS]; for (byte i = 0; i < NUM_DIMENSIONS; ++i) { if (maxDistanceDimension == i) { intersectionPoint[i] = StartPoint[i] + maxDistance * Orientation[i]; if (cuboidMinPoints[i] - intersectionPoint[i] > errorMargin || intersectionPoint[i] - cuboidMaxPoints[i] > errorMargin) { return(null); } } else { intersectionPoint[i] = candidatePlanes[i]; } } Vector3 result = new Vector3(intersectionPoint[0], intersectionPoint[1], intersectionPoint[2]); if (!IsInfiniteLength && Vector3.DistanceSquared(StartPoint, result) > Length * Length + errorMargin * errorMargin) { return(null); } else if (!Contains(result)) { return(null); } else { return(result); } }