package choonster.testmod3.util; import com.google.common.collect.Maps; import gnu.trove.TCollections; import gnu.trove.map.TObjectDoubleMap; import gnu.trove.map.hash.TObjectDoubleHashMap; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.Vec3i; import javax.vecmath.AxisAngle4d; import javax.vecmath.Matrix3d; import javax.vecmath.Vector3d; import java.util.HashMap; import java.util.Map; /** * Utility methods for vectors and {@link AxisAlignedBB}s. * * @author Choonster */ public class VectorUtils { /** * A cache of the positive facing's direction vector for each axis. */ private static final Map<EnumFacing.Axis, Vec3i> AXIS_DIRECTION_VECTORS; private static final TObjectDoubleMap<EnumFacing> HORIZONTAL_ROTATIONS; static { final Map<EnumFacing.Axis, Vec3i> axisVectors = new HashMap<>(); for (final EnumFacing.Axis axis : EnumFacing.Axis.values()) { // For each axis, // Get the direction vector of the positive facing of the axis final Vec3i directionVec = EnumFacing.getFacingFromAxis(EnumFacing.AxisDirection.POSITIVE, axis).getDirectionVec(); axisVectors.put(axis, directionVec); // Add it to the map } AXIS_DIRECTION_VECTORS = Maps.immutableEnumMap(axisVectors); // Wrap the map in an immutable enum map // 90 degrees in radians final double rotationIncrement = Math.toRadians(90); final TObjectDoubleMap<EnumFacing> horizontalRotations = new TObjectDoubleHashMap<>(); horizontalRotations.put(EnumFacing.NORTH, 0); horizontalRotations.put(EnumFacing.EAST, rotationIncrement); horizontalRotations.put(EnumFacing.SOUTH, 2 * rotationIncrement); horizontalRotations.put(EnumFacing.WEST, 3 * rotationIncrement); HORIZONTAL_ROTATIONS = TCollections.unmodifiableMap(horizontalRotations); } /** * Create a matrix that rotates around the specified axis by the specified angle. * * @param axis The axis * @param radians The angle in radians * @return The rotation matrix */ public static Matrix3d getRotationMatrix(EnumFacing.Axis axis, double radians) { final Vec3i axisDirectionVector = AXIS_DIRECTION_VECTORS.get(axis); final AxisAngle4d axisAngle = new AxisAngle4d(axisDirectionVector.getX(), axisDirectionVector.getY(), axisDirectionVector.getZ(), radians); final Matrix3d rotationMatrix = new Matrix3d(); rotationMatrix.set(axisAngle); return rotationMatrix; } /** * Rotate an {@link AxisAlignedBB} by the specified rotation matrix. * * @param axisAlignedBB The AABB * @param rotationMatrix The rotation matrix * @param forcePositive If true, set each coordinate of the rotated AABB to it absolute value * @return The rotated AABB */ public static AxisAlignedBB rotateAABB(AxisAlignedBB axisAlignedBB, Matrix3d rotationMatrix, boolean forcePositive) { // Extract the minimum and maximum coordinates of the AABB into vectors final Vector3d minCoords = new Vector3d(axisAlignedBB.minX, axisAlignedBB.minY, axisAlignedBB.minZ); final Vector3d maxCoords = new Vector3d(axisAlignedBB.maxX, axisAlignedBB.maxY, axisAlignedBB.maxZ); // Rotate the vectors in-place rotationMatrix.transform(minCoords); rotationMatrix.transform(maxCoords); if (forcePositive) { // Get the absolute value of the coordinates minCoords.absolute(); maxCoords.absolute(); } // Return an AABB with the new coordinates return new AxisAlignedBB(minCoords.getX(), minCoords.getY(), minCoords.getZ(), maxCoords.getX(), maxCoords.getY(), maxCoords.getZ()); } /** * Get the angle of the specified {@link EnumFacing} relative to {@link EnumFacing#NORTH} along the horizontal plane. * * @param facing The facing * @return The angle in radians */ public static double getHorizontalRotation(EnumFacing facing) { return HORIZONTAL_ROTATIONS.get(facing); } }