/*
* Copyright (c) 2015 NOVA, All rights reserved.
* This library is free software, licensed under GNU Lesser General Public License version 3
*
* This file is part of NOVA.
*
* NOVA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NOVA. If not, see <http://www.gnu.org/licenses/>.
*/
package nova.core.util.math;
import nova.core.render.model.Face;
import nova.core.render.model.Vertex;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.apache.commons.math3.util.FastMath;
import java.util.Random;
/**
* An extension of Apache Common's Vector3D class
* @author Calclavia
*/
public class Vector3DUtil {
private Vector3DUtil() {
}
public static final Vector3D ONE = new Vector3D(1, 1, 1);
public static final Vector3D CENTER = new Vector3D(0.5, 0.5, 0.5);
public static final Vector3D FORWARD = Vector3D.MINUS_K;
/**
* @return Creates a random unit vector
*/
public static Vector3D random() {
Random random = new Random();
return new Vector3D(random.nextDouble(), random.nextDouble(), random.nextDouble()).scalarMultiply(2).subtract(ONE);
}
/**
* Calculates maximum of each coordinate.
*
* @param a first vector.
* @param b second vector.
* @return new vector that's each coordinate is maximum of coordinates of a and b.
*/
public static Vector3D max(Vector3D a, Vector3D b) {
return new Vector3D(FastMath.max(a.getX(), b.getX()), FastMath.max(a.getY(), b.getY()), FastMath.max(a.getZ(), b.getZ()));
}
/**
* Calculates minimum of each coordinate.
* @param a first vector.
* @param b second vector.
* @return new vector that's each coordinate is minimum of coordinates of a and b.
*/
public static Vector3D min(Vector3D a, Vector3D b) {
return new Vector3D(FastMath.min(a.getX(), b.getX()), FastMath.min(a.getY(), b.getY()), FastMath.min(a.getZ(), b.getZ()));
}
public static Vector3D cartesianProduct(Vector3D a, Vector3D b) {
return new Vector3D(a.getX() * b.getX(), a.getY() * b.getY(), a.getZ() * b.getZ());
}
public static Vector3D xCross(Vector3D vec) {
return new Vector3D(0, vec.getZ(), -vec.getY());
}
public static Vector3D zCross(Vector3D vec) {
return new Vector3D(-vec.getY(), vec.getX(), 0);
}
/**
* Calculates middle point between two vectors.
* @param a first vector.
* @param b second vector.
* @return new vectors that is in the middle of a and b.
*/
public static Vector3D midpoint(Vector3D a, Vector3D b) {
return a.add(b).scalarMultiply(0.5);
}
/**
* Calculates one by vectos.
* @param vec vector to be reciprocated.
* @return reciprocal of vec.
*/
public static Vector3D reciprocal(Vector3D vec) {
return new Vector3D(1 / vec.getX(), 1 / vec.getY(), 1 / vec.getZ());
}
public static Vector3D perpendicular(Vector3D vec) {
// Special case. Z == 0 would cause a error.
//noinspection FloatingPointEquality
if (vec.getZ() == 0) {
return zCross(vec);
}
return xCross(vec);
}
public static Vector3D round(Vector3D vec) {
return new Vector3D(FastMath.round(vec.getX()), FastMath.round(vec.getY()), FastMath.round(vec.getZ()));
}
public static Vector3D ceil(Vector3D vec) {
return new Vector3D(FastMath.ceil(vec.getX()), FastMath.ceil(vec.getY()), FastMath.ceil(vec.getZ()));
}
public static Vector3D floor(Vector3D vec) {
return new Vector3D(FastMath.floor(vec.getX()), FastMath.floor(vec.getY()), FastMath.floor(vec.getZ()));
}
public static Vector3D abs(Vector3D vec) {
return new Vector3D(FastMath.abs(vec.getX()), FastMath.abs(vec.getY()), FastMath.abs(vec.getZ()));
}
public static Vector3D calculateNormal(Face face) {
// TODO: Possibly calculate from vertex normals
Vertex firstEntry = face.vertices.get(0);
Vertex secondEntry = face.vertices.get(1);
Vertex thirdEntry = face.vertices.get(2);
Vector3D v1 = secondEntry.vec.subtract(firstEntry.vec);
Vector3D v2 = thirdEntry.vec.subtract(firstEntry.vec);
return v1.crossProduct(v2).normalize();
}
}