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

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

Страниц: 1 2 3 [4] 5   Вниз
  Печать  
Автор Тема: Переделать старые структуры  (Прочитано 32664 раз)
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #45 : Сентябрь 01, 2017, 13:19 »

Умеете Вы всё в интересную сторону повернуть Улыбающийся.

Делать можно по-всякому,
Здесь я имел в виду, что, в общем случае, на базе одного нормального подхода можно нагенерить десяток дурацких реализаций, а в частном случае, что подход интерфейс + шаблонная реализация (как в моём примере) можно применить как к самой кривой, так и к её ключам, и к опциям сплайна в составе ключа, или к их комбинациям. В конечном счёте к тому, что оптимальным образом решает поставленную задачу.

Далее, в моём примере соблюдается требование "Если юзер создал кривую типа "число" - то он никак не сможет преобразовать ее в тип "вектор" или "цвет", и наоборот." (формулировка которого, кстати, отсутствует в начальном сообщении, а появилась только после уточняющих вопросов) без каких-либо дополнительных действий, а в Вашем примере это требование не соблюдается, если только не прилепить к нему костыли, в качестве которых Вы предлагаете приватные конструкторы и friend, в последующем сообщении. Отсюда и проросли мои сомнения по тонкостям постановки задачи Улыбающийся.

Вариант с наследованием от (нешаблонного) интерфейса Key я увидел сразу и уже его реализую. Но меня смущает полное отсутствие каких-либо других путей/возможностей. Конечно реальных, "просто шаблон" или "просто вариант" здесь очевидно не к месту . Поэтому послушать как же "по-всякому" хотелось бы. Но вряд ли услышу, то наверное всего лишь "дежурная фраза"  Улыбающийся
Возможно Вам придётся долго ждать, пока кто-нибудь не расскажет про какие-нибудь волшебные пути/возможности Улыбающийся. Особенно с Вашим мастерством описывать постановку задачи. Когда же Вам предлагают попробовать подойти к решению задачи с другой стороны, Вы упираетесь и говорите, что "надо именно так". Тут уже помогать становится сложнее...

В теме мелькает функция "double InterpolateValue( Curve * curve, double t )". Кроме интерполяции значений между ключевыми точками, кривые ещё что-нибудь делают? Не принимая во внимание геттеры/сеттеры её содержимого.
Код
C++ (Qt)
double InterpolateValue( Curve * curve, double t )
{
 if (t >= MaxTime(curve)) ...
 if (t <= MinTime(curve)) ...
 
 switch (curve->splineType) {
   case SPLINE_LINEAR:
     return InterpolateLinear(curve, t);
 
   case SPLINE_RATIO:
     return InterpolateRatio(curve, t);
 
   .....
 }
}
С этим куском что-нибудь пытались делать? Уйти от свитча и перейти к виртуальным методам?
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #46 : Сентябрь 02, 2017, 06:57 »

Особенно с Вашим мастерством описывать постановку задачи.
Это я неизменно слышу от научных работников Улыбающийся Но вот скажите - почему Вы в качестве примера показываете ...(ну конечно) вывод в консоль? Кто же Вам мешал взять любую совершенно реальную задачу изложенную в постановке? Напр метод AddKey (добавить контрольную точку) или DelNthKey или любой другой (там богатый выбор)? Что же Вам здесь было неизвестно? Каким образом "плохая постановка" помешала Вам это сделать?  Улыбающийся

(формулировка которого, кстати, отсутствует в начальном сообщении, а появилась только после уточняющих вопросов)
Поверьте, в ЛЮБОЙ задаче не составит никакого труда задолбать вопросами типа
Цитировать
А что будет если..?
Не существует даже ТЗ (не говоря уже о постановке) которое предусмотрит все что взбредет в голову. От постановки требуется ясное описание что дано и что хотим получить - и здесь это звучит четко. Возможны и др задачи? Может быть, но они темой обсуждения не являются.

