Совместимость с C ++ Vector Math и OpenGL - PullRequest
7 голосов
/ 06 апреля 2011

Я много занимался векторной математикой и написал для нее свой собственный шаблон.

Мои требования - много векторной математики (сложение, вычитание, масштабирование, перекрестное и точечное производство), также ямне нужно передать мой вектор как число с плавающей точкой [], чтобы openGL мог его использовать.

Некоторое время я пользовался этим довольно счастливо, сегодня лектор увидел это и застонал.Было две вещи, которые он особенно ненавидел (одну из которых я понимаю), мое использование наследования, потому что, похоже, оно не следовало стилю is a.И мой кастинг (T*)this, конечно, у него не было особых решений.

Первый: Наследование, мне нужно иметь возможность использовать vec2 дляВ vec4 я разработал свои векторы вот так.

template<typename T>
Vector2D
{
 public:
 getX(), getY(), setX(), setY() ....
};

template<typename T>
Vector3D : public Vector2D<T>
{
 public:
 getZ(), setZ() ...
}

template<typename T>
Vector4D : public Vector3D<T>
{
 public:
 getW(), setW() ...
}

Почему это плохо?и я не вижу, как это улучшить.Мне нужно (хочу) иметь возможность определять тип и иметь какие-то методы получения и установки.Если бы я переставил его, как

template<typename T, int _size>
VectorT

, я бы потерял свои вещи .getX(), .setX() и мне пришлось бы заменить их на что-то вроде .at() или [].Я предпочитаю удобочитаемость .getX(), хотя это облегчит определения операторов.

Второе: Я могу понять, почему это плохо, но чтобы сделать так, чтобы я мог передавать эти векторыв метод openGL, который ожидает массив с плавающей точкой, я перегружен оператором сплата

// Defined in Vector2D<T>
operator*() { return (T*)this; }

Насколько я понимаю, нет гарантии, что компилятор поместит переменные-члены x, y, z, w вначало класса, и если не быть осторожным, я мог бы закончить прохождение v-таблицы вместо этого.Однако я должен признать, что у меня до сих пор не было проблем.

Единственный способ, который я могу увидеть в этом, - поддерживать возвращаемый массив.Что, я полагаю, было бы проще, если бы я изменил их так, как я имею дело с векторами.

Ответы [ 6 ]

6 голосов
/ 06 апреля 2011

Возможно, вы захотите использовать GLM .Он делает все, что вы описали (хотя мне не хватало документации), включая интеграцию с OpenGL.

2 голосов
/ 06 апреля 2011

Вы можете слушать своего учителя и использовать частичную специализацию (предупреждение: не проверено):

template<typename T, int size>
class Vector;

template< typename T >
class Vector< T, 2 >
{
  public :
    Vector() : data() {}

    T GetX() const { return data[0]; };
    T GetY() const { return data[1]; };

    void SetX( const T v ) const { data[0]=v; };
    void SetY( const T v ) const { data[1]=v; };

  private :
    T data[2];
};

template< typename T >
class Vector< T, 3 >
{
  public :
    Vector() : data() {}

    T GetX() const { return data[0]; };
    T GetY() const { return data[1]; };
    T GetZ() const { return data[2]; };

    void SetX( const T v ) const { data[0]=v; };
    void SetY( const T v ) const { data[1]=v; };
    void SetZ( const T v ) const { data[2]=v; };

  private :
    T data[3];
};
1 голос
/ 06 апреля 2011

Как насчет этого:

template<class T, int _dim>
class Vector
{
    T v[_dim];
    operator*(){return v;}

friend T inner_product(Vector<T, _dim> const &v1, Vector<T, _dim> const &v2);
};

template<class T, int _dim>
T inner_product(Vector<T, _dim> const &v1, Vector<T, _dim> const &v2)
{
    T p = 0.;
    for(int i; i < _dim; i++)
        p += v1.v[i] * v2.v[i];
    return p;
}

template<class T>
class Vector2 : Vector<T, 2>
{
    float getX() const {return v[0];}
    float getS() const {return v[0];}

    float getY() const {return v[1];}
    float getT() const {return v[1];}
}

template<class T>
class Vector3 : Vector<T, 3>, Vector2<T>
{
    float getZ() const {return v[2];}
    float getR() const {return v[2];}
}

template<class T>
class Vector4 : Vector<T, 4>, Vector3<T>
{
    float getW() const {return v[3];}
    float getQ() const {return v[3];}
}

Обратите внимание, что создание inner_product другом, не являющимся частью класса, позволяет использовать его для всех производных типов!

0 голосов
/ 25 октября 2012

Вот полная библиотека Math в стиле OpenGL (с открытым исходным кодом) для c ++

http://glm.g -truc.net /

0 голосов
/ 06 апреля 2011

Я бы, наверное, сделал что-то вроде этого:

template<typename T>
class VectorT{
protected:
  T* m_data;
  int m_size;

public:
  VectorT(unsigned int size) 
  : m_size(size)
  {
    m_data=new T[size];
  }

  virtual ~VectorT()
  {
    delete[] m_data;
  }

  T* operator*() { return m_data; }
  T& operator[](int ii) { return m_data[ii]; }
}

template<typename T>
class Vector3 : public VectorT<T>
{
public:
  Vector3() : VectorT(3) {}
  T getX() { return m_data[0]; }
  T getY() { return m_data[1]; }
  T getZ() { return m_data[2]; }

  Vector3 crossP(const Vector3& vv) { ... }
}
0 голосов
/ 06 апреля 2011

Как вы сказали, вы злоупотребляете "наследственной" природой наследования. Проблема может возникнуть, если вы написали такую ​​функцию

float dotProduct (vector2D a, vector2D b);

Вы можете передать трехмерный вектор и получить скалярный результат, когда действительно точечное произведение двумерного вектора и трехмерного вектора не определено, и это на самом деле ошибка, которая может привести к странному поведению. Конечно, это не так уж сложно, но вы отбрасываете часть проверки типов, и если вы собираетесь справиться с болью статической типизации, вы можете также получить ее преимущества, когда появляются подобные ошибки.

Поддержание массива - определенно превосходное решение, вы не хотите полагаться на неопределенное поведение, потому что никогда не знаете, когда он полностью вас облажает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...