miércoles, 24 de agosto de 2011

Math Engine : Capitulo 2. Clase LPVector

Capítulo perteneciente al math engine LordPakus

Hola a todos,

Bienvenidos a un nuevo capitulo del math engine.

El capitulo de hoy trata sobre la clase LPVector que es la que se encarga de almacenar un vector de cualquier tamaño y poder opera con el.

La lista de operaciones que he considerado imprescindibles son las siguientes, todas las que querais que pongamos adicionales las ponemos... a la que tengamos una lista estable de operaciones nos dedicaremos a optimizarlas con SSE.:
//Funciones anexas.
    void Set(int t, float* vector); //Funcion para inicializar un vector de n elementos
    void Delete();                    //Función para limpiar la variable vector
    void print();                    //Función para imprimir el vector por la consola


    //OPERACIONES DE AMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
    //Operaciones vectoriales
    void operator +=(LPVector vector);           
    void operator -=(LPVector vector);           
    void sqrt_vec();                        //Calculamos la raíz cuadrada de todo los elementos del vector
    void normalize();                        //Normaliza el vector (hace que el módulo sea 1)

    //Operaciones con escalares ( sumar , restar , etc ... todo un vector por un escalar)
    void operator +=(float scal);
    void operator -=(float scal);
    void operator *=(float scal);
    void operator /=(float scal);


    //OPERACIONES QUE DEVUELVEN ALGO (NO ACUMULADORES: +,-,*, etc...)
    //Operaciones vectoriales que devuelven escalares
    float operator ^(LPVector vector);            //Operador producto escalar.
    float module();                                //Calcula el módulo del vector

El código se organiza en dos archivos LPVector (.cpp y .h) junto con los cambios del main para demostrar que funcionan:

main.cpp:
/**************************************************************************************************/
//        Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
//        para el blog LordPakus (http://lordpakus.blogspot.com/).
//        Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/

/**************************************************************************************************/
// main.cpp : Main de nuestro MathEngine
/**************************************************************************************************/

//Include del Math engine
#include "LPMath.h"

//Delete console
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

#include <iostream>                //Usada para imprimir por consola

using namespace std;

int main (int argc, char* argv[])
{
    LPVector v1,v2;
    float vec1[4] = { 1.0f ,1.1f ,1.5f ,2.5f };
    float vec2[4] = { 3.0f ,4.1f ,0.5f ,0.4f };

    float n;

    //Creamos los vectores
    v1.Set(4,vec1);
    v2.Set(4,vec2);

    cout << "Vector 1: ";
    v1.print();
    cout << "\n";

    cout << "Vector 2: ";
    v2.print();
    cout << "\n";
   
    n = v1^v2;
    cout << "Producto escalar: " <<    n << "\n";

    n = v1.module();
    cout << "Modulo vector 1: " <<    n << "\n";

    n = v2.module();
    cout << "Modulo vector 2: " <<    n << "\n";

    v1.normalize();
    n = v1.module();
    cout << "Modulo vector 1 normalizado: " <<    n << "\n";

    v2.normalize();
    n = v2.module();
    cout << "Modulo vector 2 normalizado: " <<    n << "\n";

    v2 += v1;
    cout << "Suma de vectores: ";
    v2.print();
    cout << "\n";

    n = v2.module();
    cout << "Modulo de suma de vectores: " <<    n << "\n";

    v2.normalize();
    n = v2.module();
    cout << "Modulo de suma de vectores normalizado: " <<    n << "\n";


    //Eliminamos los vectores
    v1.Delete();
    v2.Delete();

    system("PAUSE");
}

LPVector.cpp
/**************************************************************************************************/
//        Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
//        para el blog LordPakus (http://lordpakus.blogspot.com/).
//        Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/

#include "LPVector.h"
#include <math.h>
#include <iostream>                //Usada para imprimir por consola

using namespace std;

//Constructor
LPVector::LPVector()
{
    n = 0;
    v = NULL;
}

//Destructor
LPVector::~LPVector()
{
    //if (n)
    //{
    //    if( v != NULL )
    //        free(v);
    //}
}

//Funcion para inicializar un vector de n elementos
void LPVector::Set(int t, float* vector)
{
    n = t; //Inicializamos el número de elementos del vector

    //Creamos un vector de memoria dinámica.
    v = (float*) malloc( sizeof(float) * n );

    //Copiamos el vector externo en el vector interno
    memcpy(v,vector,sizeof(float) * n );
}