Если тип времени один - это хорошо. Только я бы сделал как минимум "using CurveTime = double;", сегодня оно double, а завтра не совсем double (а то может и совсем не double, например, это время может быть отрицательным?).
Типичное "если бы да кабы" - вот так, с ни хрена, нагрузить код еще одним шаблоном (а вдруг понадобится?). Мягко говоря "заслуживает самого сурового осуждения"  Плачущий 

С этим куском что-нибудь пытались делать? Уйти от свитча и перейти к виртуальным методам?
Да, это виртуальный метод Key::Interpolate что дальше спускается (расписывается) по шаблонам. Правда тут (и в др местах) возникает типа "коллизия" - для интерполяции классу Key нужны соседние Key(s). Сейчас это решается так
Код
C++ (Qt)
struct Key {
 Key * prev, * next;
 ...
};
И огромная масса кода завязана на это. С одной стороны "нарушается концептуальная чистота" - ну кто такой Key чтобы это делать, это же явно метод кривой! С другой.. этот метод так или иначе "прогуливается по ключам" и только они нужны. В общем сделал его static методом Key (зову из виртуала)

Вообще "интрузивные контейнеры" (насколько помню так называется структура выше) - интересная тема
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #47 : Сентябрь 02, 2017, 07:38 »

Типичное "если бы да кабы" - вот так, с ни хрена, нагрузить код еще одним шаблоном (а вдруг понадобится?). Мягко говоря "заслуживает самого сурового осуждения"  Плачущий 
Каким шаблоном, это тот же typedef:
Код
C++ (Qt)
typedef double CurveTime;
 
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #48 : Сентябрь 02, 2017, 12:39 »

Это я неизменно слышу от научных работников Улыбающийся Но вот скажите - почему Вы в качестве примера показываете ...(ну конечно) вывод в консоль? Кто же Вам мешал взять любую совершенно реальную задачу изложенную в постановке? Напр метод AddKey (добавить контрольную точку) или DelNthKey или любой другой (там богатый выбор)? Что же Вам здесь было неизвестно? Каким образом "плохая постановка" помешала Вам это сделать?  Улыбающийся

В своём примере я не рассматривал методы типа AddKey, DelNthKey и им подобные потому что полагаю, что им не место в том классе, который сейчас называется Curve. На мой взгляд, единственная значимая функциональность "кривой" Curve, которая мелькала в теме - это метод "InterpolateValue( double t )". На основании этого предполагаю, что эта "кривая" нужна для генерации "точки кривой" в заданный момент времени (множества точек в заданный интервал времени с заданным шагом). С этой точки зрения, это уже не кривая, а "генератор" "кривых"/"точек кривых". Как и на основе чего он будет генерировать эти точки - глубоко его личные проблемы и пользователей этого генератора особо волновать не должно. В контексте данной темы получается, что "точки кривой" генерируются на основе "ключевых точек" по заданному правилу (типу сплайна). Опять же, если смотреть с точки зрения функциональной значимости, то есть "интерполятор", который генерирует/интерполирует "точки кривой" в окрестностях "ключевых точек"/"сегменте"/"сегментах". При этом получается, что одна из реализаций "генератора" состоит из набора "интерполяторов".

Далее следует резонный вопрос: и как создавать/изменять все эти "генераторы", "интерполяторы", и самое главное, как туда ключевые точки с параметрами сплайна пихать, особенно если они разного типа могут быть? Это требуется в run-time, поэтому: интерфейс/базовый класс -> реализация и свитч или dynamic_cast до значимого интерфейса/реализации.

Вот эти Curve, о которых в теме говорили, в вашей программе как создаются, заполняются значениями и изменяются? Всё вручную в коде жёстко забито? Или загружаются/сохраняются в файлах, а для редактирования используются какие-то GUI редакторы?

