Skip to content

Instantly share code, notes, and snippets.

@copygirl
Created October 1, 2019 17:53
Show Gist options
  • Save copygirl/b0c7309d7495f00c56e76de971df222c to your computer and use it in GitHub Desktop.
Save copygirl/b0c7309d7495f00c56e76de971df222c to your computer and use it in GitHub Desktop.
using System;
using System.Text;
using Vintagestory.API.MathTools;
namespace Vintagestory.Essentials
{
[Flags]
public enum ProperNeighbor : byte
{
None = 0,
// FACINGS
East = 0b110000, // +X
West = 0b100000, // -X
Up = 0b001100, // +Y
Down = 0b001000, // -Y
South = 0b000011, // +Z
North = 0b000010, // -Z
// CARDINALS
SouthEast = South | East, // +X +Z
SouthWest = South | West, // -X +Z
NorthEast = North | East, // +X -Z
NorthWest = North | West, // -X -Z
// ALL_AXIS_PLANES
UpEast = Up | East , // +X +Y
UpWest = Up | West , // -X +Y
UpSouth = Up | South, // +Z +Y
UpNorth = Up | North, // -Z +Y
DownEast = Down | East , // +X -Y
DownWest = Down | West , // -X -Y
DownSouth = Down | South, // +Z -Y
DownNorth = Down | North, // -Z -Y
// ALL
UpSouthEast = Up | South | East, // +X +Y +Z
UpSouthWest = Up | South | West, // -X +Y +Z
UpNorthEast = Up | North | East, // +X +Y -Z
UpNorthWest = Up | North | West, // -X +Y -Z
DownSouthEast = Down | South | East, // +X -Y +Z
DownSouthWest = Down | South | West, // -X -Y +Z
DownNorthEast = Down | North | East, // +X -Y -Z
DownNorthWest = Down | North | West, // -X -Y -Z
}
public static class ProperNeighborHelper
{
public static readonly ImmutableSet<ProperNeighbor> HORIZONTALS =
new ImmutableSet<ProperNeighbor>(
ProperNeighbor.East, ProperNeighbor.West,
ProperNeighbor.South, ProperNeighbor.North);
public static readonly ImmutableSet<ProperNeighbor> VERTICALS =
new ImmutableSet<ProperNeighbor>(ProperNeighbor.Up, ProperNeighbor.Down);
public static readonly ImmutableSet<ProperNeighbor> FACINGS =
new ImmutableSet<ProperNeighbor>(HORIZONTALS, VERTICALS);
public static readonly ImmutableSet<ProperNeighbor> CARDINALS =
new ImmutableSet<ProperNeighbor>(HORIZONTALS,
ProperNeighbor.SouthEast, ProperNeighbor.SouthWest,
ProperNeighbor.NorthEast, ProperNeighbor.NorthWest);
public static readonly ImmutableSet<ProperNeighbor> ALL_AXIS_PLANES =
new ImmutableSet<ProperNeighbor>(FACINGS,
ProperNeighbor.SouthEast, ProperNeighbor.SouthWest,
ProperNeighbor.NorthEast, ProperNeighbor.NorthWest,
ProperNeighbor.UpEast , ProperNeighbor.UpWest ,
ProperNeighbor.UpSouth , ProperNeighbor.UpNorth ,
ProperNeighbor.DownEast , ProperNeighbor.DownWest ,
ProperNeighbor.DownSouth, ProperNeighbor.DownNorth);
public static readonly ImmutableSet<ProperNeighbor> ALL =
new ImmutableSet<ProperNeighbor>(ALL_AXIS_PLANES,
ProperNeighbor.UpSouthEast, ProperNeighbor.UpSouthWest,
ProperNeighbor.UpNorthEast, ProperNeighbor.UpNorthWest,
ProperNeighbor.DownSouthEast, ProperNeighbor.DownSouthWest,
ProperNeighbor.DownNorthEast, ProperNeighbor.DownNorthWest);
public static ProperNeighbor fromAxis(EnumAxis axis, int v)
{
if ((v < -1) || (v > 1))
throw new ArgumentOutOfRangeException(nameof(v), $"v must be within (-1, 1), is {v}");
switch (axis) {
case EnumAxis.X: return (v > 0) ? ProperNeighbor.East : ProperNeighbor.West;
case EnumAxis.Y: return (v > 0) ? ProperNeighbor.Up : ProperNeighbor.Down;
case EnumAxis.Z: return (v > 0) ? ProperNeighbor.South : ProperNeighbor.North;
default: return ProperNeighbor.None;
}
}
public static EnumAxis getAxis(this ProperNeighbor self)
{
switch (self) {
case ProperNeighbor.East : return EnumAxis.X;
case ProperNeighbor.West : return EnumAxis.X;
case ProperNeighbor.Up : return EnumAxis.Y;
case ProperNeighbor.Down : return EnumAxis.Y;
case ProperNeighbor.South : return EnumAxis.Z;
case ProperNeighbor.North : return EnumAxis.Z;
default: throw new ArgumentException(nameof(self), $"{self} is not one of FACINGS");
}
}
public static ProperNeighbor fromOffset(int x, int y, int z)
{
ProperNeighbor neighbor = ProperNeighbor.None;
if (x != 0) {
if (x == 1) neighbor |= ProperNeighbor.East;
else if (x == -1) neighbor |= ProperNeighbor.West;
else throw new ArgumentOutOfRangeException(nameof(x), $"x must be within (-1, 1), is {x}");
}
if (y != 0) {
if (y == 1) neighbor |= ProperNeighbor.Up;
else if (y == -1) neighbor |= ProperNeighbor.Down;
else throw new ArgumentOutOfRangeException(nameof(y), $"y must be within (-1, 1), is {y}");
}
if (z != 0) {
if (z == 1) neighbor |= ProperNeighbor.South;
else if (z == -1) neighbor |= ProperNeighbor.North;
else throw new ArgumentOutOfRangeException(nameof(z), $"z must be within (-1, 1), is {z}");
}
return neighbor;
// Alternative implementation:
// if ((x < -1) || (x > 1)) throw new ArgumentOutOfRangeException(nameof(x), "x must be within (-1, 1)");
// if ((y < -1) || (y > 1)) throw new ArgumentOutOfRangeException(nameof(y), "y must be within (-1, 1)");
// if ((z < -1) || (z > 1)) throw new ArgumentOutOfRangeException(nameof(z), "z must be within (-1, 1)");
// return ((x != 0) ? ((x > 0) ? ProperNeighbor.East : ProperNeighbor.West ) : 0)
// | ((y != 0) ? ((y > 0) ? ProperNeighbor.Up : ProperNeighbor.Down ) : 0)
// | ((z != 0) ? ((z > 0) ? ProperNeighbor.South : ProperNeighbor.North) : 0);
}
private const int X_SET_BIT = 0b100000, X_VALUE_BIT = 0b010000;
private const int Y_SET_BIT = 0b001000, Y_VALUE_BIT = 0b000100;
private const int Z_SET_BIT = 0b000010, Z_VALUE_BIT = 0b000001;
public static void getOffset(this ProperNeighbor self,
out int x, out int y, out int z)
{
x = (((int)self & X_SET_BIT) != 0) ? ((((int)self & X_VALUE_BIT) != 0) ? 1 : -1) : 0;
y = (((int)self & Y_SET_BIT) != 0) ? ((((int)self & Y_VALUE_BIT) != 0) ? 1 : -1) : 0;
z = (((int)self & Z_SET_BIT) != 0) ? ((((int)self & Z_VALUE_BIT) != 0) ? 1 : -1) : 0;
}
public static ProperPos toProperPos(this ProperNeighbor self)
{
self.getOffset(out var x, out var y, out var z);
return new ProperPos(x, y, z);
}
public static Vec3i toVec3i(this ProperNeighbor self)
{
self.getOffset(out var x, out var y, out var z);
return new Vec3i(x, y, z);
}
public static bool isNone(this ProperNeighbor self)
=> (self == ProperNeighbor.None);
public static bool isHorizontal(this ProperNeighbor self)
=> HORIZONTALS.Contains(self);
public static bool isVertical(this ProperNeighbor self)
=> VERTICALS.Contains(self);
public static bool isCardinal(this ProperNeighbor self)
=> CARDINALS.Contains(self);
public static bool isFacing(this ProperNeighbor self)
=> FACINGS.Contains(self);
public static bool isValid(this ProperNeighbor self)
=> ALL.Contains(self);
public static string ToShortString(this ProperNeighbor self)
{
if (!self.isValid()) return "-";
var sb = new StringBuilder(3);
foreach (var chr in self.ToString())
if ((chr >= 'A') && (chr <= 'Z')) // ASCII IsUpper
sb.Append(chr + 0x20); // ASCII ToUpper
return sb.ToString();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment