// Copyright (c) 2013-2014 Robert Rouhani and other contributors (see CONTRIBUTORS file). // Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE using System; using System.Runtime.InteropServices; namespace SharpNav { /// /// Represents a voxel span in a . /// [StructLayout(LayoutKind.Sequential)] public struct CompactSpan { /// /// The span minimum. /// public int Minimum; /// /// The number of voxels contained in the span. /// public int Height; /// /// A byte representing the index of the connected span in the cell directly to the west. /// public byte ConnectionWest; /// /// A byte representing the index of the connected span in the cell directly to the north. /// public byte ConnectionNorth; /// /// A byte representing the index of the connected span in the cell directly to the east. /// public byte ConnectionEast; /// /// A byte representing the index of the connected span in the cell directly to the south. /// public byte ConnectionSouth; /// /// The region the span belongs to. /// public RegionId Region; /// /// A constant that means there is no connection for the values , /// , , and . /// private const byte NotConnected = 0xff; /// /// Initializes a new instance of the struct. /// /// The span minimum. /// The number of voxels the span contains. public CompactSpan(int minimum, int height) { this.Minimum = minimum; this.Height = height; this.ConnectionWest = NotConnected; this.ConnectionNorth = NotConnected; this.ConnectionEast = NotConnected; this.ConnectionSouth = NotConnected; this.Region = RegionId.Null; } /// /// Gets a value indicating whether the span has an upper bound or goes to "infinity". /// public bool HasUpperBound { get { return Height != int.MaxValue; } } /// /// Gets the upper bound of the span. /// public int Maximum { get { return Minimum + Height; } } /// /// Gets the number of connections the current CompactSpan has with its neighbors. /// public int ConnectionCount { get { int count = 0; if (ConnectionWest != NotConnected) count++; if (ConnectionNorth != NotConnected) count++; if (ConnectionEast != NotConnected) count++; if (ConnectionSouth != NotConnected) count++; return count; } } /// /// If two CompactSpans overlap, find the minimum of the new overlapping CompactSpans. /// /// The first CompactSpan /// The second CompactSpan /// The minimum of the overlapping ComapctSpans public static void OverlapMin(ref CompactSpan left, ref CompactSpan right, out int min) { min = Math.Max(left.Minimum, right.Minimum); } /// /// If two CompactSpans overlap, find the maximum of the new overlapping CompactSpans. /// /// The first CompactSpan /// The second CompactSpan /// The maximum of the overlapping CompactSpans public static void OverlapMax(ref CompactSpan left, ref CompactSpan right, out int max) { if (left.Height == int.MaxValue) { if (right.Height == int.MaxValue) max = int.MaxValue; else max = right.Minimum + right.Height; } else if (right.Height == int.MaxValue) max = left.Minimum + left.Height; else max = Math.Min(left.Minimum + left.Height, right.Minimum + right.Height); } /// /// Creates a from a minimum boundary and a maximum boundary. /// /// The minimum. /// The maximum. /// A . public static CompactSpan FromMinMax(int min, int max) { CompactSpan s; FromMinMax(min, max, out s); return s; } /// /// Creates a from a minimum boundary and a maximum boundary. /// /// The minimum. /// The maximum. /// A . public static void FromMinMax(int min, int max, out CompactSpan span) { span.Minimum = min; span.Height = max - min; span.ConnectionWest = NotConnected; span.ConnectionNorth = NotConnected; span.ConnectionEast = NotConnected; span.ConnectionSouth = NotConnected; span.Region = RegionId.Null; } /// /// Sets connection data to a span contained in a neighboring cell. /// /// The direction of the cell. /// The index of the span in the neighboring cell. /// The to set the data for. public static void SetConnection(Direction dir, int i, ref CompactSpan s) { if (i >= NotConnected) throw new ArgumentOutOfRangeException("Index of connecting span is too high to be stored. Try increasing cell height.", "i"); switch (dir) { case Direction.West: s.ConnectionWest = (byte)i; break; case Direction.North: s.ConnectionNorth = (byte)i; break; case Direction.East: s.ConnectionEast = (byte)i; break; case Direction.South: s.ConnectionSouth = (byte)i; break; default: throw new ArgumentException("dir isn't a valid Direction."); } } /// /// Un-sets connection data from a neighboring cell. /// /// The direction of the cell. /// The to set the data for. public static void UnsetConnection(Direction dir, ref CompactSpan s) { switch (dir) { case Direction.West: s.ConnectionWest = NotConnected; break; case Direction.North: s.ConnectionNorth = NotConnected; break; case Direction.East: s.ConnectionEast = NotConnected; break; case Direction.South: s.ConnectionSouth = NotConnected; break; default: throw new ArgumentException("dir isn't a valid Direction."); } } /// /// Gets the connection data for a neighboring cell in a specified direction. /// /// The to get the connection data from. /// The direction. /// The index of the span in the neighboring cell. public static int GetConnection(ref CompactSpan s, Direction dir) { switch (dir) { case Direction.West: return s.ConnectionWest; case Direction.North: return s.ConnectionNorth; case Direction.East: return s.ConnectionEast; case Direction.South: return s.ConnectionSouth; default: throw new ArgumentException("dir isn't a valid Direction."); } } /// /// Gets the connection data for a neighboring call in a specified direction. /// /// The direction. /// The index of the span in the neighboring cell. public int GetConnection(Direction dir) { return GetConnection(ref this, dir); } /// /// Gets a value indicating whether the span is connected to another span in a specified direction. /// /// The direction. /// A value indicating whether the specified direction has a connected span. public bool IsConnected(Direction dir) { switch (dir) { case Direction.West: return ConnectionWest != NotConnected; case Direction.North: return ConnectionNorth != NotConnected; case Direction.East: return ConnectionEast != NotConnected; case Direction.South: return ConnectionSouth != NotConnected; default: throw new ArgumentException("dir isn't a valid Direction."); } } } }