Если тип времени один - это хорошо. Только я бы сделал как минимум "using CurveTime = double;", сегодня оно double, а завтра не совсем double (а то может и совсем не double, например, это время может быть отрицательным?).
Типичное "если бы да кабы" - вот так, с ни хрена, нагрузить код еще одним шаблоном (а вдруг понадобится?). Мягко говоря "заслуживает самого сурового осуждения"  Плачущий
Про то, что это не шаблон, а элементарный typedef выше уже сказали. Такой псевдоним стоит сделать уже ради того, чтобы к обезличенному double добавить смысла, что это не какое-то абстрактное вещественное число, а время. Если смотреть чуть дальше, то тип "время кривой" может выражаться вещественным числом с какими-либо ограничениями, например, не может быть отрицательным, или понадобятся какие-нибудь дополнительные возможности, например, конвертация в/из time_t/std::...::time_point/QDateTime. Тогда CurveTime лучше сделать уже классом. А так как заранее для него существовал псевдоним, то делать рефакторинг по CurveTime будет проще, чем по double.
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #49 : Сентябрь 03, 2017, 09:59 »

Про то, что это не шаблон, а элементарный typedef выше уже сказали. Такой псевдоним стоит сделать уже ради того, чтобы к обезличенному double добавить смысла, что это не какое-то абстрактное вещественное число, а время. Если смотреть чуть дальше, то тип "время кривой" может выражаться вещественным числом с какими-либо ограничениями, например, не может быть отрицательным, или понадобятся какие-нибудь дополнительные возможности, например, конвертация в/из time_t/std::...::time_point/QDateTime. Тогда CurveTime лучше сделать уже классом. А так как заранее для него существовал псевдоним, то делать рефакторинг по CurveTime будет проще, чем по double.
Не хотелось бы особо раздувать этот мелкий момент, но все же.. Это спорно. Напр в одной либе (действительно крутой и классной) так и сделано,
Код
C++ (Qt)
typedef float btReal;
Ну ясное дело - теперь "легким движением руки" float превращается в double. Ни фига, не работает Улыбающийся Хотя и скомпилится, варнингов отсыпется туча (потеря точности), а главное - есть немало кода SSE(E) завязанного именно на 4-байтовый флоат. И в том же OpenGL замена double <-> float далеко не безобидна. В рез-те летит там и сям, а разбираться в большом коде желающих нет

Ну так может и не стоило притворяться и заявлять что, мол, "это можно будет (легко) сделать"? Дескать, "это на будущее, мы смотрим далеко вперед" Улыбающийся Неправда, никуда мы не смотрим, просто лепим "по книжке" - и все.

С др стороны самый безобидный typedef все-таки поглощает внимание программиста, все-таки надо вспоминать типа "а, это float" - пусть какие-то доли секунды, но все же. А когда таких typedef налеплено много - возникают уже серьезные трудности с пониманием написанного. Впрочем это мое личное мнение, моя память хуже средней.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #50 : Сентябрь 03, 2017, 14:04 »

Не хотелось бы особо раздувать этот мелкий момент, но все же.. Это спорно. Напр в одной либе (действительно крутой и классной) так и сделано,
Код
C++ (Qt)
typedef float btReal;
Ну ясное дело - теперь "легким движением руки" float превращается в double. Ни фига, не работает Улыбающийся Хотя и скомпилится, варнингов отсыпется туча (потеря точности), а главное - есть немало кода SSE(E) завязанного именно на 4-байтовый флоат. И в том же OpenGL замена double <-> float далеко не безобидна. В рез-те летит там и сям, а разбираться в большом коде желающих нет

Ну так может и не стоило притворяться и заявлять что, мол, "это можно будет (легко) сделать"? Дескать, "это на будущее, мы смотрим далеко вперед" Улыбающийся Неправда, никуда мы не смотрим, просто лепим "по книжке" - и все.

Я упор делал не на то, что в один прекрасный момент float на double поменяется, а на то, что могут появиться какие-либо ограничения, проверки валидности, дополнительные значимые для этого типа операции. И лучше бы их иметь в одном классе, чем в куче глобальных функций.

