313 lines
6.6 KiB
Java
313 lines
6.6 KiB
Java
package speiger.src.coreengine.math.misc;
|
|
|
|
import java.util.EnumSet;
|
|
import java.util.Iterator;
|
|
import java.util.Set;
|
|
import java.util.StringJoiner;
|
|
import java.util.function.Predicate;
|
|
|
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
|
import speiger.src.collections.objects.lists.ObjectList;
|
|
import speiger.src.coreengine.math.MathUtils;
|
|
import speiger.src.coreengine.math.misc.Facing.Axis;
|
|
import speiger.src.coreengine.math.vector.ints.Vec2i;
|
|
|
|
public final class FacingList implements Iterable<Facing>, Predicate<Facing>
|
|
{
|
|
static final FacingList[] FACINGS = createArray();
|
|
public static final FacingList EMPTY = ofNumber(0);
|
|
public static final FacingList NORTH = ofFacings(Facing.NORTH);
|
|
public static final FacingList EAST = ofFacings(Facing.EAST);
|
|
public static final FacingList SOUTH = ofFacings(Facing.SOUTH);
|
|
public static final FacingList WEST = ofFacings(Facing.WEST);
|
|
|
|
public static final FacingList NORTH_EAST = ofFacings(Facing.NORTH, Facing.EAST);
|
|
public static final FacingList SOUTH_EAST = ofFacings(Facing.EAST, Facing.SOUTH);
|
|
public static final FacingList SOUTH_WEST = ofFacings(Facing.SOUTH, Facing.WEST);
|
|
public static final FacingList NORTH_WEST = ofFacings(Facing.WEST, Facing.NORTH);
|
|
|
|
public static final FacingList VERTICAL = ofFacings(Facing.NORTH, Facing.SOUTH);
|
|
public static final FacingList HORIZONTAL = ofFacings(Facing.EAST, Facing.WEST);
|
|
public static final FacingList ALL = ofFacings(Facing.NORTH, Facing.SOUTH, Facing.EAST, Facing.WEST);
|
|
|
|
final byte code;
|
|
final byte next;
|
|
final byte opposite;
|
|
final byte prev;
|
|
final byte count;
|
|
final Vec2i offset;
|
|
final Facing[] array;
|
|
|
|
private FacingList(int initCode)
|
|
{
|
|
code = (byte)MathUtils.clamp(0, 15, initCode);
|
|
Vec2i pos = Vec2i.mutable();
|
|
ObjectList<Facing> facings = new ObjectArrayList<Facing>();
|
|
for(int i = 0;i<4;i++)
|
|
{
|
|
if((code & 1 << i) != 0)
|
|
{
|
|
pos.add(Facing.byIndex(i).getOffset());
|
|
facings.add(Facing.byIndex(i));
|
|
}
|
|
}
|
|
int[] data = new int[3];
|
|
for(int i = 0,m=facings.size();i<m;i++)
|
|
{
|
|
Facing face = facings.get(i);
|
|
data[0] |= 1 << face.forward().getIndex();
|
|
data[1] |= 1 << face.opposite().getIndex();
|
|
data[2] |= 1 << face.backwards().getIndex();
|
|
}
|
|
next = (byte)MathUtils.clamp(0, 15, data[0]);
|
|
opposite = (byte)MathUtils.clamp(0, 15, data[1]);
|
|
prev = (byte)MathUtils.clamp(0, 15, data[2]);
|
|
offset = pos.asImmutable();
|
|
count = (byte)facings.size();
|
|
array = facings.toArray(new Facing[facings.size()]);
|
|
}
|
|
|
|
public static FacingList ofFacing(Facing facing)
|
|
{
|
|
return FACINGS[1 << facing.getIndex()];
|
|
}
|
|
|
|
public static FacingList ofFacings(Facing... facings)
|
|
{
|
|
return FACINGS[toNumber(facings)];
|
|
}
|
|
|
|
public static FacingList ofFlags(boolean[] facings)
|
|
{
|
|
return FACINGS[toNumber(facings)];
|
|
}
|
|
|
|
public static FacingList ofNumber(int value)
|
|
{
|
|
return FACINGS[value & 15];
|
|
}
|
|
|
|
public static FacingList ofAxis(Axis axis)
|
|
{
|
|
return FACINGS[axis.getCode()];
|
|
}
|
|
|
|
public static FacingList fromVec(Vec2i value)
|
|
{
|
|
value = value.clamp(-1, 1);
|
|
for(int i = 0;i<16;i++)
|
|
{
|
|
if(FACINGS[i].getOffset().equals(value))
|
|
{
|
|
return FACINGS[i];
|
|
}
|
|
}
|
|
return FACINGS[0];
|
|
}
|
|
|
|
public Set<Facing> toFacings()
|
|
{
|
|
return isEmpty() ? EnumSet.noneOf(Facing.class) : EnumSet.copyOf(ObjectArrayList.wrap(array));
|
|
}
|
|
|
|
public boolean[] toFlags()
|
|
{
|
|
return toFlags(array);
|
|
}
|
|
|
|
public int getRotation()
|
|
{
|
|
switch(count)
|
|
{
|
|
case 1: return array[0].getRotation();
|
|
case 2: return array[0].getRotation(array[1]);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
public FacingList rotate(int amount)
|
|
{
|
|
switch(amount & 3)
|
|
{
|
|
case 1: return FACINGS[next];
|
|
case 2: return FACINGS[opposite];
|
|
case 3: return FACINGS[prev];
|
|
default: return this;
|
|
}
|
|
}
|
|
|
|
public FacingList invert()
|
|
{
|
|
return FACINGS[15 - code];
|
|
}
|
|
|
|
public FacingList opposite()
|
|
{
|
|
return FACINGS[opposite];
|
|
}
|
|
|
|
public FacingList add(Facing facing)
|
|
{
|
|
return FACINGS[code | (1 << facing.getIndex())];
|
|
}
|
|
|
|
public FacingList add(FacingList facings)
|
|
{
|
|
return FACINGS[code | facings.code];
|
|
}
|
|
|
|
public FacingList remove(Facing facing)
|
|
{
|
|
return FACINGS[code & ~(1 << facing.getIndex())];
|
|
}
|
|
|
|
public FacingList remove(FacingList facings)
|
|
{
|
|
return FACINGS[code & ~facings.code];
|
|
}
|
|
|
|
public boolean contains(Facing direction)
|
|
{
|
|
return (code & 1 << direction.getIndex()) != 0;
|
|
}
|
|
|
|
public boolean contains(FacingList facings)
|
|
{
|
|
return (code & facings.code) == facings.code;
|
|
}
|
|
|
|
public boolean containsAny(FacingList facings)
|
|
{
|
|
return (code & facings.code) != 0;
|
|
}
|
|
|
|
public boolean notContains(Facing direction)
|
|
{
|
|
return (code & 1 << direction.getIndex()) == 0;
|
|
}
|
|
|
|
public boolean notContains(FacingList facings)
|
|
{
|
|
return (code & facings.code) != facings.code;
|
|
}
|
|
|
|
public FacingList flipFacing(Facing facing)
|
|
{
|
|
return contains(facing) ? remove(facing).add(facing.opposite()) : this;
|
|
}
|
|
|
|
public FacingList flipAxis(Axis axis)
|
|
{
|
|
FacingList result = this;
|
|
for(int i = 0,m=array.length;i<m;i++)
|
|
{
|
|
if(array[i].getAxis() == axis)
|
|
{
|
|
result = result.remove(array[i]).add(array[i].opposite());
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public Vec2i getOffset()
|
|
{
|
|
return offset;
|
|
}
|
|
|
|
public Facing getFacing(int index)
|
|
{
|
|
return array[index];
|
|
}
|
|
|
|
public int getCode()
|
|
{
|
|
return code;
|
|
}
|
|
|
|
public int size()
|
|
{
|
|
return count;
|
|
}
|
|
|
|
public boolean isEmpty()
|
|
{
|
|
return code == 0;
|
|
}
|
|
|
|
public boolean isFull()
|
|
{
|
|
return code == 15;
|
|
}
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
StringJoiner joiner = new StringJoiner(",", "[", "]");
|
|
for(int i = 0,m=array.length;i<m;i++)
|
|
{
|
|
joiner.add(array[i].getName());
|
|
}
|
|
return joiner.toString();
|
|
}
|
|
|
|
@Override
|
|
public boolean test(Facing t)
|
|
{
|
|
return (code & 1 << t.getIndex()) != 0;
|
|
}
|
|
|
|
@Override
|
|
public Iterator<Facing> iterator()
|
|
{
|
|
return new Iterator<Facing>(){
|
|
int index = 0;
|
|
@Override
|
|
public boolean hasNext()
|
|
{
|
|
return index < size();
|
|
}
|
|
|
|
@Override
|
|
public Facing next()
|
|
{
|
|
return array[index++];
|
|
}
|
|
};
|
|
}
|
|
|
|
public static int toNumber(Facing...facings)
|
|
{
|
|
int value = 0;
|
|
for(int i = 0,m=facings.length;i<m;i++)
|
|
{
|
|
value |= (1 << facings[i].getIndex());
|
|
}
|
|
return value & 15;
|
|
}
|
|
|
|
public static int toNumber(boolean[] facings)
|
|
{
|
|
return (facings[0] ? 1 : 0) << 0 | (facings[1] ? 1 : 0) << 1 | (facings[2] ? 1 : 0) << 2 | (facings[3] ? 1 : 0) << 3;
|
|
}
|
|
|
|
public static boolean[] toFlags(Facing...facings)
|
|
{
|
|
boolean[] array = new boolean[4];
|
|
for(int i = 0,m=facings.length;i<m;i++)
|
|
{
|
|
array[facings[i].getIndex()] = true;
|
|
}
|
|
return array;
|
|
}
|
|
|
|
private static FacingList[] createArray()
|
|
{
|
|
FacingList[] facings = new FacingList[16];
|
|
for(int i = 0;i<16;i++)
|
|
{
|
|
facings[i] = new FacingList(i);
|
|
}
|
|
return facings;
|
|
}
|
|
}
|