Beispiel #1
0
        /// <summary>
        /// Test if it is safe for the grid to rotate.
        /// </summary>
        /// <param name="axis">Normalized axis of rotation in world space.</param>
        /// <returns>True iff the path is clear.</returns>
        private bool in_TestRotate(Vector3 axis)
        {
            IMyCubeGrid myGrid       = m_block.CubeGrid;
            Vector3     centreOfMass = myGrid.Physics.CenterOfMassWorld;
            float       longestDim   = myGrid.GetLongestDim();

            // calculate height
            Matrix  toMyLocal     = myGrid.WorldMatrixNormalizedInv;
            Vector3 myLocalCoM    = Vector3.Transform(centreOfMass, toMyLocal);
            Vector3 myLocalAxis   = Vector3.Transform(axis, toMyLocal.GetOrientation());
            Vector3 myLocalCentre = myGrid.LocalAABB.Center;             // CoM may not be on ship (it now considers mass from attached grids)
            Ray     upper         = new Ray(myLocalCentre + myLocalAxis * longestDim * 2f, -myLocalAxis);
            float?  upperBound    = myGrid.LocalAABB.Intersects(upper);

            if (!upperBound.HasValue)
            {
                Log.AlwaysLog("Math fail, upperBound does not have a value", Logger.severity.FATAL);
            }
            Ray   lower      = new Ray(myLocalCentre - myLocalAxis * longestDim * 2f, myLocalAxis);
            float?lowerBound = myGrid.LocalAABB.Intersects(lower);

            if (!lowerBound.HasValue)
            {
                Log.AlwaysLog("Math fail, lowerBound does not have a value", Logger.severity.FATAL);
            }
            //Log.DebugLog("LocalAABB: " + myGrid.LocalAABB + ", centre: " + myLocalCentre + ", axis: " + myLocalAxis + ", longest dimension: " + longestDim + ", upper ray: " + upper + ", lower ray: " + lower);
            float height = longestDim * 4f - upperBound.Value - lowerBound.Value;

            float furthest = 0f;

            foreach (IMyCubeGrid grid in AttachedGrid.AttachedGrids(myGrid, Attached.AttachedGrid.AttachmentKind.Physics, true))
            {
                CubeGridCache cache = CubeGridCache.GetFor(grid);
                if (cache == null)
                {
                    return(false);
                }
                foreach (Vector3I cell in cache.OccupiedCells())
                {
                    Vector3 rejection       = Vector3.Reject(cell * myGrid.GridSize, myLocalAxis);
                    float   cellDistSquared = Vector3.DistanceSquared(myLocalCoM, rejection);
                    if (cellDistSquared > furthest)
                    {
                        furthest = cellDistSquared;
                    }
                }
            }
            float length = (float)Math.Sqrt(furthest) + myGrid.GridSize;

            //Log.DebugLog("height: " + height + ", length: " + length);

            BoundingSphereD surroundingSphere = new BoundingSphereD(centreOfMass, Math.Max(length, height) * MathHelper.Sqrt2);

            m_obstructions.Clear();
            MyGamePruningStructure.GetAllTopMostEntitiesInSphere(ref surroundingSphere, m_obstructions);

            LineSegment axisSegment = new LineSegment();

            m_closestPlanet = null;

            foreach (MyEntity entity in m_collector.Invoke(m_obstructions))
            {
                if (entity is IMyVoxelBase)
                {
                    IMyVoxelMap voxel = entity as IMyVoxelMap;
                    if (voxel != null)
                    {
                        if (voxel.GetIntersectionWithSphere(ref surroundingSphere))
                        {
                            Log.DebugLog("Too close to " + voxel.getBestName() + ", CoM: " + centreOfMass.ToGpsTag("Centre of Mass") + ", required distance: " + surroundingSphere.Radius);
                            ObstructingEntity = voxel;
                            return(false);
                        }
                        continue;
                    }

                    if (m_closestPlanet == null)
                    {
                        MyPlanet planet = entity as MyPlanet;
                        if (planet == null)
                        {
                            continue;
                        }

                        double distToPlanetSq = Vector3D.DistanceSquared(centreOfMass, planet.PositionComp.GetPosition());
                        if (distToPlanetSq < planet.MaximumRadius * planet.MaximumRadius)
                        {
                            m_closestPlanet = planet;

                            if (m_planetObstruction)
                            {
                                Log.DebugLog("planet blocking");
                                ObstructingEntity = m_closestPlanet;
                                return(false);
                            }
                        }
                    }
                    continue;
                }

                IMyCubeGrid grid = entity as IMyCubeGrid;
                if (grid != null)
                {
                    Matrix  toLocal     = grid.WorldMatrixNormalizedInv;
                    Vector3 localAxis   = Vector3.Transform(axis, toLocal.GetOrientation());
                    Vector3 localCentre = Vector3.Transform(centreOfMass, toLocal);
                    axisSegment.From = localCentre - localAxis * height;
                    axisSegment.To   = localCentre + localAxis * height;

                    CubeGridCache cache = CubeGridCache.GetFor(grid);
                    if (cache == null)
                    {
                        return(false);
                    }
                    foreach (Vector3I cell in cache.OccupiedCells())
                    {
                        if (axisSegment.PointInCylinder(length, cell * grid.GridSize))
                        {
                            Log.DebugLog("axis segment: " + axisSegment.From + " to " + axisSegment.To + ", radius: " + length + ", hit " + grid.nameWithId() + " at " + cell);
                            ObstructingEntity = grid;
                            return(false);
                        }
                    }

                    continue;
                }

                Log.DebugLog("No tests for object: " + entity.getBestName(), Logger.severity.INFO);
                ObstructingEntity = entity;
                return(false);
            }

            MyAPIGateway.Utilities.TryInvokeOnGameThread(TestPlanet);
            ObstructingEntity = null;
            return(true);
        }
        /// <summary>
        /// Test if it is safe for the grid to rotate.
        /// </summary>
        /// <param name="axis">Normalized axis of rotation in world space.</param>
        /// <param name="ignoreAsteroids"></param>
        /// <returns>True iff the path is clear.</returns>
        public bool TestRotate(Vector3 axis, bool ignoreAsteroids, out IMyEntity obstruction)
        {
            Vector3 centreOfMass = m_grid.Physics.CenterOfMassWorld;
            float   longestDim   = m_grid.GetLongestDim();

            // calculate height
            Matrix  toMyLocal     = m_grid.WorldMatrixNormalizedInv;
            Vector3 myLocalCoM    = Vector3.Transform(centreOfMass, toMyLocal);
            Vector3 myLocalAxis   = Vector3.Transform(axis, toMyLocal.GetOrientation());
            Vector3 myLocalCentre = m_grid.LocalAABB.Center;             // CoM may not be on ship (it now considers mass from attached grids)
            Ray     upper         = new Ray(myLocalCentre + myLocalAxis * longestDim * 2f, -myLocalAxis);
            float?  upperBound    = m_grid.LocalAABB.Intersects(upper);

            if (!upperBound.HasValue)
            {
                m_logger.alwaysLog("Math fail, upperBound does not have a value", Logger.severity.FATAL);
            }
            Ray   lower      = new Ray(myLocalCentre - myLocalAxis * longestDim * 2f, myLocalAxis);
            float?lowerBound = m_grid.LocalAABB.Intersects(lower);

            if (!lowerBound.HasValue)
            {
                m_logger.alwaysLog("Math fail, lowerBound does not have a value", Logger.severity.FATAL);
            }
            m_logger.debugLog("LocalAABB: " + m_grid.LocalAABB + ", centre: " + myLocalCentre + ", axis: " + myLocalAxis + ", longest dimension: " + longestDim + ", upper ray: " + upper + ", lower ray: " + lower);
            float height = longestDim * 4f - upperBound.Value - lowerBound.Value;

            float furthest = 0f;

            m_cells.ForEach(cell => {
                Vector3 rejection     = Vector3.Reject(cell * m_grid.GridSize, myLocalAxis);
                float cellDistSquared = Vector3.DistanceSquared(myLocalCoM, rejection);
                if (cellDistSquared > furthest)
                {
                    furthest = cellDistSquared;
                }
            });
            float length = (float)Math.Sqrt(furthest) + m_grid.GridSize * 0.5f;

            m_logger.debugLog("height: " + height + ", length: " + length);

            BoundingSphereD surroundingSphere = new BoundingSphereD(centreOfMass, Math.Max(length, height));

            m_obstructions.Clear();
            MyGamePruningStructure.GetAllTopMostEntitiesInSphere(ref surroundingSphere, m_obstructions);

            LineSegment axisSegment = new LineSegment();

            ClosestPlanet = MyPlanetExtensions.GetClosestPlanet(centreOfMass);
            MyAPIGateway.Utilities.TryInvokeOnGameThread(TestPlanet);

            foreach (MyEntity entity in m_obstructions)
            {
                if (PathChecker.collect_Entity(m_grid, entity))
                {
                    if (entity is IMyVoxelBase)
                    {
                        if (ignoreAsteroids)
                        {
                            continue;
                        }

                        IMyVoxelMap voxel = entity as IMyVoxelMap;
                        if (voxel != null)
                        {
                            if (voxel.GetIntersectionWithSphere(ref surroundingSphere))
                            {
                                m_logger.debugLog("Too close to " + voxel.getBestName() + ", CoM: " + centreOfMass.ToGpsTag("Centre of Mass") + ", required distance: " + surroundingSphere.Radius);
                                obstruction = voxel;
                                return(false);
                            }
                            continue;
                        }

                        if (PlanetState != Pathfinder.PathState.No_Obstruction)
                        {
                            m_logger.debugLog("planet blocking");
                            obstruction = ClosestPlanet;
                            return(false);
                        }
                        continue;
                    }

                    IMyCubeGrid grid = entity as IMyCubeGrid;
                    if (grid != null)
                    {
                        Matrix  toLocal     = grid.WorldMatrixNormalizedInv;
                        Vector3 localAxis   = Vector3.Transform(axis, toLocal.GetOrientation());
                        Vector3 localCentre = Vector3.Transform(centreOfMass, toLocal);
                        axisSegment.From = localCentre - localAxis * height;
                        axisSegment.To   = localCentre + localAxis * height;

                        bool found = false;
                        GridCellCache.GetCellCache(grid).ForEach(cell => {
                            if (axisSegment.PointInCylinder(length, cell * grid.GridSize))
                            {
                                found = true;
                                return(true);
                            }
                            return(false);
                        });

                        if (found)
                        {
                            obstruction = grid;
                            return(false);
                        }
                        continue;
                    }

                    m_logger.debugLog("No tests for object: " + entity.getBestName(), Logger.severity.INFO);
                    obstruction = entity;
                    return(false);
                }
            }

            obstruction = null;
            return(true);
        }