С др стороны самый безобидный typedef все-таки поглощает внимание программиста, все-таки надо вспоминать типа "а, это float" - пусть какие-то доли секунды, но все же. А когда таких typedef налеплено много - возникают уже серьезные трудности с пониманием написанного. Впрочем это мое личное мнение, моя память хуже средней.

О типе CurveTime надо думать именно как о времени (или что он там может значить в контексте кривых), пусть на текущий момент он и очень похож на double. Взять, к примеру, QDateTime. Вы знаете в каком типе он хранит свои внутренние данные? Знание этого внутреннего типа Вам помогает/мешает пользоваться классом QDateTime? Лично мне от этого знания ни горячо ни холодно. И если этот внутренний тип когда-нибудь изменится, надеюсь я об этом не узнаю и никак не почувствую в своём коде Улыбающийся. И взять с другой стороны time_t, который часто не более чем "typedef long time_t;". Зачем это делали и отвлекали на доли секунды? Писали бы везде long да и всё Улыбающийся.
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #51 : Сентябрь 04, 2017, 10:20 »

В своём примере я не рассматривал методы типа AddKey, DelNthKey и им подобные потому что полагаю, что им не место в том классе, который сейчас называется Curve. На мой взгляд, единственная значимая функциональность "кривой" Curve, которая мелькала в теме - это метод "InterpolateValue( double t )".
Оригинальное мЫшление, во всяком случае у меня совсем не такое  Улыбающийся Интерполяция (математика сплайнов) конечно есть, как же без нее. Но я ведь совсем не призывал ее разрывать. Ну работает себе да и работает. А вот как эти разнообразные сплайны (с разными типами данных) "поселить" - вот что предлагалось обсудить.

Вот эти Curve, о которых в теме говорили, в вашей программе как создаются, заполняются значениями и изменяются? Всё вручную в коде жёстко забито? Или загружаются/сохраняются в файлах, а для редактирования используются какие-то GUI редакторы?
Это просто "линейка времени". Есть объект, напр кубик, у него есть много всяких параметров - ну хотя бы "позиция в мире". Однако это не фиксированное значение, а "анимационная кривая". Т.е. если юзверь подвинет бегунок времени - то и кубик переместится куда Curve скажет

Все-таки - а какие есть еще решения? Что-то смутно помню про паттерн "обстервер" но сам ни разу его не юзал. Ну и как его сюда воткнуть? Еще какие мысли/идеи?
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #52 : Сентябрь 04, 2017, 14:20 »

Оригинальное мЫшление, во всяком случае у меня совсем не такое  Улыбающийся

Мышление не оригинальное, оно объектно-ориентированное Улыбающийся. В противовес стилю C, раннего С++, фреймворков MFC, Qt, которые больше тяготеют к процедурному. Нельзя сказать, что одно лучше другого, нужно их применять разумно, возможно в комбинации. Может кто-нибудь ещё придёт в тему и скажет: "Вы всё неправильно делаете! Надо писать в функциональном стиле!" Улыбающийся.

Это просто "линейка времени". Есть объект, напр кубик, у него есть много всяких параметров - ну хотя бы "позиция в мире". Однако это не фиксированное значение, а "анимационная кривая". Т.е. если юзверь подвинет бегунок времени - то и кубик переместится куда Curve скажет

Интерполяция (математика сплайнов) конечно есть, как же без нее. Но я ведь совсем не призывал ее разрывать.

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

Соответственно имеем два интерфейса (пока примерно):
Код
C++ (Qt)
class PointGenerator
{
   virtual double generate(Time time) = 0;
};
 
class EditableCurve
{
   virtual void addKey(Time time, Key key) = 0;
   virtual void removeKey(Time time, Key key) = 0;
   virtual Key & keyAt(Time time) = 0;
};
 

Далее пишется конкретный класс, который реализует эти интерфейсы:
Код
C++ (Qt)
class CurveGenerator : public PointGenerator, public EditableCurve
{
   double generate(Time time) override;
 
