/// <summary>
    /// Do the two rectangular prisms (defined by a center, size and rotation) overlap?
    /// </summary>
    /// <param name="r1Center"></param>
    /// <param name="r1Extents"></param>
    /// <param name="r1Rot"></param>
    /// <param name="r2Center"></param>
    /// <param name="r2Extents"></param>
    /// <param name="r2Rot"></param>
    /// <returns></returns>
    public static bool RectangularPrismOverlaps(Vector3 r1Center, Vector3 r1Extents, Quaternion r1Rot, Vector3 r2Center, Vector3 r2Extents, Quaternion r2Rot)
    {
        var invRot  = Quaternion.Inverse(r1Rot);
        var invRot2 = Quaternion.Inverse(r2Rot);

        var axisBounds = new Bounds(invRot * r1Center, r1Extents * 2);
        var invRotB    = new RotationalBounds(axisBounds.center + invRot * (r1Center - r2Center), r2Extents * 2, invRot * r2Rot);

#if CUSTOMDEBUG
        DebugHelper.DrawCube(axisBounds.center, axisBounds.extents, Quaternion.identity, Color.gray, 0);
        DebugHelper.DrawCube(invRotB.center, invRotB.extents, invRotB.rotation, Color.gray, 0);
#endif

        if (axisBounds.Contains(invRotB.center + invRotB.rotation * new Vector3(invRotB.extents.x, invRotB.extents.y, invRotB.extents.z)) ||
            axisBounds.Contains(invRotB.center + invRotB.rotation * new Vector3(invRotB.extents.x, -invRotB.extents.y, invRotB.extents.z)) ||
            axisBounds.Contains(invRotB.center + invRotB.rotation * new Vector3(invRotB.extents.x, invRotB.extents.y, -invRotB.extents.z)) ||
            axisBounds.Contains(invRotB.center + invRotB.rotation * new Vector3(invRotB.extents.x, -invRotB.extents.y, -invRotB.extents.z)) ||
            axisBounds.Contains(invRotB.center + invRotB.rotation * new Vector3(-invRotB.extents.x, invRotB.extents.y, invRotB.extents.z)) ||
            axisBounds.Contains(invRotB.center + invRotB.rotation * new Vector3(-invRotB.extents.x, -invRotB.extents.y, invRotB.extents.z)) ||
            axisBounds.Contains(invRotB.center + invRotB.rotation * new Vector3(-invRotB.extents.x, invRotB.extents.y, -invRotB.extents.z)) ||
            axisBounds.Contains(invRotB.center + invRotB.rotation * new Vector3(-invRotB.extents.x, -invRotB.extents.y, -invRotB.extents.z)))
        {
            return(true);
        }

        invRotB.ReduceToTriangles(_triangleCache);

        // Test x-axis aligned cube
        var xzRect = new Rect(axisBounds.min.xz(), axisBounds.size.xz());
#if CUSTOMDEBUG
        DebugHelper.DrawCube(new Vector3(xzRect.center.x, 0, xzRect.center.y), new Vector3(xzRect.width / 2, 0, xzRect.height / 2), Quaternion.identity, Color.black, 0);
#endif

        if (!OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[0].p1.xz(), _triangleCache[0].p2.xz(), _triangleCache[0].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[1].p1.xz(), _triangleCache[1].p2.xz(), _triangleCache[1].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[2].p1.xz(), _triangleCache[2].p2.xz(), _triangleCache[2].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[3].p1.xz(), _triangleCache[3].p2.xz(), _triangleCache[3].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[4].p1.xz(), _triangleCache[4].p2.xz(), _triangleCache[4].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[5].p1.xz(), _triangleCache[5].p2.xz(), _triangleCache[5].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[6].p1.xz(), _triangleCache[6].p2.xz(), _triangleCache[6].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[7].p1.xz(), _triangleCache[7].p2.xz(), _triangleCache[7].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[8].p1.xz(), _triangleCache[8].p2.xz(), _triangleCache[8].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[9].p1.xz(), _triangleCache[0].p2.xz(), _triangleCache[9].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[10].p1.xz(), _triangleCache[10].p2.xz(), _triangleCache[10].p3.xz(), xzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[11].p1.xz(), _triangleCache[11].p2.xz(), _triangleCache[11].p3.xz(), xzRect))
        {
#if CUSTOMDEBUG
            foreach (var triangle in _triangleCache)
            {
                Debug.DrawLine(triangle.p1.x0z(), triangle.p2.x0z(), Color.red);
                Debug.DrawLine(triangle.p2.x0z(), triangle.p3.x0z(), Color.red);
                Debug.DrawLine(triangle.p3.x0z(), triangle.p1.x0z(), Color.red);
            }
#endif
            return(false);
        }
#if CUSTOMDEBUG
        else
        {
            foreach (var triangle in _triangleCache)
            {
                Debug.DrawLine(triangle.p1.x0z(), triangle.p2.x0z(), Color.green);
                Debug.DrawLine(triangle.p2.x0z(), triangle.p3.x0z(), Color.green);
                Debug.DrawLine(triangle.p3.x0z(), triangle.p1.x0z(), Color.green);
            }
        }
