Russian Qt Forum
Ноябрь 22, 2024, 18:09 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: Шаблон треугольника  (Прочитано 18770 раз)
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« : Июнь 14, 2016, 12:19 »

Привет, друзья!
Не часто приходилось писать свои шаблоны. Прошу помочь.
Есть класс треугольника, реализованный через QVector3D
Код
C++ (Qt)
class Triangle{
public:
   Triangle();
   Triangle(const QVector3D &a, const QVector3D &b, const QVector3D &c);
 
   QVector3D a() const;
   QVector3D b() const;
   QVector3D c() const;
 
   QVector3D ab() const;
   QVector3D bc() const;
   QVector3D ac() const;
 
   QVector3D normal() const;
   QVector3D normal(const QVector3D &pointUnderPlane) const;
   QVector3D perpendicular() const;
 
   float square() const;
   QVector3D center() const;
 
private:
   std::array<QVector3D, nodeCountPerFace> vertices;
};
 
using TriangleList = QVector<Triangle>;
 
Мне понадобилось увеличить точность до двойной и я решил в качестве вершин использовать класс сторонней библиотеки arma::vec3.
Как бы мне сделать шаблон так, чтобы можно было работать и с QVector3D и с arma::vec3?
Сейчас основная проблема: точность площади. Я могу либо оставить её всегда double, либо передавать 2 аргумента шаблона. Как бы поступили вы?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Июнь 14, 2016, 15:38 »

Хранить вертексы в полигоне - неудачная затея. Всегда есть операции применяемые ко всем вертексам и "доставать" их из полигонов будет очень неудобно (особенно учитывая что один вертекс может использоваться неск полигонами). Храните в полигонах индексы, а вертексы в отдельном контейнере, вот он может быть (и обычно бывает) разных типов. Напр так
Код
C++ (Qt)
struct VertexList {
virtual size_t size( void ) const = 0;
 
virtual arma::vec3 GetVertex( size_t index ) = 0;
virtual void SetVertex( const arma::vec3 & val,  size_t index ) = 0;
};
 
template <class T>
struct TVertexList<T> : public VertexList {
virtual size_t size( void ) const  { return mData.size(); }
 
virtual arma::vec3 GetVertex( size_t index ) { return mData[index]; }
virtual void SetVertex( const arma::vec3 & val,  size_t index ) { mData[index] = val; }
 
std::vector<T> mData;
};
Так одни и те же полигоны работают с разными представлениями вертексов, надо только добавить операторы перевода vec3 <-> QVector3D
Сейчас основная проблема: точность площади. Я могу либо оставить её всегда double, либо передавать 2 аргумента шаблона. Как бы поступили вы?
Не понял что за проблема. Если площадь оказывается меньше допустимого предела - полигон некорректен и должен быть удален. При этом возможно/часто модель должна быть перестроена. Использование double само по себе не решение. Напр если 3 точки лежат на 1 прямой - площадь нулевая при любой точности.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #2 : Июнь 14, 2016, 21:44 »

Нет, индексы я пока что не буду использовать. А если буду, то заведу под это отдельный класс. Про площадь я имел в виду, возвращаемый тип float/double как разрешить при помощи шаблона.

Что-то мне кажется, что надо отказываться от QVector3D и переходить на arma::Row<T>::fixed<3>...
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Июнь 15, 2016, 10:34 »

Про площадь я имел в виду, возвращаемый тип float/double как разрешить при помощи шаблона.
А зачем его "разрешать"? Просто возвращайте "старший" тип double, не вижу чем это грозит. Да, и если плохие тр-ки образуются в результате boolean операции (напр рассечение полигона), то двойная точность не спасает.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #4 : Июнь 15, 2016, 10:35 »

Ну, как бы не хотелось бы тратиться на преобразования флоат-дабл и обратно. Хоть они и незначительны.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Июнь 15, 2016, 11:03 »

Ну, как бы не хотелось бы тратиться на преобразования флоат-дабл и обратно. Хоть они и незначительны.
Ф-ция/метод возвращает рез-т в регистре FPU (насколько помню 10 байт) и только при записи рез-та в память происходит конвертация в 4, 8 или 10 байт - но в любом случае одной командой.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #6 : Июнь 15, 2016, 13:21 »

тогда зачем придумали тригонометрические функции с суффиксом f? (sinf, cosf)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Июнь 16, 2016, 10:58 »

тогда зачем придумали тригонометрические функции с суффиксом f? (sinf, cosf)
Чтобы загрублять точность аргумента и рез-та.

Возможно Вы имели ввиду что реализации square нужны разные, напр из-за разницы в оператораx QVector3D и arma::vec3. Тогда так
Код
C++ (Qt)
template <class T>
class Triangle {
public:
   Triangle();
   Triangle(const T &a, const T &b, const T &c);
 