   void addKey(Time time, Key key) override;
   void removeKey(Time time, Key key) override;
   Key & keyAt(Time time) override;
};
 

Кубик может иметь связь с PointGenerator. Чтобы этот генератор передать редактору, нужно сделать dynamic_cast<EditableCurve>.

Далее про множество типов и шаблоны. Кубик можно переместить в какую-то точку пространства (Vector3D), вряд ли его можно переместить в "красный цвет". Равно как и покрасить в "координату пространства". Соответственно, для перемещения кубик должен иметь связь с PointGenerator<Vector3D>, а для изменения цвета - с PointGenerator<Color>. Если все эти кривые должны лежать в одном контейнере, то вводим общего предка BasePointGenerator, от него наследуем шаблонные PointGenerator<Vector3D>, PointGenerator<Color>. И разгребаем в зависимости от ситуации: надо переместить кубик - ищем dynamic_cast'ом PointGenerator<Vector3D> и перемещаем; в контейнере/параметре метода встретился PointGenerator<Vector3D> - перемещаем кубик, PointGenerator<Color> - изменяем цвет. Поэтому я не вижу особого смысла сваливать типы данных кривых в один variant<double, Vector3D, Color>. И при всём этом у PointGenerator нет никаких головняков с ключевыми точками, множеством типов сплайнов и прочего.

А вот как эти разнообразные сплайны (с разными типами данных) "поселить" - вот что предлагалось обсудить.

Подход такой же: идти от функциональности, а не от данных. Сплайны нужны, чтобы выдать интерполированное значение в какой-то момент времени. Интерфейс примерно такой:

Код
C++ (Qt)
class Interpolator
{
   virtual double interpolate(Time time) = 0;
   virtual Time keyTime() const = 0;
};
где keyTime - время ключевой точки, в окрестностях которой интерполятор может генерировать точки. Или может стоит ввести диапазон - границы ответственности текущего интерполятора.

Хранить эти интерполяторы можно в простом vector<Interpolator *>. Генератор кривой ищет в этом контейнере интерполятор, который ответственен за требуемое время time, и вызывает его interpolate(time).

И EditableCurve, описанный выше, будет оперировать не только ключевыми точками Key, но и интерполяторами Interpolator.

Конкретные интерполяторы с параметрами сплайна наследуются от Interpolator:
Код
C++ (Qt)
template <class CurvePoint, class T>
class RatioInterpolator : public Interpolator
{
   RatioInterpolator(Time keyTime, Key & key_1, Key & key_2, Key & key_3)
      : m_keyTime(keyTime), m_key_1(key_1), m_key_2(key_2), m_key_3(key_3)
   {}
 
   CurvePoint interpolate(Time time) override;
   Time keyTime() const override { return m_keyTime; }
 
   T inRatioVector;
   T outRatioVector;
 
   Time m_keyTime;
   Key & m_key_1;
   Key & m_key_2;
   Key & m_key_3;
};

А бедным редакторам придётся разгребать всё это множество разнотипных XxxInterpolator. Здесь возможно придётся организовать фабрику редакторов. Грубо говоря, что-то вроде QItemEditorFactory.

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

Все-таки - а какие есть еще решения? Что-то смутно помню про паттерн "обстервер" но сам ни разу его не юзал. Ну и как его сюда воткнуть? Еще какие мысли/идеи?

Скорее паттерн Visitor. Например, когда к "геометрическому объекту" нужно применить "кривую", или "кривую" отредактировать с помощью "редактора", и при этом возникает задача двойной диспетчеризации.

Кстати, не пробовали смотреть исходники какого-нибудь Inkscape? Там тоже рисуются кривые с разными типами сплайна в отдельных точках.
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #53 : Сентябрь 05, 2017, 08:45 »

А бедным редакторам придётся разгребать всё это множество разнотипных XxxInterpolator. Здесь возможно придётся организовать фабрику редакторов. Грубо говоря, что-то вроде QItemEditorFactory.

