package openmods.geometry; import com.google.common.base.Preconditions; import gnu.trove.map.TIntObjectMap; import gnu.trove.map.hash.TIntObjectHashMap; import net.minecraftforge.common.util.ForgeDirection; public enum Orientation { XN_YN(HalfAxis.NEG_X, HalfAxis.NEG_Y), XN_YP(HalfAxis.NEG_X, HalfAxis.POS_Y), XN_ZN(HalfAxis.NEG_X, HalfAxis.NEG_Z), XN_ZP(HalfAxis.NEG_X, HalfAxis.POS_Z), XP_YN(HalfAxis.POS_X, HalfAxis.NEG_Y), XP_YP(HalfAxis.POS_X, HalfAxis.POS_Y), XP_ZN(HalfAxis.POS_X, HalfAxis.NEG_Z), XP_ZP(HalfAxis.POS_X, HalfAxis.POS_Z), YN_ZP(HalfAxis.NEG_Y, HalfAxis.POS_Z), YN_XN(HalfAxis.NEG_Y, HalfAxis.NEG_X), YN_XP(HalfAxis.NEG_Y, HalfAxis.POS_X), YN_ZN(HalfAxis.NEG_Y, HalfAxis.NEG_Z), YP_XN(HalfAxis.POS_Y, HalfAxis.NEG_X), YP_XP(HalfAxis.POS_Y, HalfAxis.POS_X), YP_ZN(HalfAxis.POS_Y, HalfAxis.NEG_Z), YP_ZP(HalfAxis.POS_Y, HalfAxis.POS_Z), ZN_XP(HalfAxis.NEG_Z, HalfAxis.POS_X), ZN_XN(HalfAxis.NEG_Z, HalfAxis.NEG_X), ZN_YP(HalfAxis.NEG_Z, HalfAxis.POS_Y), ZN_YN(HalfAxis.NEG_Z, HalfAxis.NEG_Y), ZP_XN(HalfAxis.POS_Z, HalfAxis.NEG_X), ZP_XP(HalfAxis.POS_Z, HalfAxis.POS_X), ZP_YN(HalfAxis.POS_Z, HalfAxis.NEG_Y), ZP_YP(HalfAxis.POS_Z, HalfAxis.POS_Y); public static final Orientation[] VALUES = values(); private static final TIntObjectMap<Orientation> LOOKUP_XY = new TIntObjectHashMap<Orientation>(VALUES.length); private static final TIntObjectMap<Orientation> LOOKUP_XZ = new TIntObjectHashMap<Orientation>(VALUES.length); private static final TIntObjectMap<Orientation> LOOKUP_YZ = new TIntObjectHashMap<Orientation>(VALUES.length); private static final Orientation[][] ROTATIONS = new Orientation[VALUES.length][HalfAxis.VALUES.length]; private static int lookupKey(HalfAxis a, HalfAxis b) { return (a.ordinal() << 3) | (b.ordinal() << 0); } private static void addToLookup(TIntObjectMap<Orientation> lookup, Orientation o, HalfAxis a, HalfAxis b) { final int key = lookupKey(a, b); final Orientation prev = lookup.put(key, o); Preconditions.checkState(prev == null, "Key %s duplicate: %s->%s", key, prev, o); } static { for (Orientation o : VALUES) { addToLookup(LOOKUP_XY, o, o.x, o.y); addToLookup(LOOKUP_YZ, o, o.y, o.z); addToLookup(LOOKUP_XZ, o, o.x, o.z); } for (Orientation o : VALUES) { final int i = o.ordinal(); ROTATIONS[i][HalfAxis.POS_X.ordinal()] = lookupXYNotNull(o.x, o.z.negate()/* , o.y */); ROTATIONS[i][HalfAxis.NEG_X.ordinal()] = lookupXYNotNull(o.x, o.z/* , o.y.negate() */); ROTATIONS[i][HalfAxis.POS_Y.ordinal()] = lookupXYNotNull(o.z, o.y/* , o.x.negate() */); ROTATIONS[i][HalfAxis.NEG_Y.ordinal()] = lookupXYNotNull(o.z.negate(), o.y/* , o.x */); ROTATIONS[i][HalfAxis.POS_Z.ordinal()] = lookupXYNotNull(o.y.negate(), o.x/* , o.z */); ROTATIONS[i][HalfAxis.NEG_Z.ordinal()] = lookupXYNotNull(o.y, o.x.negate()/* , o.z */); } } public static Orientation lookupXY(HalfAxis x, HalfAxis y) { final int key = lookupKey(x, y); return LOOKUP_XY.get(key); } public static Orientation lookupXZ(HalfAxis x, HalfAxis z) { final int key = lookupKey(x, z); return LOOKUP_XZ.get(key); } public static Orientation lookupYZ(HalfAxis y, HalfAxis z) { final int key = lookupKey(y, z); return LOOKUP_YZ.get(key); } private static Orientation lookupXYNotNull(HalfAxis x, HalfAxis y) { Orientation v = lookupXY(x, y); if (v == null) throw new NullPointerException(x + ":" + y); return v; } public static Orientation rotateAround(Orientation orientation, HalfAxis axis) { return ROTATIONS[orientation.ordinal()][axis.ordinal()]; } public Orientation rotateAround(HalfAxis axis) { return rotateAround(this, axis); } public final HalfAxis x; // +X, east public final HalfAxis y; // +Y, top public final HalfAxis z; // +Z, south private final ForgeDirection[] localToGlobalDirections = new ForgeDirection[ForgeDirection.values().length]; private final ForgeDirection[] globalToLocalDirections = new ForgeDirection[ForgeDirection.values().length]; private void addDirectionMapping(ForgeDirection local, ForgeDirection global) { localToGlobalDirections[local.ordinal()] = global; globalToLocalDirections[global.ordinal()] = local; } private void addDirectionMappings(ForgeDirection local, ForgeDirection global) { addDirectionMapping(local, global); addDirectionMapping(local.getOpposite(), global.getOpposite()); } private Orientation(HalfAxis x, HalfAxis y) { this.x = x; this.y = y; this.z = x.cross(y); addDirectionMappings(ForgeDirection.EAST, x.dir); addDirectionMappings(ForgeDirection.UP, y.dir); addDirectionMappings(ForgeDirection.SOUTH, z.dir); addDirectionMapping(ForgeDirection.UNKNOWN, ForgeDirection.UNKNOWN); } public ForgeDirection localToGlobalDirection(ForgeDirection local) { return localToGlobalDirections[local.ordinal()]; } public ForgeDirection globalToLocalDirection(ForgeDirection global) { return globalToLocalDirections[global.ordinal()]; } public ForgeDirection north() { return localToGlobalDirection(ForgeDirection.NORTH); } public ForgeDirection south() { return localToGlobalDirection(ForgeDirection.SOUTH); } public ForgeDirection east() { return localToGlobalDirection(ForgeDirection.EAST); } public ForgeDirection west() { return localToGlobalDirection(ForgeDirection.WEST); } public ForgeDirection up() { return localToGlobalDirection(ForgeDirection.UP); } public ForgeDirection down() { return localToGlobalDirection(ForgeDirection.DOWN); } public double transformX(double x, double y, double z) { return this.x.x * x + this.y.x * y + this.z.x * z; } public int transformX(int x, int y, int z) { return this.x.x * x + this.y.x * y + this.z.x * z; } public double transformY(double x, double y, double z) { return this.x.y * x + this.y.y * y + this.z.y * z; } public int transformY(int x, int y, int z) { return this.x.y * x + this.y.y * y + this.z.y * z; } public double transformZ(double x, double y, double z) { return this.x.z * x + this.y.z * y + this.z.z * z; } public int transformZ(int x, int y, int z) { return this.x.z * x + this.y.z * y + this.z.z * z; } public Matrix3d createTransformMatrix() { // basis change matrix - local east (X), up (Y), south (Z) are new basis vectors final Matrix3d mat = new Matrix3d(); mat.m00 = x.x; mat.m01 = x.y; mat.m02 = x.z; mat.m10 = y.x; mat.m11 = y.y; mat.m12 = y.z; mat.m20 = z.x; mat.m21 = z.y; mat.m22 = z.z; return mat; } }