/*
* This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT).
*
* Copyright (c) JCThePants (www.jcwhatever.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.jcwhatever.nucleus.internal.providers.math;
import com.jcwhatever.nucleus.providers.math.FastMath;
import com.jcwhatever.nucleus.providers.math.IRotationMatrix;
import com.jcwhatever.nucleus.utils.PreCon;
import com.jcwhatever.nucleus.utils.coords.IVector2D;
import com.jcwhatever.nucleus.utils.coords.IVector3D;
import com.jcwhatever.nucleus.utils.coords.Vector2D;
import com.jcwhatever.nucleus.utils.coords.Vector3D;
import java.math.BigDecimal;
/**
* Nucleus implementation of {@link IRotationMatrix}.
*/
public class NucleusRotationMatrix implements IRotationMatrix {
private static final int ANGLE_PRECISION = 64;
private static final int ANGLE_MODULUS = 361 * ANGLE_PRECISION;
private static NucleusRotationMatrix[] MATRICES = new NucleusRotationMatrix[ANGLE_MODULUS];
static {
for (int i=0; i < MATRICES.length; i++) {
MATRICES[i] = new NucleusRotationMatrix((float)(i / ANGLE_PRECISION) - 180f);
}
}
public static NucleusRotationMatrix get(float rotation) {
while (rotation > 180f)
rotation -= 360f;
while (rotation < -180f)
rotation += 360f;
int index = (int)((rotation + 180) * ANGLE_PRECISION + 0.5f);
return MATRICES[index];
}
private final float _rotation;
private final float _cos;
private final float _sin;
NucleusRotationMatrix(float rotation) {
_rotation = rotation;
_cos = FastMath.cos(_rotation);
_sin = FastMath.sin(_rotation);
/*
newX = x * matrix[0][0] + y * matrix[1][0] + z * matrix[2][0];
newY = x * matrix[0][1] + y * matrix[1][1] + z * matrix[2][1];
newZ = x * matrix[0][2] + y * matrix[1][2] + z * matrix[2][2];
*/
}
@Override
public float getRotation() {
return _rotation;
}
@Override
public IVector2D rotateX(IVector2D vector) {
return rotateX(vector, new Vector2D());
}
@Override
public IVector3D rotateX(IVector3D vector) {
return rotateX(vector, new Vector3D());
}
@Override
public <T extends IVector2D> T rotateX(IVector2D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double z = vector.getZ();
output.setX(x);
output.setZ(z * _cos);
return output;
}
@Override
public <T extends IVector3D> T rotateX(IVector3D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double y = vector.getY();
double z = vector.getZ();
output.setX(x);
output.setY(y * _cos + z * -_sin);
output.setZ(y * _sin + z * _cos);
return output;
}
@Override
public IVector2D rotateY(IVector2D vector) {
return rotateY(vector, new Vector2D());
}
@Override
public IVector3D rotateY(IVector3D vector) {
return rotateY(vector, new Vector3D());
}
@Override
public <T extends IVector2D> T rotateY(IVector2D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double z = vector.getZ();
// using reverse Matrix instead of forward Matrix due to Minecraft's inverted X axis coordinates
// relative to Yaw 0.
output.setX(x * _cos + z * -_sin);
output.setZ(x * _sin + z * _cos);
return output;
}
@Override
public <T extends IVector3D> T rotateY(IVector3D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double y = vector.getY();
double z = vector.getZ();
// using reverse Matrix instead of forward Matrix due to Minecraft's inverted X axis coordinates
// relative to Yaw 0.
output.setX(x * _cos + z * -_sin);
output.setY(y);
output.setZ(x * _sin + z * _cos);
return output;
}
@Override
public IVector2D rotateZ(IVector2D vector) {
return rotateZ(vector, new Vector2D());
}
@Override
public IVector3D rotateZ(IVector3D vector) {
return rotateZ(vector, new Vector3D());
}
@Override
public <T extends IVector2D> T rotateZ(IVector2D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double z = vector.getZ();
output.setX(x * _cos);
output.setZ(z);
return output;
}
@Override
public <T extends IVector3D> T rotateZ(IVector3D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double y = vector.getY();
double z = vector.getZ();
output.setX(x * _cos + y * -_sin);
output.setY(x * _sin + y * _cos);
output.setZ(z);
return output;
}
@Override
public IVector2D rotateReverseX(IVector2D vector) {
return rotateReverseX(vector, new Vector2D());
}
@Override
public IVector3D rotateReverseX(IVector3D vector) {
return rotateReverseX(vector, new Vector3D());
}
@Override
public <T extends IVector2D> T rotateReverseX(IVector2D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double z = vector.getZ();
output.setX(x);
output.setZ(z * _cos);
return output;
}
@Override
public <T extends IVector3D> T rotateReverseX(IVector3D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double y = vector.getY();
double z = vector.getZ();
output.setX(x);
output.setY(y * _cos + z * _sin);
output.setZ(y * -_sin + z * _cos);
return output;
}
@Override
public IVector2D rotateReverseY(IVector2D vector) {
return rotateReverseY(vector, new Vector2D());
}
@Override
public IVector3D rotateReverseY(IVector3D vector) {
return rotateReverseY(vector, new Vector3D());
}
@Override
public <T extends IVector2D> T rotateReverseY(IVector2D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double z = vector.getZ();
// using forward Matrix instead of Reverse Matrix due to Minecraft's inverted X axis coordinates
// relative to Yaw 0.
output.setX(x * _cos + z * _sin);
output.setZ(x * -_sin + z * _cos);
return output;
}
@Override
public <T extends IVector3D> T rotateReverseY(IVector3D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double y = vector.getY();
double z = vector.getZ();
// using forward Matrix instead of Reverse Matrix due to Minecraft's inverted X axis coordinates
// relative to Yaw 0.
output.setX(x * _cos + z * _sin);
output.setY(y);
output.setZ(x * -_sin + z * _cos);
return output;
}
@Override
public IVector2D rotateReverseZ(IVector2D vector) {
return rotateReverseZ(vector, new Vector2D());
}
@Override
public IVector3D rotateReverseZ(IVector3D vector) {
return rotateReverseZ(vector, new Vector3D());
}
@Override
public <T extends IVector2D> T rotateReverseZ(IVector2D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double z = vector.getZ();
output.setX(x * _cos);
output.setZ(z);
return output;
}
@Override
public <T extends IVector3D> T rotateReverseZ(IVector3D vector, T output) {
PreCon.notNull(vector);
PreCon.notNull(output);
double x = vector.getX();
double y = vector.getY();
double z = vector.getZ();
output.setX(x * _cos + y * _sin);
output.setY(x * -_sin + y * _cos);
output.setZ(z);
return output;
}
private static float scale(float value, int scale) {
return new BigDecimal(value)
.setScale(scale, BigDecimal.ROUND_HALF_UP).floatValue();
}
}