//public bool GravityTest(LineSegmentD line, Vector3D finalDestination, out MyEntity blockingPath, out Vector3? pointOfObstruction) //{ // if (Vector3.DistanceSquared(line.From, line.To) > 10000f) // { // BoundingBoxD box = line.BoundingBox; // m_voxels.Clear(); // MyGamePruningStructure.GetAllVoxelMapsInBox(ref box, m_voxels); // foreach (MyEntity entity in m_voxels) // { // MyPlanet planet = entity as MyPlanet; // if (planet == null) // continue; // Vector3D planetCentre = planet.GetCentre(); // Vector3D closestPoint = line.ClosestPoint(planetCentre); // if (!planet.IsPositionInGravityWell(closestPoint)) // continue; // m_logger.debugLog("path: " + line.From + " to " + line.To + ", final: " + finalDestination + ", closest point: " + closestPoint + ", planet @ " + planetCentre + " : " + planet.getBestName(), "GravityTest()"); // if (closestPoint == line.From) // { // m_logger.debugLog("closest point is start", "GravityTest()"); // continue; // } // if (closestPoint == line.To) // { // if (line.To == finalDestination ) // { // m_logger.debugLog("closest point is final", "GravityTest()"); // continue; // } // if (Vector3D.DistanceSquared(planetCentre, closestPoint) < Vector3D.DistanceSquared(planetCentre, finalDestination)) // { // m_logger.debugLog("closest point is end, which is closer to planet than final dest is", "GravityTest()"); // blockingPath = entity; // pointOfObstruction = closestPoint; // return false; // } // m_logger.debugLog("closest point is end", "GravityTest()"); // continue; // } // //float startGravity = planet.GetWorldGravityGrid( line.From).LengthSquared(); // //float closestGravity = planet.GetWorldGravityGrid(closestPoint).LengthSquared(); // //double toDistSq = Vector3D.DistanceSquared(planetCentre, line.To); // //if (closestPoint == line.To && (line.To == finalDestination || )) // //{ // // m_logger.debugLog("path: " + line.From + " to " + line.To + ", closest point: " + closestPoint + ", planet @ " + planetCentre + " : " + planet.getBestName(), "GravityTest()"); // // m_logger.debugLog("closest point is end", "GravityTest()"); // // continue; // //} // //m_logger.debugLog("path: " + line.From + " to " + line.To + ", closest point: " + closestPoint + ", planet @ " + planetCentre + " : " + planet.getBestName(), "GravityTest()", Logger.severity.DEBUG); // double closestDistSq = Vector3D.DistanceSquared(planetCentre, closestPoint) + 1f; // if (closestDistSq < Vector3D.DistanceSquared(planetCentre, line.From) || closestDistSq < Vector3D.DistanceSquared(planetCentre, line.To)) // { // m_logger.debugLog("path moves ship closer to planet. closestDistSq: " + closestDistSq + ", from dist sq: " + Vector3D.DistanceSquared(planetCentre, line.From) + ", to dist sq: " + Vector3D.DistanceSquared(planetCentre, line.To), "GravityTest()", Logger.severity.INFO); // blockingPath = entity; // pointOfObstruction = closestPoint; // return false; // } // } // } // blockingPath = null; // pointOfObstruction = null; // return true; //} /// <summary> /// How far long the line would the ship be able to travel? Uses a capsule derived from previously calculated path. /// </summary> /// <param name="canTravel">Line along which navigation block would travel</param> /// <remarks> /// Capsule only test because the ship will not be oriented correctly /// </remarks> /// <returns>distance from the destination that can be reached</returns> public float distanceCanTravel(LineSegment canTravel) { BoundingBoxD atFrom = m_grid.WorldAABB.Translate(canTravel.From - m_grid.GetPosition()); BoundingBoxD atTo = m_grid.WorldAABB.Translate(canTravel.To - m_grid.GetPosition()); ICollection <MyEntity> offenders = EntitiesInLargeAABB(atFrom, atTo); if (offenders.Count == 0) { m_logger.debugLog("AABB is empty"); return(0); } m_logger.debugLog("collected entities to test: " + offenders.Count); IOrderedEnumerable <MyEntity> ordered = offenders.OrderBy(entity => Vector3D.Distance(canTravel.From, entity.GetCentre())); Capsule path = new Capsule(canTravel.From, canTravel.To, m_path.Radius); Vector3?pointOfObstruction = null; foreach (MyEntity entity in ordered) { if (path.IntersectsAABB(entity)) { MyVoxelBase voxel = entity as MyVoxelBase; if (voxel != null) { if (!TestVoxel(voxel, path, out pointOfObstruction)) { m_logger.debugLog("obstruction at " + pointOfObstruction + " distance from dest is " + Vector3.Distance(canTravel.To, (Vector3)pointOfObstruction)); return(Vector3.Distance(canTravel.To, (Vector3)pointOfObstruction)); } } IMyCubeGrid grid = entity as IMyCubeGrid; if (grid != null) { float minDistSq = (m_grid.GridSize + grid.GridSize) * (m_grid.GridSize + grid.GridSize); GridCellCache cache = GridCellCache.GetCellCache(grid); cache.ForEach(cell => { Vector3 cellPos = grid.GridIntegerToWorld(cell); if (canTravel.PointInCylinder(minDistSq, ref cellPos)) { pointOfObstruction = cellPos; return(true); } return(false); }); if (pointOfObstruction.HasValue) { return(Vector3.Distance(canTravel.To, (Vector3)pointOfObstruction)); } } m_logger.debugLog("not a grid, testing bounds"); if (!m_path.IntersectsVolume(entity)) { continue; } m_logger.debugLog("no more tests for non-grids are implemented", Logger.severity.DEBUG); pointOfObstruction = m_path.get_Line().ClosestPoint(entity.GetCentre()); return(Vector3.Distance(canTravel.To, (Vector3)pointOfObstruction)); } } // no obstruction m_logger.debugLog("no obstruction"); return(0f); }
/// <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); }
/// <summary> /// Starts checking path against the geometry of the closest planet. /// </summary> /// <param name="displacement">Destination - current postion</param> private void Start(ref Vector3 displacement) { using (m_lock.AcquireExclusiveUsing()) { if ((CurrentState & State.Running) != 0) { return; } CurrentState |= State.Running; m_displacement = displacement; m_cells.Clear(); Vector3D gridCentre = m_grid.GetCentre(); double distSq; gravcomp = MyPlanetExtensions.GetClosestPlanet(gridCentre, out distSq); if (gravcomp == null) { //m_logger.debugLog("No planets found", "Start()", Logger.severity.TRACE); CurrentState = State.Clear; return; } if (distSq > gravcomp.MaximumRadius * gravcomp.MaximumRadius) { //m_logger.debugLog("Outside maximum radius of closest planet", "Start()", Logger.severity.TRACE); // gravity test // TODO: it might be worthwhile to perform gravity test against multiple planets Path.From = gridCentre; Path.To = gridCentre + displacement; Vector3D closestPoint = Path.ClosestPoint(gravcomp.WorldMatrix.Translation); if (closestPoint != Path.From && closestPoint != Path.To) { //float gravityAtClose = ClosestPlanet.GetGravityMultiplier(closestPoint) - MinGravityAvoid; float gravityAtClose = gravComp.GetGravityMultiplier(closestPoint) - MinGravityAvoid; //if (gravityAtClose > 0f && gravityAtClose > ClosestPlanet.GetGravityMultiplier(Path.From) && gravityAtClose > ClosestPlanet.GetGravityMultiplier(Path.To)) if (gravityAtClose > 0f && gravityAtClose > gravComp.GetGravityMultiplier(Path.From) && gravityAtClose > gravComp.GetGravityMultiplier(Path.To)) { ObstructionPoint = closestPoint; CurrentState = State.BlockedGravity; return; } } CurrentState = State.Clear; return; } Vector3 direction; Vector3.Normalize(ref displacement, out direction); direction = Vector3.Transform(direction, m_grid.WorldMatrixNormalizedInv.GetOrientation()); GridCellCache.GetCellCache(m_grid).ForEach(cell => { Vector3I rejected; Vector3.Reject(cell, direction).ApplyOperation(x => (int)Math.Round(x), out rejected); if (m_cellsUnique.Add(rejected)) { m_cells.Enqueue(rejected); } }); m_cellsUnique.Clear(); DoTests.Enqueue(TestPath); } }
public RotateChecker(IMyCubeGrid grid) { this.m_logger = new Logger(() => m_grid.DisplayName); this.m_grid = grid; this.m_cells = GridCellCache.GetCellCache(grid); }