Как я предупреждал, классов получается очень много. И появляются трудности не столько с написанием кода, сколько с придумыванием адекватных названий для классов и методов Улыбающийся.
Вот сейчас, без всяких плюсов, кривая рисуется примерно так
Код
C++ (Qt)
void DrawCurve( Curve * curve )
{
  Key * key = GetFirstKey(curve);
  while (key) {
   Key * next = GetNextKey(key);
   if (!next) break;
   DrawSegment(curve, key, next);
   key = next;
 }
}
 
void DrawSegment( Curve * curve, Key * key0, Key * key1 )
{
 Coordinate pos;
 
 double tStep = (GetKeyTime(key1) - GetKeyTime(key0)) / drawSteps;
 for (size_t i = 0; i < drawSteps; ++i) {
   InterpolateCurve(i * tStep, key0, key1, &pos);
   AddOpenGLVertex(pos);
 }  
}
 
Сколько здесь классов? Не считая просто структур (без методов) НОЛЬ (не говоря уже о сраных шаблонах). Тем не менее - прекрасный код, Вы его поняли сразу (а вот я Ваш не очень Улыбающийся). Зачем же бездумно плодить массу классов? Если класс Curve сделан хорошо, то его использование легко и приятно как выше. А если мы заряжаем класс на каждый чих - то по сути мы перекладываем заботы на др части кода. А этих частей конечно намного больше. Мало того что это просто невыгодно - не вижу даже "чисто теоретических" оснований. Ну напр эта curve имеет др тип данных (не Coordinate) - так assert и вся любовь, нечего было 2-мерную кривую рисовать как 3-мерную. А уж доставать наружу потроха сплайнов - полная дичь, это глубоко личные подробности кривой. 

Но нет, нам неймется, простой код - это не круто. Надо же наделать кучу шаблонов. хвабрик и еще бог весть чего. Увы, часто, разобравшись во всем этом, приходим к выводу - да за этим ничего не стоит, просто фуфло
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #54 : Сентябрь 05, 2017, 12:13 »

Сколько здесь классов? Не считая просто структур (без методов) НОЛЬ (не говоря уже о сраных шаблонах). Тем не менее - прекрасный код, Вы его поняли сразу (а вот я Ваш не очень Улыбающийся).

Ну давайте нарисуем мою кривую в функции:
Код
C++ (Qt)
void DrawCurve(PointGenerator * generator, Time from, Time to, Time step)
{
   for (Time time = from; time <= to; time += step )
       AddOpenGLVertex(generator->generate(time));
}

Много тут классов? Или кода непонятного? Улыбающийся

Теперь давайте посмотрим, что нужно знать функции DrawCurve в Вашем и в моём случае:
(в Вашем) - целиком класс Curve, что она состоит из каких-то ключей, что выполняется какая-то интерполяция.
(в моём) - достаточно одного интерфейса PointGenerator, т.е. сделать #include PointGenerator.h, который выглядит так:
Код
C++ (Qt)
class PointGenerator
{
   virtual double generate(Time time) = 0;
};

Зачем же бездумно плодить массу классов? Если класс Curve сделан хорошо, то его использование легко и приятно как выше. А если мы заряжаем класс на каждый чих - то по сути мы перекладываем заботы на др части кода. А этих частей конечно намного больше. Мало того что это просто невыгодно - не вижу даже "чисто теоретических" оснований. Ну напр эта curve имеет др тип данных (не Coordinate) - так assert и вся любовь, нечего было 2-мерную кривую рисовать как 3-мерную. А уж доставать наружу потроха сплайнов - полная дичь, это глубоко личные подробности кривой.

Массу классов я нагородил, чтобы они расширялись под Ваши будущие хотелки. Например: "Сейчас тип сплайна один для всей кривой, но есть желание чтобы можно было задавать тип сплайна для каждого ключа (контрольной точки) индивидуально.". Вы так и не рассказали, как редактируете эти контрольные точки. Поэтому мне приходится самому об этом догадываться. Я бы делал примерно так, как в Inkscape редактируются кривые.

