Название: Шаблон треугольника Отправлено: __Heaven__ от Июнь 14, 2016, 12:19 Привет, друзья!
Не часто приходилось писать свои шаблоны. Прошу помочь. Есть класс треугольника, реализованный через QVector3D Код Мне понадобилось увеличить точность до двойной и я решил в качестве вершин использовать класс сторонней библиотеки arma::vec3. Как бы мне сделать шаблон так, чтобы можно было работать и с QVector3D и с arma::vec3? Сейчас основная проблема: точность площади. Я могу либо оставить её всегда double, либо передавать 2 аргумента шаблона. Как бы поступили вы? Название: Re: Шаблон треугольника Отправлено: Igors от Июнь 14, 2016, 15:38 Хранить вертексы в полигоне - неудачная затея. Всегда есть операции применяемые ко всем вертексам и "доставать" их из полигонов будет очень неудобно (особенно учитывая что один вертекс может использоваться неск полигонами). Храните в полигонах индексы, а вертексы в отдельном контейнере, вот он может быть (и обычно бывает) разных типов. Напр так
Код Так одни и те же полигоны работают с разными представлениями вертексов, надо только добавить операторы перевода vec3 <-> QVector3D Сейчас основная проблема: точность площади. Я могу либо оставить её всегда double, либо передавать 2 аргумента шаблона. Как бы поступили вы? Не понял что за проблема. Если площадь оказывается меньше допустимого предела - полигон некорректен и должен быть удален. При этом возможно/часто модель должна быть перестроена. Использование double само по себе не решение. Напр если 3 точки лежат на 1 прямой - площадь нулевая при любой точности.Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 14, 2016, 21:44 Нет, индексы я пока что не буду использовать. А если буду, то заведу под это отдельный класс. Про площадь я имел в виду, возвращаемый тип float/double как разрешить при помощи шаблона.
Что-то мне кажется, что надо отказываться от QVector3D и переходить на arma::Row<T>::fixed<3>... Название: Re: Шаблон треугольника Отправлено: Igors от Июнь 15, 2016, 10:34 Про площадь я имел в виду, возвращаемый тип float/double как разрешить при помощи шаблона. А зачем его "разрешать"? Просто возвращайте "старший" тип double, не вижу чем это грозит. Да, и если плохие тр-ки образуются в результате boolean операции (напр рассечение полигона), то двойная точность не спасает.Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 15, 2016, 10:35 Ну, как бы не хотелось бы тратиться на преобразования флоат-дабл и обратно. Хоть они и незначительны.
Название: Re: Шаблон треугольника Отправлено: Igors от Июнь 15, 2016, 11:03 Ну, как бы не хотелось бы тратиться на преобразования флоат-дабл и обратно. Хоть они и незначительны. Ф-ция/метод возвращает рез-т в регистре FPU (насколько помню 10 байт) и только при записи рез-та в память происходит конвертация в 4, 8 или 10 байт - но в любом случае одной командой. Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 15, 2016, 13:21 тогда зачем придумали тригонометрические функции с суффиксом f? (sinf, cosf)
Название: Re: Шаблон треугольника Отправлено: Igors от Июнь 16, 2016, 10:58 тогда зачем придумали тригонометрические функции с суффиксом f? (sinf, cosf) Чтобы загрублять точность аргумента и рез-та. Возможно Вы имели ввиду что реализации square нужны разные, напр из-за разницы в оператораx QVector3D и arma::vec3. Тогда так Код Т.е. переписываете с "T" вместо QVector3D. A потом объявляете специализацию для QVector3D и/или arma::vec3 Код Все же практичнее использовать классы с одинаковыми базовыми операторами/методами. отличающиеся только float/double Название: Re: Шаблон треугольника Отправлено: m_ax от Июнь 16, 2016, 13:27 Цитировать Т.е. переписываете с "T" вместо QVector3D. A потом объявляете специализацию для QVector3D и/или arma::vec3 Специализировать целый класс ради одной-двух функций?) Название: Re: Шаблон треугольника Отправлено: Racheengel от Июнь 16, 2016, 14:46 А зачем тут шаблон? Не проще сделать общий интерфейс и 2 имплементации к нему?
Название: Re: Шаблон треугольника Отправлено: m_ax от Июнь 16, 2016, 15:04 А зачем тут шаблон? Не проще сделать общий интерфейс и 2 имплементации к нему? Нет конечно) И потом, почему именно 2? И как Вы себе представляете общий интерфейс для этого класса? Шаблоны здесь кстатии, только я не согласен вот с этим подходом: Цитировать Т.е. переписываете с "T" вместо QVector3D. A потом объявляете специализацию для QVector3D и/или arma::vec3 Название: Re: Шаблон треугольника Отправлено: Igors от Июнь 16, 2016, 15:22 Специализировать целый класс ради одной-двух функций?) Да, верно (недавно обсуждали подобное). Хорошо, а если так?Код
Название: Re: Шаблон треугольника Отправлено: m_ax от Июнь 16, 2016, 15:58 Цитировать Хорошо, а если так? И чем это лучше? Всё равно придётся копипастить весь класс..Я имел в виду завести point_traits, где определить нужные функции и подсовывать уже его в реализацию одного шаблонного треугольника: Код
Название: Re: Шаблон треугольника Отправлено: Racheengel от Июнь 16, 2016, 16:22 А зачем тут шаблон? Не проще сделать общий интерфейс и 2 имплементации к нему? Нет конечно) И потом, почему именно 2? И как Вы себе представляете общий интерфейс для этого класса? Потому что сейчас речь идет о QVector3d, который основан на float, и другой класс, который использует double для внутреннего представления. Скорее всего, и API у них также различны. А значит, шаблонное решение тут очень спорно - нет "общих точек соприкосновения". Поэтому по хорошему автору нужен враппер, API которого будет независимо от внутреннего API векторных классов. В интерфейс надо вынести функции, которые имеют значение для обоих классов, и принимают в качестве параметром только примитивные типы. А вот уже эти типы можно описать с помощью шаблонов (типа Вашего последнего примера). Если же автор захочет иметь метод, который раньше возвращал QVector3d - то шаблоны не спасут. Название: Re: Шаблон треугольника Отправлено: m_ax от Июнь 16, 2016, 16:46 Цитировать Потому что сейчас речь идет о QVector3d, который основан на float, и другой класс, который использует double для внутреннего представления. А завтра ТС захочет 3-ий, 4-ый и 5-ый) Цитировать Поэтому по хорошему автору нужен враппер, API которого будет независимо от внутреннего API векторных классов. Сейчас оно уже не зависимо)Цитировать В интерфейс надо вынести функции, которые имеют значение для обоих классов, и принимают в качестве параметром только примитивные типы. А если завтра их захочется больше (в смысле классов)? Цитировать Если же автор захочет иметь метод, который раньше возвращал QVector3d - то шаблоны не спасут. Не понял? Почему?Можно кодом продемонстрировать, как Вы это представляете? Название: Re: Шаблон треугольника Отправлено: Racheengel от Июнь 16, 2016, 16:57 Я имею в виду следующее: у автора есть методы типа
class Triangle{ public: ... QVector3D a() const; ... }; Т.е класс Triangle "заточен" на работу с QVector3D. В общем случае это не годится, и вместо QVector3D придется использовать независимый от имплементации класс-враппер, типа CUniversalVector3D, который уже может быть специализирован для double & float отдельно. Это, в свою очередь, означает смену API: class Triangle{ public: ... CUniversalVector3D a() const; ... }; только тогда человек сможет "безболезненно" менять имплементации векторов. Название: Re: Шаблон треугольника Отправлено: m_ax от Июнь 16, 2016, 17:09 Цитировать только тогда человек сможет "безболезненно" менять имплементации векторов. Безболезненно? Вы шутите?) То что Вы сейчас предлагаете - это антипатерн..Это как минимум не эффективно: приводить суперкласс к частным случаям (QVector3D, arma::vec3).. И как быть с тем, что завтра мне понадобится использовать в качестве вектора /точки другой класс? (например с размерностью больше 3?) Ммм? Будете опять лезть в супервектор и добавлять новый функционал? И так до бесконечности? Нет уж, нафиг-нафиг) Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 16, 2016, 17:15 Я имел в виду завести point_traits, где определить нужные функции и подсовывать уже его в реализацию одного шаблонного треугольника: Элегантненько, спасибо :)Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 16, 2016, 17:22 Racheengel, если я правильно вас понял, то сделать больше двух (и даже одного, имхо) наследников будет болью. Так и зачем нам привязка именно к QVector3D не совсем понял.
Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 16, 2016, 17:53 m_ax, а зачем в аргументы шаблона записывать class PointTraits = point_traits<T> ?
Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 16, 2016, 17:55 А всё, сообразил, чтобы какой-нибудь Generic можно было вставить
Название: Re: Шаблон треугольника Отправлено: m_ax от Июнь 16, 2016, 17:59 m_ax, а зачем в аргументы шаблона записывать class PointTraits = point_traits<T> ? Если понадобится расширить класс харрактеристик (в котором еобходимо передавать более одного шаблона).. Но можно и не писать, если в этом нет необходимости.. Название: Re: Шаблон треугольника Отправлено: Racheengel от Июнь 16, 2016, 22:51 Racheengel, если я правильно вас понял, то сделать больше двух (и даже одного, имхо) наследников будет болью. Так и зачем нам привязка именно к QVector3D не совсем понял. Боль будет в любом случае, поскольку изначальный класс завязан на QVector3D , с которым double не получится... А значит, и весь код, зависящий от этого класса, придется переделать на нечто генерическое с абстрактым вектором. Но после этого хоть 2, хоть 22 наследника можно делать - все будет более-менее одинаково. Главное API не поломать. Название: Re: Шаблон треугольника Отправлено: Racheengel от Июнь 16, 2016, 22:55 Безболезненно? Вы шутите?) То что Вы сейчас предлагаете - это антипатерн.. С каких пор "фасад" стал антипаттерном? O_o Это как минимум не эффективно: приводить суперкласс к частным случаям (QVector3D, arma::vec3).. И как быть с тем, что завтра мне понадобится использовать в качестве вектора /точки другой класс? (например с размерностью больше 3?) Ммм? Будете опять лезть в супервектор и добавлять новый функционал? И так до бесконечности? Суперкласс сейчас завязан на QVector3D. Если его привести к CAbstractVector3D, то имплементаций можно ваять сколько угодно - но код, использующий CAbstractVector3D, переписывать не придется :) Название: Re: Шаблон треугольника Отправлено: m_ax от Июнь 16, 2016, 23:51 Цитировать С каких пор "фасад" стал антипаттерном? O_o А я сомневаюсь, что это в данном случае именно фасад)Ну хорошо, как Вы видите себе API абстрактного CAbstractVector3D? Как Вы его будете приводить к QVector3D, arma::vec3, MyCustomPont5D? Название: Re: Шаблон треугольника Отправлено: Racheengel от Июнь 17, 2016, 01:17 // Это базовый шаблон-интерфейс, в который передаем T=float/double/whatever...
template<typename T> class IAbstractVector3D { public: IAbstractVector3D(T x, T y, T z); IAbstractVector3D GetMul(T factor) const = 0; IAbstractVector3D GetSomethingElse(...) const = 0; T GetX() const = 0; T GetY() const = 0; T GetZ() const = 0; }; // float-имплементация на основе QVector3D class CVector3D: public IAbstractVector3D<float> { public: CVector3D(float x, float y, float z): m_vector3d(x,y,z) {} IAbstractVector3D GetMul(T factor) const { QVector3D result = m_vector3d * factor; return CVector3D(result.x(), result.y(), result.z()); } ... float GetX() const { return m_vector.x(); } ... private: QVector3D m_vector3d; }; // double-имплементация на основе vec3 class CArmaVector3D: public IAbstractVector3D<double> { public: CArmaVector3D(double x, double y, double z): m_vector3d(x,y,z) {} IAbstractVector3D GetMul(double factor) const { CArmaVector3D result = m_vector3d * factor; return CArmaVector3D(result.x(), result.y(), result.z()); } ... double GetX() const { return m_vector.x(); } ... private: arma::vec3 m_vector3d; }; Примерно так у нас реализованы подобные классы в рабочей либе (сейчас писал по памяти, без компилятора, но в общем идея, думаю, понятна) Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 17, 2016, 09:32 Зачем мне реализовывать GetMul?, если везде определён operator*, а если в какой-то экзотической либе не определён, то я могу его определить сам
Название: Re: Шаблон треугольника Отправлено: Racheengel от Июнь 17, 2016, 10:03 Зачем мне реализовывать GetMul?, если везде определён operator*, а если в какой-то экзотической либе не определён, то я могу его определить сам Ну, это я для примера привел :) В реальности все скорее всего решится через Find & Replace :) Даже имплементация через общий интерфейс имеет недостаток того, что в вызывающем коде все равно придется менять флоты на даблы. Поэтому, любое другое решение, кроме замены, будет избыточным :) Название: Re: Шаблон треугольника Отправлено: m_ax от Июнь 17, 2016, 10:36 Цитировать Примерно так у нас реализованы подобные классы в рабочей либе (сейчас писал по памяти, без компилятора, но в общем идея, думаю, понятна) Теперь понятно, спасибо) Думаю, класс точки/вектора - это немного не тот случай, когда паттерн фассад оправдан.. Во всяком случае я не вижу никаких преимуществ в данном подходе.. Как я понимаю, пользователь сам должен выбирать удобную для него реализацию класса точки/вектора (с любой из которых сможет однообразно работать класс Triangle) а не переписывать каждый раз весь её функционал, наследуясь от абстрактного предка. Название: Re: Шаблон треугольника Отправлено: Racheengel от Июнь 17, 2016, 10:51 Во всяком случае я не вижу никаких преимуществ в данном подходе.. Да собственно, их и нет. Единственное, для чего все это городится - чтобы "встык" заменить QVector3D на нечто другое. Но проблема тут в том, что и вызывающий код придется насиловать в любом случае. Либо заменять все вызовы Triangle на IAbstractTriangle, либо переписать на шаблонах... Опять же, возникает вопрос - усилия того стоят? Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 17, 2016, 13:09 Прочитал на википедии про паттерн фасад. Глядя на пример BlackSabbath ничего не понятно, в чём тут паттерн... Либо я интуитивно его постоянно использую. Есть что-то маленькое, которое входит в состав чего-то большого и имеет свою ответственность.
Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 17, 2016, 13:12 Код из первого моего поста ведь тоже фасад? Три точки, которые управляются бОльшим классом.
Название: Re: Шаблон треугольника Отправлено: Igors от Июнь 17, 2016, 13:50 И чем это лучше? Всё равно придётся копипастить весь класс.. Нет, только конструкторы с аргументами, остальное унаследуется. Хотя стоит ли оно того - хз. Напр вот реализация Код Очевидно для arma::vec3 это не прокатит. Арифметика (-, /) там наверное есть, а вот статический crossProduct вряд ли, да и length может быть другим. То же самое случится со многими (если не всеми) содержательными методами, итог обобщения - неск косметических сеттеров. Также template проблематичен и с др стороны. Допустим мы добились желаемого и теперь может свободно объявлять Код Ну и как теперь с этим работать? Напр был класс Код А теперь, когда Triangle стал шаблоном - какой контейнер писать? И к кому обращаться методам использующим mPoly? Утрированный пример: Код Минусы (или просто глупость) такого решения очевидны. Мои предложения 1) Реализовать всю содержательную часть Triangle для "старшего" типа, здесь это arma::vec3 и только хранилище (vertices) имеет тип аргумента template Код Теперь T может быть чем угодно - лишь бы он умел приводиться к arma::vec3, это легко обеспечить. Да, есть расходы на перегонку, но они терпимы. 2) Подобным образом "замкнуть" template внутри контейнера полигонов Код Теперь мы можем писать Код
3) Вот что-то мне никак не верится что есть необходимость в хранении фундаментальных данных (полигонов) 2-мя или более способами. Впечатление что площадь считается по формуле Герона - ну тогда да, точность низкая. Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 17, 2016, 14:30 3) плавно перевести проект с использования одного типа на другой.
Название: Re: Шаблон треугольника Отправлено: Igors от Июнь 17, 2016, 15:12 3) плавно перевести проект с использования одного типа на другой. К слову: VBO с double не дружит. Ошибок не выдает, но тормоза вместо ускорения. Не смертельно, но придется на карту подать временный массив float. По поводу "плавности" - все-таки лобовая замена дешевле, обобщение здесь оказывается совсем не простым.Безболезненно? Вы шутите?) То что Вы сейчас предлагаете - это антипатерн.. Да, но эти скромные потери все же лучше чем все инфицировано template, там полный тупик.Это как минимум не эффективно: приводить суперкласс к частным случаям (QVector3D, arma::vec3).. И как быть с тем, что завтра мне понадобится использовать в качестве вектора /точки другой класс? (например с размерностью больше 3?) Ммм? Будете опять лезть в супервектор и добавлять новый функционал? И так до бесконечности? Кстати размерность 4 - вполне реальный случай, так называемые "однородные" координаты, 4-е число - делитель. Часто используется для хранения перспективы, напр в OpenGL. Да, возможно тогда придется чего-то "специализировать", напр вычисление центра тр-ка, при этом приводясь к явному классу. Но это неизбежно, мы не можем получить 4-ю если базовый вектор имеет 3.Нет уж, нафиг-нафиг) Название: Re: Шаблон треугольника Отправлено: Old от Июнь 17, 2016, 16:05 Минусы (или просто глупость) такого решения очевидны. Это точно.Но, как я понял, __Heaven__ хотел простого перехода от одного треугольника к другому, а не совместно их использовать в проекте: Код
Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 17, 2016, 16:38 Old, в точку.
Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Июнь 17, 2016, 16:40 Igors, да. Vbo будет наполняться float.
Название: Re: Шаблон треугольника Отправлено: __Heaven__ от Январь 30, 2017, 11:00 Кстати, не рассматривался вариант шаблонной обёртки для точки с оператором преобразования к типу. Он будет как-то хуже, чем предложенный с point_traits?
|