   T a() const;
//....
private:
   std::array<T, nodeCountPerFace> vertices;};
 
Т.е. переписываете с "T" вместо QVector3D. A потом объявляете специализацию для QVector3D и/или arma::vec3
Код
C++ (Qt)
template<> class Triangle<QVector3D> {
public:
float square( void );
};
 
Все же практичнее использовать классы с одинаковыми базовыми операторами/методами. отличающиеся только float/double
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #8 : Июнь 16, 2016, 13:27 »

Цитировать
Т.е. переписываете с "T" вместо QVector3D. A потом объявляете специализацию для QVector3D и/или arma::vec3
Специализировать целый класс ради одной-двух функций?) 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #9 : Июнь 16, 2016, 14:46 »

А зачем тут шаблон? Не проще сделать общий интерфейс и 2 имплементации к нему?
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #10 : Июнь 16, 2016, 15:04 »

А зачем тут шаблон? Не проще сделать общий интерфейс и 2 имплементации к нему?
Нет конечно) И потом, почему именно 2? И как Вы себе представляете общий интерфейс для этого класса?

Шаблоны здесь кстатии, только я не согласен вот с этим подходом:
Цитировать
Т.е. переписываете с "T" вместо QVector3D. A потом объявляете специализацию для QVector3D и/или arma::vec3
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Июнь 16, 2016, 15:22 »

Специализировать целый класс ради одной-двух функций?) 
Да, верно (недавно обсуждали подобное). Хорошо, а если так?
Код
C++ (Qt)
template<class T>
class TriangleQ : public Triangle<T> {
public:
       TriangleQ(const T &a, const T &b, const T &c) : Triangle<T>(a, b, c)
{
}
 
float square( void ) const
{
return 1;
}
};
 
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #12 : Июнь 16, 2016, 15:58 »

Цитировать
Хорошо, а если так?
И чем это лучше? Всё равно придётся копипастить весь класс..

Я имел в виду завести point_traits, где определить нужные функции и подсовывать уже его в реализацию одного шаблонного треугольника:
Код
C++ (Qt)
template <class>
point_traits
{};
 
template <>
point_traits<QVector3D>
{
   typedef float value_type;
 
   static value_type square(const QVector3D & p1, const QVector3D & p2, const QVector3D & p3) { return ...; }
};
 
template <>
point_traits<arma::vec3>
{
   typedef double value_type;
 
   static value_type square(const arma::vec3 & p1, const value_type & p2, const value_type & p3) { return ...; }
};
 
template <class T, class PointTraits = point_traits<T>>
class Triangle
{
public:
   typedef T point_type;
   typedef typename PointTraits::value_type value_type;
...
  value_type square() const { return PointTraits::square(p1, p2, p3); }
 
private:
  point_type p1;
  point_type p2;
  point_type p3;
};
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #13 : Июнь 16, 2016, 16:22 »

А зачем тут шаблон? Не проще сделать общий интерфейс и 2 имплементации к нему?
Нет конечно) И потом, почему именно 2? И как Вы себе представляете общий интерфейс для этого класса?

Потому что сейчас речь идет о QVector3d, который основан на float, и другой класс, который использует double для внутреннего представления. Скорее всего, и API у них также различны. А значит, шаблонное решение тут очень спорно - нет "общих точек соприкосновения". Поэтому по хорошему автору нужен враппер, API которого будет независимо от внутреннего API векторных классов. В интерфейс надо вынести функции, которые имеют значение для обоих классов, и принимают в качестве параметром только примитивные типы. А вот уже эти типы можно описать с помощью шаблонов (типа Вашего последнего примера). Если же автор захочет иметь метод, который раньше возвращал QVector3d - то шаблоны не спасут.
« Последнее редактирование: Июнь 16, 2016, 16:25 от Racheengel » Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #14 : Июнь 16, 2016, 16:46 »

Цитировать
Потому что сейчас речь идет о QVector3d, который основан на float, и другой класс, который использует double для внутреннего представления.
А завтра ТС захочет 3-ий, 4-ый и 5-ый)

Цитировать
Поэтому по хорошему автору нужен враппер, API которого будет независимо от внутреннего API векторных классов.
Сейчас оно уже не зависимо)

Цитировать
В интерфейс надо вынести функции, которые имеют значение для обоих классов, и принимают в качестве параметром только примитивные типы.

А если завтра их захочется больше (в смысле классов)?

Цитировать
Если же автор захочет иметь метод, который раньше возвращал QVector3d - то шаблоны не спасут.
Не понял? Почему?

Можно кодом продемонстрировать, как Вы это представляете?
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.168 секунд. Запросов: 23.