Но нет, нам неймется, простой код - это не круто. Надо же наделать кучу шаблонов. хвабрик и еще бог весть чего. Увы, часто, разобравшись во всем этом, приходим к выводу - да за этим ничего не стоит, просто фуфло
По поводу фуфла и простого кода. Если хотите всё в один класс запихнуть - то это не ко мне Улыбающийся.
Записан

Пока сам не сделаешь...
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #55 : Сентябрь 05, 2017, 12:25 »

ViTech, а вы отчаянный. Улыбающийся
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #56 : Сентябрь 05, 2017, 12:46 »

ViTech, а вы отчаянный. Улыбающийся

А вдруг Улыбающийся.
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #57 : Сентябрь 06, 2017, 10:30 »

Теперь давайте посмотрим, что нужно знать функции DrawCurve в Вашем и в моём случае:
(в Вашем) - целиком класс Curve, что она состоит из каких-то ключей, что выполняется какая-то интерполяция.
(в моём) - достаточно одного интерфейса PointGenerator,
Да, curve состоит из ключей между которыми выполняется та или иная интерполяция. Да, все части кода если и не должны, то могут опираться на это. ЗАЧЕМ рисовать абстрактный интерфейс в расчете на то что
Цитировать
а может в будущем это будет не так?
Непонимающий Даже если (ну гипотетически, предположим) это случится - такие "заготовки на будущее" не спасут, т.к. они писались без знания новых потребностей. А вот разбивать ноги об них (и больно) придется уже сейчас. Обратите внимание - мой пример использует только Curve и Key, т.е. сущности заявленные в стартовом посте. Ваш немедленно привлекает новый класс, а он вероятно еще и еще. Так это классика
Цитировать
Не плодите сущностей

По поводу фуфла и простого кода. Если хотите всё в один класс запихнуть - то это не ко мне
А что собсно "все"? Что curve умеет хранить и интерполировать контрольные точки? Так это нормально, для этого данный класс и предназначен. Ненормально как раз заводить для этого десятки разных классов, "сущность" одна и класс должен быть один.

Вы так и не рассказали, как редактируете эти контрольные точки. Поэтому мне приходится самому об этом догадываться. Я бы делал примерно так, как в Inkscape редактируются кривые.
Ну кривые рисуются в окнах, если юзер выберет Key(s),  то появляются "ручки" которые он может таскать настраивая сплайн интерактивно. Для др типов сплайна можно скроллить параметр в UI наблюдая как меняется кривая. Это давно сделано и работает хорошо, нет необходимости смотреть как это в др приложениях.

Конечно мне не жалко это рассказать, но я никак не пойму зачем Вам нужно это знать Улыбающийся И ежу понятно что если есть "параметры сплайна" в каждой точке - то их будут менять. Но кто и как - это класс Curve совершенно не волнует, он лишь хранит их и обеспечивает доступ к ним
« Последнее редактирование: Сентябрь 06, 2017, 10:31 от Igors » Записан
Bepec
Гость
« Ответ #58 : Сентябрь 06, 2017, 11:09 »

Я прям вижу как Igors разрывает на части, из-за противоречия между "хочу расширяемость" и "не плодите сущностей".
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #59 : Сентябрь 06, 2017, 12:24 »

Да, curve состоит из ключей между которыми выполняется та или иная интерполяция. Да, все части кода если и не должны, то могут опираться на это.

Тут дело такое:
Вариант 1.
Код
C++ (Qt)
void DrawCurve( Curve * curve )
{
  Key * key = GetFirstKey(curve);
  while (key) {
   Key * next = GetNextKey(key);
   if (!next) break;
   DrawSegment(curve, key, next);
   key = next;
 }
}
 
