/// <summary> /// Gets the subdivision that is calculated for the given agent. /// </summary> /// <param name="agent">The given agent.</param> /// <returns>The subdivision that is calculated for the given agent.</returns> public SectorSubdivision GetSubdivisionForAgent(Agent agent) { /// Collect the overlap enabled agents. RCSet <Agent> overlapEnabledAgents = new RCSet <Agent>(); RCSet <Agent> currentlyOverlappingAgents = this.grid[agent.Area.X, agent.Area.Y].GetAgents(agent.MovingSize); foreach (Agent staticAgent in this.staticAgents[agent.MovingSize]) { if (currentlyOverlappingAgents.Contains(staticAgent) || staticAgent.Client.IsOverlapEnabled(agent.Client) || agent.Client.IsOverlapEnabled(staticAgent.Client)) { overlapEnabledAgents.Add(staticAgent); } } /// Try to find an already existing sector subdivision for the agent. SectorSubdivision subdivisionForAgent = this.subdivisions.FirstOrDefault(subdivision => subdivision.MovingSize == agent.MovingSize && subdivision.OverlapEnabledAgents.SetEquals(overlapEnabledAgents)); if (subdivisionForAgent == null) { /// Create a new one if not found. subdivisionForAgent = new SectorSubdivision(this, agent.MovingSize, overlapEnabledAgents); this.subdivisions.Add(subdivisionForAgent); } return(subdivisionForAgent); }
/// <see cref="IGraph<Region>.GetNeighbours"/> public IEnumerable <Region> GetNeighbours(Region node) { if (!this.transitionCells.ContainsKey(node)) { this.transitionCells.Add(node, new Dictionary <Region, RCSet <Cell> >()); for (int direction = 0; direction < GridDirections.DIRECTION_COUNT; direction++) { Sector neighbourSector = node.Subdivision.Sector.GetNeighbour(direction); if (neighbourSector == null) { continue; } SectorSubdivision neighbourSubdivision = neighbourSector.GetSubdivisionForAgent(this.agent); foreach (Region neighbourRegion in neighbourSubdivision.Regions) { RCSet <Cell> transitionCells = node.GetTransitionCells(neighbourRegion, direction); if (transitionCells.Count > 0) { this.transitionCells[node][neighbourRegion] = transitionCells; } } } } return(this.transitionCells[node].Keys); }
/// <summary> /// Constructs a RegionGraph instance with the given target cell for the given agent. /// </summary> /// <param name="targetCell">The given target cell.</param> /// <param name="agent">The given agent.</param> //public RegionGraph(Region targetRegion, Agent agent) public RegionGraph(Cell targetCell, Agent agent) { this.agent = agent; this.targetCell = targetCell; SectorSubdivision targetSubdivision = this.targetCell.Sector.GetSubdivisionForAgent(this.agent); this.targetRegion = this.targetCell.GetRegion(targetSubdivision); this.transitionCells = new Dictionary <Region, Dictionary <Region, RCSet <Cell> > >(); }
/// <summary> /// Removes this cell from the region that belongs to the given subdivision. /// </summary> /// <param name="subdivision">The given subdivision.</param> public void RemoveFromRegion(SectorSubdivision subdivision) { Region regionToRemove = this.regions.FirstOrDefault(region => region.Subdivision == subdivision); if (regionToRemove != null) { this.regions.Remove(regionToRemove); } }
/// <summary> /// Constructs a region instance. /// </summary> /// <param name="subdivision">The sector subdivision that this region belongs to.</param> public Region(SectorSubdivision subdivision) { this.parent = this; this.rank = 0; this.subdivision = subdivision; this.edgeCells = new RCSet <Cell> [GridDirections.DIRECTION_COUNT]; for (int dir = 0; dir < GridDirections.DIRECTION_COUNT; dir++) { this.edgeCells[dir] = new RCSet <Cell>(); } }
/// <summary> /// Gets the region of the given subdivision that this cell belongs to or null if no such region found. /// </summary> /// <param name="subdivision">The given subdivision.</param> public Region GetRegion(SectorSubdivision subdivision) { return(this.regions.FirstOrDefault(region => region.Subdivision == subdivision)); }
/// <summary> /// Calculates the next region on this path. /// </summary> /// <exception cref="InvalidOperationException">If this path is not in state PathStatusEnum.Partial.</exception> public void CalculateNextRegion() { if (this.Status != PathStatusEnum.Partial) { throw new InvalidOperationException("The state of this path shall be PathStatusEnum.Partial!"); } /// Calculate the high-level path if not yet calculated. if (this.highLevelPath == null) { SectorSubdivision sourceSubdivision = this.sourceCell.Sector.GetSubdivisionForAgent(this.agent); Region sourceRegion = this.sourceCell.GetRegion(sourceSubdivision); RegionGraph regionGraph = new RegionGraph(this.targetCell, this.agent); PathfindingAlgorithm <Region> highLevelPathfinding = new PathfindingAlgorithm <Region>(sourceRegion, regionGraph); PathfindingResult <Region> highLevelPathfindingResult = highLevelPathfinding.Execute(); this.highLevelPath = new List <Tuple <Region, RCSet <Cell> > >(); for (int i = 0; i < highLevelPathfindingResult.Path.Count; i++) { Region currentRegion = highLevelPathfindingResult.Path[i]; Region nextRegion = i < highLevelPathfindingResult.Path.Count - 1 ? highLevelPathfindingResult.Path[i + 1] : null; RCSet <Cell> targetCells = nextRegion != null?regionGraph.GetTransitionCells(currentRegion, nextRegion) : new RCSet <Cell> { this.targetCell }; this.highLevelPath.Add(Tuple.Create(currentRegion, targetCells)); } } /// Check if the region to be calculated is still valid -> if not then this path is broken. if (!this.highLevelPath[this.regionIndex].Item1.IsValid) { this.isBroken = true; return; } IGraph <Cell> graph = null; if (this.regionIndex < this.highLevelPath.Count - 1) { graph = new TransitRegionGraph( this.highLevelPath[this.regionIndex].Item1, this.highLevelPath[this.regionIndex + 1].Item1.Subdivision.Sector.Center, this.highLevelPath[this.regionIndex].Item2); } else { graph = new TransitRegionGraph( this.highLevelPath[this.regionIndex].Item1, this.targetCell.Coords, this.highLevelPath[this.regionIndex].Item2); } Cell fromCell = this.lowLevelPath != null ? this.lowLevelPath[this.lowLevelPath.Count - 1] : this.sourceCell; PathfindingAlgorithm <Cell> lowLevelPathfinding = new PathfindingAlgorithm <Cell>(fromCell, graph); PathfindingResult <Cell> lowLevelPathfindingResult = lowLevelPathfinding.Execute(); /// Check if a transition cell of the current region could be found -> if not then this path is broken. if (this.regionIndex < this.highLevelPath.Count - 1 && !lowLevelPathfindingResult.TargetFound) { this.isBroken = true; return; } /// Save the next section of the low level path and move to the next region. if (this.lowLevelPath == null) { this.lowLevelPath = lowLevelPathfindingResult.Path; } else { this.lowLevelPath.RemoveAt(this.lowLevelPath.Count - 1); this.lowLevelPath.AddRange(lowLevelPathfindingResult.Path); } this.regionIndex++; }