Skip to content

Commit

Permalink
Mejoras en Tests y Transicion
Browse files Browse the repository at this point in the history
  • Loading branch information
Awes0meM4n committed Aug 13, 2020
1 parent 1fd881e commit 1361aa5
Show file tree
Hide file tree
Showing 6 changed files with 313 additions and 165 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

group = 'es.lanyu'
version = '1.0.2'
version = '1.0.3'
sourceCompatibility = 1.8
targetCompatibility = 1.8

Expand Down
202 changes: 114 additions & 88 deletions src/main/java/es/lanyu/commons/math/MathUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,98 +4,124 @@
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.concurrent.ThreadLocalRandom;

/**Clase de utilidad para realizar operaciones matematicas como
* {@link MathUtils#horquillar(Comparable, Comparable, Comparable)} entre dos valores,
* redondeos o dividir un arco en {@code N} puntos.
/**
* Clase de utilidad para realizar operaciones matematicas como
* {@link MathUtils#horquillar(Comparable, Comparable, Comparable)} entre dos
* valores, redondeos o dividir un arco en {@code N} puntos.
*
* @author <a href="https://github.com/Awes0meM4n">Awes0meM4n</a>
* @version 1.0
* @version 1.0.3
* @since 1.0
*/
public class MathUtils {

/**Devuelve el valor que estara entre {@code min} y {@code max}. Al ser un metodo generico
* puede compararse cualquier tipo {@link Comparable}
* @param <T> Debe ser un tipo que pueda compararse
* @param val Valor de inicio. Puede exceder de los limites
* @param min Valor minimo del resultado
* @param max Valor maximo del resultado
* @return Valor que se aproxima a {@code val} sin exceder los limites
*/
public static <T extends Comparable<T>> T horquillar (T val, T min, T max) {
if (val.compareTo(min) < 0) return min;
else if (val.compareTo(max) > 0) return max;
else return val;
}

/**Calcula una {@link Collection} de dimension {@code numeroPuntos} de tipo {@link Punto} repartidos
* por el arco definido por los argumentos pasados
* @param tipo {@code T} implementando {@link Vector2d} para usar
* @param xCentro Coordenada X del centro del arco
* @param yCentro Coordenada Y del centro del arco
* @param radio Valor del radio del arco
* @param numeroPuntos Numero de puntos entre los que divir el arco
* @param inclinacionInicial Angulo inicial del que empezar a dividir
* @param anguloArco Angulo del arco (no tiene que ser toda la circunferencia)
* @param sentidoDelReloj {@code true} para dividir en sentido horario, si no {@code false}
* @param <T> Tipo {@code T} que debe tener un constructor con parametros (int, int) si no arrojara una excepcion
* @return {@code Collection<Point>} con los puntos que dividen el arco en partes iguales
*/
public static <T extends Vector2d> Collection<T> generarPuntosEnArcoCircular(Class<T> tipo,
double xCentro, double yCentro, double radio, int numeroPuntos,
double inclinacionInicial, double anguloArco, boolean sentidoDelReloj) {
Collection<T> coordenadas = new LinkedHashSet<>();
int[][] coorCrudas = generarPuntosEnArcoCircularCrudos(xCentro, yCentro, radio, numeroPuntos,
inclinacionInicial, anguloArco, sentidoDelReloj);
try {
Constructor<T> constructor = tipo.getConstructor(Float.class, Float.class);
for(int i = 0; i < coorCrudas.length; i++){
coordenadas.add(constructor.newInstance(coorCrudas[i][0]*1f, coorCrudas[i][1]*1f));
}
} catch (NoSuchMethodException | SecurityException | InstantiationException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
e1.printStackTrace();
}

return coordenadas;
}

/**Metodo auxiliar que reliza el calculo pedido por
* {@link MathUtils#generarPuntosEnArcoCircular(double, double, double, int, double, double, boolean)}
* pero devuelve un array bidimensional con las coordenadas de los puntos que luego son pasadas a {@link Point}.
* @param xCentro Coordenada X del centro del arco
* @param yCentro Coordenada Y del centro del arco
* @param radio Valor del radio del arco
* @param numeroPuntos Numero de puntos entre los que divir el arco
* @param inclinacionInicial Angulo inicial del que empezar a dividir
* @param anguloArco Angulo del arco (no tiene que ser toda la circunferencia)
* @param sentidoDelReloj {@code true} para dividir en sentido horario, si no {@code false}
* @return Array bidimensional con las coordenadas que dividen el arco en partes iguales
*/
private static int[][] generarPuntosEnArcoCircularCrudos(double xCentro, double yCentro, double radio, int numeroPuntos,
double inclinacionInicial, double anguloArco, boolean sentidoDelReloj) {
int[][] coordenadas = new int[numeroPuntos][2];
double anguloEntrePuntos = 0;
if (numeroPuntos > 1)
anguloEntrePuntos = anguloArco/(numeroPuntos-1) * ((sentidoDelReloj) ? -1 : 1);

for (int i = 0; i < numeroPuntos; i++) {
double a = i * anguloEntrePuntos + inclinacionInicial;
//Coordenada X
coordenadas[i][0] = (int)(radio * Math.sin(a) + xCentro);
//Coordenada Y
coordenadas[i][1] = (int)(radio * Math.cos(a) + yCentro);
}

return coordenadas;
}

public static String floatEnEntero(float f) {
return floatEnEntero(f, true);
}

public static String floatEnEntero(float f, boolean devolverNegativo) {
if (devolverNegativo) return Math.round(f) + "";
else return (f > 0) ? Math.round(f) + "" : "";
}
/**
* Devuelve el valor que estara entre {@code min} y {@code max}. Al ser un
* metodo generico puede compararse cualquier tipo {@link Comparable}
*
* @param <T> Debe ser un tipo que pueda compararse
* @param val Valor de inicio. Puede exceder de los limites
* @param min Valor minimo del resultado
* @param max Valor maximo del resultado
* @return Valor que se aproxima a {@code val} sin exceder los limites
*/
public static <T extends Comparable<T>> T horquillar(T val, T min, T max) {
if (val.compareTo(min) < 0) return min;
else if (val.compareTo(max) > 0) return max;
else return val;
}

/**
* Calcula una {@link Collection} de dimension {@code numeroPuntos} de tipo
* {@link Punto} repartidos por el arco definido por los argumentos pasados
*
* @param tipo {@code T} implementando {@link Vector2d} para usar
* @param xCentro Coordenada X del centro del arco
* @param yCentro Coordenada Y del centro del arco
* @param radio Valor del radio del arco
* @param numeroPuntos Numero de puntos entre los que divir el arco
* @param inclinacionInicial Angulo inicial del que empezar a dividir
* @param anguloArco Angulo del arco (no tiene que ser toda la circunferencia)
* @param sentidoDelReloj {@code true} para dividir en sentido horario, si no {@code false}
* @param <T> Tipo {@code T} que debe tener un constructor con parametros (int, int) si no arrojara una excepcion
* @return {@code Collection<Point>} con los puntos que dividen el arco en partes iguales
*/
public static <T extends Vector2d> Collection<T> generarPuntosEnArcoCircular(Class<T> tipo,
double xCentro, double yCentro, double radio, int numeroPuntos,
double inclinacionInicial, double anguloArco, boolean sentidoDelReloj) {
Collection<T> coordenadas = new LinkedHashSet<>();
int[][] coorCrudas = generarPuntosEnArcoCircularCrudos(xCentro, yCentro, radio, numeroPuntos,
inclinacionInicial, anguloArco, sentidoDelReloj);
try {
Constructor<T> constructor = tipo.getConstructor(Float.class, Float.class);
for (int i = 0; i < coorCrudas.length; i++) {
coordenadas.add(constructor.newInstance(coorCrudas[i][0] * 1f, coorCrudas[i][1] * 1f));
}
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e1) {
e1.printStackTrace();
}

return coordenadas;
}

/**
* Metodo auxiliar que reliza el calculo pedido por
* {@link MathUtils#generarPuntosEnArcoCircular(double, double, double, int, double, double, boolean)}
* pero devuelve un array bidimensional con las coordenadas de los puntos
* que luego son pasadas a {@link Point}.
*
* @param xCentro Coordenada X del centro del arco
* @param yCentro Coordenada Y del centro del arco
* @param radio Valor del radio del arco
* @param numeroPuntos Numero de puntos entre los que divir el arco
* @param inclinacionInicial Angulo inicial del que empezar a dividir
* @param anguloArco Angulo del arco (no tiene que ser toda la circunferencia)
* @param sentidoDelReloj {@code true} para dividir en sentido horario, si no {@code false}
* @return Array bidimensional con las coordenadas que dividen el arco en partes iguales
*/
private static int[][] generarPuntosEnArcoCircularCrudos(double xCentro, double yCentro, double radio,
int numeroPuntos, double inclinacionInicial, double anguloArco, boolean sentidoDelReloj) {
int[][] coordenadas = new int[numeroPuntos][2];
double anguloEntrePuntos = 0;
if (numeroPuntos > 1)
anguloEntrePuntos = anguloArco / (numeroPuntos - 1) * ((sentidoDelReloj) ? -1 : 1);

for (int i = 0; i < numeroPuntos; i++) {
double a = i * anguloEntrePuntos + inclinacionInicial;
// Coordenada X
coordenadas[i][0] = (int) (radio * Math.sin(a) + xCentro);
// Coordenada Y
coordenadas[i][1] = (int) (radio * Math.cos(a) + yCentro);
}

return coordenadas;
}

public static String floatEnEntero(float f) {
return floatEnEntero(f, true);
}

public static String floatEnEntero(float f, boolean devolverNegativo) {
if (devolverNegativo) return Math.round(f) + "";
else return (f > 0) ? Math.round(f) + "" : "";
}

// Ver https://stackoverflow.com/a/51256264
// El redondeo puede hacer que en valores muy cercanos max sea < que min
// Con los comentarios actuales funciona con tandas largas
public static float generarFloatRandom(float min, float max) {
// if (min >= max)
// throw new IllegalArgumentException("max must be greater than min");
float result = nextFloat() * (max - min) + min;
// if (result >= max) // correct for rounding
// result = Float.intBitsToFloat(Float.floatToIntBits(max) - 1);
return result;
}

public static float nextFloat() {
return ThreadLocalRandom.current().nextFloat();
}
}
156 changes: 81 additions & 75 deletions src/main/java/es/lanyu/commons/math/Transicion.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,83 +2,89 @@