void DrawSegment( Curve * curve, Key * key0, Key * key1 )
{
 Coordinate pos;
 
 double tStep = (GetKeyTime(key1) - GetKeyTime(key0)) / drawSteps;
 for (size_t i = 0; i < drawSteps; ++i) {
   InterpolateCurve(i * tStep, key0, key1, &pos);
   AddOpenGLVertex(pos);
 }  
}

Вариант 2.
Код
C++ (Qt)
void DrawCurve(PointGenerator * generator, Time from, Time to, Time step)
{
   for (Time time = from; time <= to; time += step )
       AddOpenGLVertex(generator->generate(time));
}

Если Вам нравится, итерируя по точкам кривой, каждый раз писать как в варианте 1, то, как говорится: хозяин - барин Улыбающийся. Я же предпочитаю второй вариант.

ЗАЧЕМ рисовать абстрактный интерфейс в расчете на то что
Цитировать
а может в будущем это будет не так?
Непонимающий Даже если (ну гипотетически, предположим) это случится - такие "заготовки на будущее" не спасут, т.к. они писались без знания новых потребностей. А вот разбивать ноги об них (и больно) придется уже сейчас. Обратите внимание - мой пример использует только Curve и Key, т.е. сущности заявленные в стартовом посте. Ваш немедленно привлекает новый класс, а он вероятно еще и еще. Так это классика
Цитировать
Не плодите сущностей

Основной вопрос: эта кривая нужна больше чтобы её использовать как конечный набор точек(интерполированных) на заданном интервале времени, или она нужна чтобы её постоянно редактировали, загружали/сохраняли/печатали её ключи?

Собственно контекст использования, о чём сразу же в первом ответе этой темы и спросили. Вы так цепляетесь за эти ключи и параметры сплайны, что мне вспоминаются строки из классики: "В уездном городе N было так много парикмахерских заведений и бюро похоронных процессий, что, казалось, жители города рождаются лишь затем, чтобы побриться, остричься, освежить голову вежеталем и сразу же умереть."("Двенадцать стульев"). Если перефразировать, то кривые нужны лишь затем, чтобы их создать, загрузить, поиграться в редакторе, сохранить и удалить. Если контекст использования такой, то да, мои классы типа PointGenerator не нужны.

Если же предположить, что кривые нужны больше для того, чтобы с их помощью двигать объекты и тому подобное, т.е. использовать их как набор точек, то интерфейса PointGenerator будет достаточно. Для разработчика, который пользуется кривыми таким образом, как раз ключи и параметры сплайнов будут лишними сущностями. Можете объяснить, при перемещении объекта из точки А в точку Б, зачем знать какие там ключевые точки, параметры сплайна, и что они вообще есть? Так что это ещё вопрос, кто сущности плодит Улыбающийся.

А что собсно "все"? Что curve умеет хранить и интерполировать контрольные точки? Так это нормально, для этого данный класс и предназначен. Ненормально как раз заводить для этого десятки разных классов, "сущность" одна и класс должен быть один.

Ладно, я уже не буду фантазировать про кэширование интерполированных данных и использование заранее рассчитанных кривых, которые могут являть собой простой контейнер map<Time, Vector3D>/vector<struct{Time; Vector3D}>.

Ну кривые рисуются в окнах, если юзер выберет Key(s),  то появляются "ручки" которые он может таскать настраивая сплайн интерактивно. Для др типов сплайна можно скроллить параметр в UI наблюдая как меняется кривая. Это давно сделано и работает хорошо, нет необходимости смотреть как это в др приложениях.

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

Ежи вообще самые понятливые животные, мне до них далеко Улыбающийся. Но может быть такой сценарий использования, что параметры сплайна используются при интерполяции, загружаются из файла и в программе не редактируются. Может эти ключевые точки формируются во внешнем продвинутом редакторе, снимаются с датчиков motion capture, да мало ли ещё откуда появляются.
Записан

Пока сам не сделаешь...
Страниц: 1 2 3 [4] 5   Вверх
  Печать  
 
Перейти в:  


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