//Función para limpiar la variable vector
void LPVector::Delete()
{
    n=0;
    free(v);
}

//Imprimimos el valor del vector
void LPVector::print()
{
    for(int i = 0 ; i < n ; ++i)
    {
        cout << (float) v[i] << " ";
    }
}

void LPVector::random(int t, float min, float max)
{
    n = t; //Inicializamos el número de elementos del vector

    //Creamos un vector de memoria dinámica.
    v = (float*) malloc( sizeof(float) * n );

    for(int i = 0 ; i < n ; ++i)
        v[i] = (float)(rand()%(int)(max*1000 - min*1000))/1000 + min;

}

void LPVector::cross(LPVector vector)
{
    //POR IMPLEMENTAR
}

void LPVector::sqrt_vec()
{
    for(int i = 0 ; i < n ; ++i)
        v[i] = sqrt(v[i]);
}

void LPVector::normalize()
{
    //Dividimos cada componente por el módulo
    *this /= this->module();
}

//Sobrecarga operador +=
void LPVector::operator +=(LPVector vector)
{
    //Si las dimensiones son diferentes , tenemos un problema grave.
    if (n != vector.n)
    {
        cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
        return;
    }

    for(int i = 0 ; i < n ; ++i)
        v[i] += vector.v[i];
  
}

//Sobrecarga operador -=
void LPVector::operator -=(LPVector vector)
{
    //Si las dimensiones son diferentes , tenemos un problema grave.
    if (n != vector.n)
    {
        cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
        return;
    }

    for(int i = 0 ; i < n ; ++i)
        v[i] -= vector.v[i];
}

//Sobrecarga operador +=
void LPVector::operator +=(float scal)
{
    for(int i = 0 ; i < n ; ++i)
        v[i] += scal;
}

//Sobrecarga operador -=
void LPVector::operator -=(float scal)
{
    for(int i = 0 ; i < n ; ++i)
        v[i] -= scal;
}

//Sobrecarga operador *=
void LPVector::operator *=(float scal)
{
    for(int i = 0 ; i < n ; ++i)
        v[i] *= scal;
  
}

//Sobrecarga operador /=
void LPVector::operator /=(float scal)
{
    for(int i = 0 ; i < n ; ++i)
        v[i] /= scal;
  
}
//Sobrecarga operador *= //Este operador es el que nos devolverá matrices como resultado del producto de una columna por un fila.
                         //Es decir, es el producto vectorial. Ya lo veremos a su momento
/*void LPVector::operator *=(LPVector vector)
{
    //Si las dimensiones son diferentes , tenemos un problema grave.
    if (n != vector.n)
    {
        cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
        return;
    }

    for(int i = 0 ; i < n ; ++i)
        v[i] += vector.v[i];
}
*/

//Sobrecarga operador ^ A partir de ahora se entederá que es el producto escalar.
float LPVector::operator ^(LPVector vector)
{
    float a = 0.0;

    //Si las dimensiones son diferentes , tenemos un problema grave.
    if (n != vector.n)
    {
        cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
        return 0.0;
    }

    for(int i = 0 ; i < n ; ++i)
        a += v[i] * vector.v[i];

    return a;
}

float LPVector::module()
{
    float a = 0.0;

    for(int i = 0 ; i < n ; ++i)
        a += v[i] * v[i];

    return sqrt(a);
}

float LPVector::distance(LPVector vector)
{
    float a = 0.0;
    float temp = 0.0;

    //Si las dimensiones son diferentes , tenemos un problema grave.
    if (n != vector.n)
    {
        cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
        return (-1.0);
    }

    for(int i = 0 ; i < n ; ++i)
    {
        temp = (v[i] - vector.v[i]);
        a+=temp*temp;
    }

    return sqrt(a);
}


LPVector.h
/**************************************************************************************************/
//        Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
//        para el blog LordPakus (http://lordpakus.blogspot.com/).
//        Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/


/**************************************************************************************************/
// LPVector.h
/**************************************************************************************************/

#ifndef __LPVector__
#define __LPVector__

class LPVector
{
public:
    LPVector();
    ~LPVector();

