ZeroVR/ZeroPacientVR/Assets/CodeRespawn/DungeonArchitect/ThirdParty/SharpNav/Cell.cs

180 lines
4.4 KiB
C#

// Copyright (c) 2013-2014 Robert Rouhani <robert.rouhani@gmail.com> and other contributors (see CONTRIBUTORS file).
// Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace SharpNav
{
/// <summary>
/// A cell is a column of voxels represented in <see cref="Span"/>s.
/// </summary>
public class Cell
{
private List<Span> spans;
private int height;
/// <summary>
/// Initializes a new instance of the <see cref="Cell"/> class.
/// </summary>
/// <param name="height">The number of voxels in the column.</param>
public Cell(int height)
{
this.height = height;
spans = new List<Span>();
}
/// <summary>
/// Gets the height of the cell in number of voxels.
/// </summary>
public int Height
{
get
{
return height;
}
}
/// <summary>
/// Gets the number of spans in the cell.
/// </summary>
public int SpanCount
{
get
{
return spans.Count;
}
}
/// <summary>
/// Gets the number of spans that are in walkable <see cref="Area"/>s.
/// </summary>
public int WalkableSpanCount
{
get
{
int count = 0;
for (int i = 0; i < spans.Count; i++)
if (spans[i].Area.IsWalkable)
count++;
return count;
}
}
/// <summary>
/// Gets a readonly list of all the <see cref="Span"/>s contained in the cell.
/// </summary>
/// <value>A readonly list of spans.</value>
public ReadOnlyCollection<Span> Spans
{
get
{
return spans.AsReadOnly();
}
}
/// <summary>
/// Gets a modifiable list of all the <see cref="Span"/>s contained in the cell.
/// Should only be used for filtering in <see cref="Heightfield"/>.
/// </summary>
/// <value>A list of spans for modification.</value>
internal List<Span> MutableSpans
{
get
{
return spans;
}
}
/// <summary>
/// Gets the <see cref="Span"/> that contains the specified voxel.
/// </summary>
/// <param name="location">The voxel to search for.</param>
/// <returns>The span containing the voxel. Null if the voxel is empty.</returns>
public Span? this[int location]
{
get
{
if (location < 0 || location >= height)
throw new ArgumentOutOfRangeException("Location must be a value between 0 and " + height + ".");
//iterate the list of spans
foreach (Span s in spans)
{
if (s.Minimum > location)
break;
else if (s.Maximum >= location)
return s;
}
return null;
}
}
/// <summary>
/// Adds a <see cref="Span"/> to the cell.
/// </summary>
/// <param name="span">A span.</param>
/// <exception cref="ArgumentException">Thrown if an invalid span is provided.</exception>
public void AddSpan(Span span)
{
if (span.Minimum > span.Maximum)
{
int tmp = span.Minimum;
span.Minimum = span.Maximum;
span.Maximum = tmp;
}
//clamp the span to the cell's range of [0, maxHeight]
MathHelper.Clamp(ref span.Minimum, 0, height);
MathHelper.Clamp(ref span.Maximum, 0, height);
lock (spans)
{
for (int i = 0; i < spans.Count; i++)
{
//Check whether the current span is below, or overlapping existing spans.
//If the span is completely above the current span the loop will continue.
Span cur = spans[i];
if (cur.Minimum > span.Maximum)
{
//The new span is below the current one and is not intersecting.
spans.Insert(i, span);
return;
}
else if (cur.Maximum >= span.Minimum)
{
//The new span is colliding with the current one, merge them together.
if (cur.Minimum < span.Minimum)
span.Minimum = cur.Minimum;
if (cur.Maximum == span.Maximum)
{
//In the case that both spans end at the same voxel, the area gets merged. The new span's area
//has priority if both spans are walkable, so the only case where the area gets set is when
//the new area isn't walkable and the old one is.
if (!span.Area.IsWalkable && cur.Area.IsWalkable)
span.Area = cur.Area;
}
else if (cur.Maximum > span.Maximum)
{
span.Maximum = cur.Maximum;
span.Area = cur.Area;
}
//Remove the current span and adjust i.
//We do this to avoid duplicating the current span.
spans.RemoveAt(i);
i--;
}
}
//If the span is not inserted, it is the highest span and will be added to the end.
spans.Add(span);
}
}
}
}