#endif

        var xyRect = new Rect(axisBounds.min.xy(), axisBounds.size.xy());
#if CUSTOMDEBUG
        DebugHelper.DrawCube(new Vector3(xyRect.center.x, xyRect.center.y, 0), new Vector3(xyRect.width / 2, xyRect.height / 2, 0), Quaternion.identity, Color.black, 0);
#endif
        if (!OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[0].p1.xy(), _triangleCache[0].p2.xy(), _triangleCache[0].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[1].p1.xy(), _triangleCache[1].p2.xy(), _triangleCache[1].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[2].p1.xy(), _triangleCache[2].p2.xy(), _triangleCache[2].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[3].p1.xy(), _triangleCache[3].p2.xy(), _triangleCache[3].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[4].p1.xy(), _triangleCache[4].p2.xy(), _triangleCache[4].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[5].p1.xy(), _triangleCache[5].p2.xy(), _triangleCache[5].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[6].p1.xy(), _triangleCache[6].p2.xy(), _triangleCache[6].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[7].p1.xy(), _triangleCache[7].p2.xy(), _triangleCache[7].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[8].p1.xy(), _triangleCache[8].p2.xy(), _triangleCache[8].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[9].p1.xy(), _triangleCache[0].p2.xy(), _triangleCache[9].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[10].p1.xy(), _triangleCache[10].p2.xy(), _triangleCache[10].p3.xy(), xyRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[11].p1.xy(), _triangleCache[11].p2.xy(), _triangleCache[11].p3.xy(), xyRect))
        {
#if CUSTOMDEBUG
            foreach (var triangle in _triangleCache)
            {
                Debug.DrawLine(triangle.p1.xy0(), triangle.p2.xy0(), Color.red);
                Debug.DrawLine(triangle.p2.xy0(), triangle.p3.xy0(), Color.red);
                Debug.DrawLine(triangle.p3.xy0(), triangle.p1.xy0(), Color.red);
            }
#endif
            return(false);
        }
#if CUSTOMDEBUG
        else
        {
            foreach (var triangle in _triangleCache)
            {
                Debug.DrawLine(triangle.p1.xy0(), triangle.p2.xy0(), Color.green);
                Debug.DrawLine(triangle.p2.xy0(), triangle.p3.xy0(), Color.green);
                Debug.DrawLine(triangle.p3.xy0(), triangle.p1.xy0(), Color.green);
            }
        }
#endif

        var yzRect = new Rect(axisBounds.min.yz(), axisBounds.size.yz());
#if CUSTOMDEBUG
        DebugHelper.DrawCube(new Vector3(0, yzRect.center.x, yzRect.center.y), new Vector3(0, yzRect.width / 2, yzRect.height / 2), Quaternion.identity, Color.black, 0);
#endif
        if (!OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[0].p1.yz(), _triangleCache[0].p2.yz(), _triangleCache[0].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[1].p1.yz(), _triangleCache[1].p2.yz(), _triangleCache[1].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[2].p1.yz(), _triangleCache[2].p2.yz(), _triangleCache[2].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[3].p1.yz(), _triangleCache[3].p2.yz(), _triangleCache[3].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[4].p1.yz(), _triangleCache[4].p2.yz(), _triangleCache[4].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[5].p1.yz(), _triangleCache[5].p2.yz(), _triangleCache[5].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[6].p1.yz(), _triangleCache[6].p2.yz(), _triangleCache[6].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[7].p1.yz(), _triangleCache[7].p2.yz(), _triangleCache[7].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[8].p1.yz(), _triangleCache[8].p2.yz(), _triangleCache[8].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[9].p1.yz(), _triangleCache[0].p2.yz(), _triangleCache[9].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[10].p1.yz(), _triangleCache[10].p2.yz(), _triangleCache[10].p3.yz(), yzRect) &&
            !OverlapUtilites2D.TriangleOverlapsRect(_triangleCache[11].p1.yz(), _triangleCache[11].p2.yz(), _triangleCache[11].p3.yz(), yzRect))
        {
#if CUSTOMDEBUG
            foreach (var triangle in _triangleCache)
            {
                Debug.DrawLine(triangle.p1.x0yz(), triangle.p2.x0yz(), Color.red);
                Debug.DrawLine(triangle.p2.x0yz(), triangle.p3.x0yz(), Color.red);
                Debug.DrawLine(triangle.p3.x0yz(), triangle.p1.x0yz(), Color.red);
            }
#endif
            return(false);
        }
#if CUSTOMDEBUG
        else
        {
            foreach (var triangle in _triangleCache)
            {
                Debug.DrawLine(triangle.p1.x0yz(), triangle.p2.x0yz(), Color.green);
                Debug.DrawLine(triangle.p2.x0yz(), triangle.p3.x0yz(), Color.green);
                Debug.DrawLine(triangle.p3.x0yz(), triangle.p1.x0yz(), Color.green);
            }
        }
#endif

        return(true);
    }