public IntersectKey(PartFromPrefab partA, PartFromPrefab partB, MatrixI transformAB, bool testOptional)
 {
     m_partA        = partA;
     m_partB        = partB;
     m_transformAB  = transformAB;
     m_testOptional = testOptional;
 }
        public static bool Intersects(ref PartFromPrefab partA, ref MatrixI transformA, ref MatrixI invTransformA, ref PartFromPrefab partB, ref MatrixI transformB, ref MatrixI invTransformB, bool testOptional, bool testQuick = false)
        {
            var cheapResult = IntersectsInternalCheap(ref partA, ref transformA, ref invTransformA, ref partB, ref transformB, ref invTransformB, testOptional);

            switch (cheapResult)
            {
            case CheapIntersection.Yes:
                return(true);

            case CheapIntersection.No:
                return(false);

            case CheapIntersection.Maybe:
            default:
                break;
            }
            if (testQuick)
            {
                return(true);
            }

            MatrixI abTransform;

            MatrixI.Multiply(ref transformA, ref invTransformB, out abTransform);
            var  key = new IntersectKey(partA, partB, abTransform, testOptional);
            bool result;

            // ReSharper disable once ConvertIfStatementToReturnStatement
            // TODO when threading cause a wait when another thread is preparing this cache value?
            if (IntersectionCache.TryGet(key, out result))
            {
                return(result);
            }
            return(IntersectionCache.Store(key, IntersectsInternalExpensive(ref partA, ref transformA, ref invTransformA, ref partB, ref transformB, ref invTransformB, testOptional)));
        }
        private static bool IntersectsInternalExpensive(ref PartFromPrefab partA, ref MatrixI transformA, ref MatrixI invTransformA, ref PartFromPrefab partB, ref MatrixI transformB, ref MatrixI invTransformB, bool testOptional)
        {
            using (partA.LockSharedUsing())
                using (partB.LockSharedUsing())
                {
                    var reservedAAll = Utilities.TransformBoundingBox(partA.ReservedSpace, ref transformA);
                    var reservedBAll = Utilities.TransformBoundingBox(partB.ReservedSpace, ref transformB);

                    var reservedA = new List <MyTuple <ReservedSpace, BoundingBox> >(partA.m_reservedSpaces.Count);
                    // ReSharper disable once LoopCanBeConvertedToQuery (preserve ref)
                    foreach (var aabb in partA.m_reservedSpaces)
                    {
                        if (!aabb.IsOptional || testOptional)
                        {
                            reservedA.Add(MyTuple.Create(aabb, Utilities.TransformBoundingBox(aabb.Box, ref transformA)));
                        }
                    }

                    var reservedB = new List <MyTuple <ReservedSpace, BoundingBox> >(partB.m_reservedSpaces.Count);
                    // ReSharper disable once LoopCanBeConvertedToQuery (preserve ref)
                    foreach (var aabb in partB.m_reservedSpaces)
                    {
                        if (!aabb.IsOptional || testOptional)
                        {
                            reservedB.Add(MyTuple.Create(aabb, Utilities.TransformBoundingBox(aabb.Box, ref transformB)));
                        }
                    }

                    // Reserved spaces intersect?
                    if (partA.m_reservedSpaces.Count > 0 && partB.m_reservedSpaces.Count > 0 && reservedAAll.Intersects(reservedBAll))
                    {
                        if (reservedA.Any(x => reservedB.Any(y => !y.Item1.IsShared && !x.Item1.IsShared && x.Item2.Intersects(y.Item2))))
                        {
                            return(true);
                        }
                    }

                    var blockAAll = Utilities.TransformBoundingBox(partA.BoundingBox, ref transformA);
                    var blockBAll = Utilities.TransformBoundingBox(partB.BoundingBox, ref transformB);

                    // Block spaces intersect with reserved space?
                    if (partA.m_reservedSpaces.Count > 0 && reservedAAll.Intersects(blockBAll))
                    {
                        foreach (var aabb in reservedA)
                        {
                            var min = Vector3I.Floor(Vector3.Max(aabb.Item2.Min, blockBAll.Min));
                            var max = Vector3I.Ceiling(Vector3.Min(aabb.Item2.Max, blockBAll.Max));
                            for (var vi = new Vector3I_RangeIterator(ref min, ref max); vi.IsValid(); vi.MoveNext())
                            {
                                if (partB.CubeExists(Vector3I.Transform(vi.Current, invTransformB)))
                                {
                                    return(true);
                                }
                            }
                        }
                    }
                    if (partB.m_reservedSpaces.Count > 0 && reservedBAll.Intersects(blockAAll))
                    {
                        foreach (var aabb in reservedB)
                        {
                            var min = Vector3I.Floor(Vector3.Max(aabb.Item2.Min, blockAAll.Min));
                            var max = Vector3I.Ceiling(Vector3.Min(aabb.Item2.Max, blockAAll.Max));
                            for (var vi = new Vector3I_RangeIterator(ref min, ref max); vi.IsValid(); vi.MoveNext())
                            {
                                if (partA.CubeExists(Vector3I.Transform(vi.Current, invTransformA)))
                                {
                                    return(true);
                                }
                            }
                        }
                    }

                    // Block space intersects with block space?
                    if (!blockAAll.Intersects(blockBAll))
                    {
                        return(false);
                    }
                    if (partA.m_blocks.Count < partB.m_blocks.Count)
                    {
                        foreach (var pos in partA.m_blocks.Keys)
                        {
                            if (partB.CubeExists(Vector3I.Transform(Vector3I.Transform(pos, ref transformA), ref invTransformB)))
                            {
                                return(true);
                            }
                        }
                    }
                    else
                    {
                        foreach (var pos in partB.m_blocks.Keys)
                        {
                            if (partA.CubeExists(Vector3I.Transform(Vector3I.Transform(pos, ref transformB), ref invTransformA)))
                            {
                                return(true);
                            }
                        }
                    }
                    return(false);
                }
        }
 public static bool Intersects(PartFromPrefab partA, MatrixI transformA, MatrixI invTransformA, ref PartFromPrefab partB, ref MatrixI transformB, ref MatrixI invTransformB, bool testOptional, bool testQuick = false)
 {
     return(Intersects(ref partA, ref transformA, ref invTransformA, ref partB, ref transformB, ref invTransformB, testOptional, testQuick));
 }
        private static CheapIntersection IntersectsInternalCheap(ref PartFromPrefab partA, ref MatrixI transformA, ref MatrixI invTransformA, ref PartFromPrefab partB, ref MatrixI transformB, ref MatrixI invTransformB, bool testOptional)
        {
            using (partA.LockSharedUsing())
                using (partB.LockSharedUsing())
                {
                    var reservedAAll = Utilities.TransformBoundingBox(partA.ReservedSpace, ref transformA);
                    var reservedBAll = Utilities.TransformBoundingBox(partB.ReservedSpace, ref transformB);

                    var reservedA = new List <MyTuple <ReservedSpace, BoundingBox> >(partA.m_reservedSpaces.Count);
                    // ReSharper disable once LoopCanBeConvertedToQuery (preserve ref)
                    foreach (var aabb in partA.m_reservedSpaces)
                    {
                        if (!aabb.IsOptional || testOptional)
                        {
                            reservedA.Add(MyTuple.Create(aabb, Utilities.TransformBoundingBox(aabb.Box, ref transformA)));
                        }
                    }

                    var reservedB = new List <MyTuple <ReservedSpace, BoundingBox> >(partB.m_reservedSpaces.Count);
                    // ReSharper disable once LoopCanBeConvertedToQuery (preserve ref)
                    foreach (var aabb in partB.m_reservedSpaces)
                    {
                        if (!aabb.IsOptional || testOptional)
                        {
                            reservedB.Add(MyTuple.Create(aabb, Utilities.TransformBoundingBox(aabb.Box, ref transformB)));
                        }
                    }

                    // Reserved spaces intersect?
                    if (partA.m_reservedSpaces.Count > 0 && partB.m_reservedSpaces.Count > 0 && reservedAAll.Intersects(reservedBAll))
                    {
                        if (reservedA.Any(x => reservedB.Any(y => !y.Item1.IsShared && !x.Item1.IsShared && x.Item2.Intersects(y.Item2))))
                        {
                            return(CheapIntersection.Yes);
                        }
                    }


                    var blockAAll = Utilities.TransformBoundingBox(partA.BoundingBox, ref transformA);
                    var blockBAll = Utilities.TransformBoundingBox(partB.BoundingBox, ref transformB);

                    // Block spaces intersect with reserved space?
                    if (partA.m_reservedSpaces.Count > 0 && reservedAAll.Intersects(blockBAll))
                    {
                        if (reservedA.Any(aabb => aabb.Item2.Intersects(blockBAll)))
                        {
                            return(CheapIntersection.Maybe);
                        }
                    }
                    // ReSharper disable once InvertIf
                    if (partB.m_reservedSpaces.Count > 0 && reservedBAll.Intersects(blockAAll))
                    {
                        if (reservedB.Any(aabb => aabb.Item2.Intersects(blockAAll)))
                        {
                            return(CheapIntersection.Maybe);
                        }
                    }

                    // Block space intersects with block space?
                    return(!blockAAll.Intersects(blockBAll) ? CheapIntersection.No : CheapIntersection.Maybe);
                }
        }