    //Funciones anexas.
    void Set(int t, float* vector); //Funcion para inicializar un vector de n elementos
    void Delete();                    //Función para limpiar la variable vector
    void print();                    //Función para imprimir el vector por la consola
    void random(int t,float min, float max);                //Función para rellenar de random un vector de t posiciones

    //OPERACIONES DE AMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
    //Operaciones vectoriales
    void operator +=(LPVector vector);          
    void operator -=(LPVector vector);  
    void cross(LPVector vector);            //Calculamos el producto vectorial (cross) POR HACER
    void sqrt_vec();                        //Calculamos la raíz cuadrada de todo los elementos del vector
    void normalize();                        //Normaliza el vector (hace que el módulo sea 1)
          

    //Operaciones con escalares ( sumar , restar , etc ... todo un vector por un escalar)
    void operator +=(float scal);
    void operator -=(float scal);
    void operator *=(float scal);
    void operator /=(float scal);


    //OPERACIONES QUE DEVUELVEN ALGO (NO ACUMULADORES: +,-,*, etc...)
    //Operaciones vectoriales que devuelven escalares
    float operator ^(LPVector vector);            //Operador producto escalar.
    float module();                                //Calcula el módulo del vector
    float distance(LPVector vector);

public:
    int n;         //número de elementos del vector
    float *v;    //puntero a memoria dinámica
};

#endif
Cualquier otra cosa que se os ocurra que le pongamos o cualquier fallo que veais, hacedmelo llegar

Espero que os haya gustado,

Nos vemos

EDIT:
27-08-2011:Se han añadido las funciones siguientes:
       - vector de randoms
       - distancia entre vectores
       - se deja a la espera el cross product (alguíen tiene el código y me lo quiere pasar??)

4 comentarios :

  1. El math engine entiendo que es un proyecto aparte del game engine, aunque ¿siempre te podrás apoyar en el posteriormente no?

    Algunas operaciones que uso yo y que creo que no están son:
    -el producto vectorial(cross)
    -la distancia entre dos vectores(la resta i luego el modulo)
    -vector de randoms.

    También me gustaría saber porque el game engine no lo haces 3d ya que normalmente llama más la atención y creo que captarías mas gente.
    Igualmente yo seguiré mirando todos tus post, ya que aparte de interesantes creo que es muy portable a 3D lo que haces.
    Saludos!!
    26 de agosto de 2011 15:42

    ResponderEliminar
  2. Si, el math engine es un proyecto aparte del game engine y la idea es que en un futuro se puedan entremezclar o aprovechar ciertos códigos del uno en el otro.

    El objetivo final no es mas que una excusa de poder hacer cosillas de SSE y paralelización (que siempre me ha gustado pero que en el game engine es complicado de implementar).

    Las tres funciones que me propones me parecen buenas... en breve las implemento a ver si te parecen bien.

    El game engine es 2D/3D lo que por motivos de tiempo solo me he podido poner con el tema de 2D. De hecho, aquí : http://lordpakus.blogspot.com/2011/06/gameengine-capitulo-8.html y aquí: http://lordpakus.blogspot.com/2011/06/gameengine-capitulo-3.html,podrás ver cosillas de 3D dentro del motor.

    Espero que en breve pueda acabar lo que tenga a medias de 2D y me pueda poner más a fondo con el 3D.

    Gracias por tu apoyo y dedicación

    Nos vemos

    ResponderEliminar
  3. Buenas LordPakus, tienes un pequeño error que se puede subsanar muy fácilmente. En el método:

    void operator +=(LPVector vector);

    Lo que estás haciendo es pasar el parámetro "vector" por copia, osea, que cada vez que llamas al operador += estás copiando el parámetro. Como es de solo lectura (debería), puedes pasarlo por referencia, ¿no? Quedaría así:

    void operator +=(const LPVector& vector);

    El resto de tu código queda inalterado. Un saludo!

    ResponderEliminar
  4. Pues tienes toda la razón, he hecho el fallo del novato. Thenkius, el tema de la sobrecarga de operadores aún no lo tengo controlado al 100% :D.

    Por ahora no lo toco por que estoy metido con el game engine... si vierais que subo otra versión del math engine sin arreglar esto, caneadme :D.

    Muchisimas gracias por tu aportación, por mi mismo este fallo se me habría pasado seguro.

    ResponderEliminar

Entradas populares