import java.util.function.Function;

/**Permite crear una transicion entre dos estados y actualizar su estado en funcion del tiempo
* transcurrido. Tambien permite invertir la transicion. Al usar valores {@code float} permite
* definir multiples transiciones (puede usarse para movimiento usando transciones para cada coordenada
* o mutar de un color a otro creando una transicion para cada componente R, G y B)
/**
* Permite crear una transicion entre dos estados y actualizar su estado en
* funcion del tiempo transcurrido. Tambien permite invertir la transicion.
* Al usar valores {@code float} permite definir multiples transiciones (puede
* usarse para movimiento usando transiciones para cada coordenada o mutar de un
* color a otro creando una transicion para cada componente R, G y B)
*
* @author <a href="https://github.com/Awes0meM4n">Awes0meM4n</a>
* @version 1.0
* @version 1.0.3
* @since 1.0
*/
public class Transicion {
float valorInicial;
float valorFinal;
float miliSegundosParaTransicion;
Function<Float, Float> funcion;

float deltaPorMiliSegundo;
boolean finActualizacion = false;
float valorActual;

public float getValorActual() {
return valorActual;
}

public boolean esFinActualizacion() {
return finActualizacion;
}

public void setFinActualizacion(boolean finActualizacion) {
this.finActualizacion = finActualizacion;
}

public static void actualizarTransiciones(Transicion[] transiciones, float delta){
for(Transicion t : transiciones){
t.updateValor(delta);
}
}

public <T, R> Transicion(float valorInicial, float valorFinal, float miliSegundosParaTransicion, Function<Float, Float> funcion){
this(valorInicial, valorFinal, miliSegundosParaTransicion);
this.funcion = funcion;
}

public Transicion(float valorInicial, float valorFinal, float miliSegundosParaTransicion) {
super();
this.valorInicial = valorInicial;
this.valorFinal = valorFinal;
this.miliSegundosParaTransicion = miliSegundosParaTransicion;
this.funcion = new Function<Float, Float>() {
@Override
public Float apply(Float t) {
return deltaPorMiliSegundo*t;
}
};
valorActual = valorInicial;

deltaPorMiliSegundo = (valorFinal - valorInicial)/this.miliSegundosParaTransicion;
}

public float updateValor(float delta){
if(!finActualizacion){
valorActual += funcion.apply(delta);

if(deltaPorMiliSegundo > 0)
finActualizacion = valorActual >= valorFinal;
else
finActualizacion = valorActual <= valorFinal;

if(finActualizacion)
valorActual = valorFinal;
}

return valorActual;
}

public void flipTransicion(){
valorFinal = valorInicial;
valorInicial = valorActual;
finActualizacion = false;
}

private float valorInicial;
private float valorFinal;
private Function<Float, Float> funcion;

private float deltaPorMiliSegundo;
private boolean finActualizacion = false;
private float valorActual;

protected Function<Float, Float> getFuncion() {
return funcion;
}

public float getValorActual() {
return valorActual;
}

private void setValorActual(float valorActual) {
this.valorActual = valorActual;
}

public boolean esFinActualizacion() {
return finActualizacion;
}

public void setFinActualizacion(boolean finActualizacion) {
this.finActualizacion = finActualizacion;
}

public static void actualizarTransiciones(Transicion[] transiciones, float delta) {
for (Transicion t : transiciones) {
t.updateValor(delta);
}
}

public Transicion(float valorInicial, float valorFinal, float miliSegundosParaTransicion,
Function<Float, Float> funcion) {
this(valorInicial, valorFinal, miliSegundosParaTransicion);
this.funcion = funcion;
}

public Transicion(float valorInicial, float valorFinal, float miliSegundosParaTransicion) {
super();
this.valorInicial = valorInicial;
this.valorFinal = valorFinal;
this.funcion = t -> deltaPorMiliSegundo * t;
setValorActual(valorInicial);

deltaPorMiliSegundo = (valorFinal - valorInicial) / miliSegundosParaTransicion;
}

public float updateValor(float delta) {
if (!finActualizacion) {
setValorActual(getValorActual() + getFuncion().apply(delta));

if (deltaPorMiliSegundo > 0)
finActualizacion = getValorActual() >= valorFinal;
else
finActualizacion = getValorActual() <= valorFinal;

if (finActualizacion)
setValorActual(valorFinal);
}

return getValorActual();
}

public void flipTransicion() {
valorFinal = valorInicial;
valorInicial = getValorActual();
finActualizacion = false;
deltaPorMiliSegundo = -deltaPorMiliSegundo;
}

}
Loading

0 comments on commit 1361aa5

Please sign in to comment.