Russian Qt Forum

Программирование => Общий => Тема начата: Igors от Август 23, 2017, 08:39



Название: Переделать старые структуры
Отправлено: Igors от Август 23, 2017, 08:39
Добрый день

Есть класс Curve (кривая) которая задается контейнером "ключей" (контрольных точек) + типом сплайна. Curve выдает значение параметра для заданного времени t (т.е. просто (редактируемый график). Значения бывают 3 типов

- число (double)
- вектор (3 double x, y, z)
- цвет с альфой (4 uchar)

Реализован это класс был в незапамятные времена, наверное еще на паскале, потом кое-как переведен на С, и вот дожил до наших дней
Код
C++ (Qt)
struct Curve {
// общие данные для всех типов кривых
int dataType;  // тип значения кривой
union {
  DoubleCurve * doubleCurve;
  VectorCurve * vectorCurve;
  СolorCurve * colorCurve;
};
};
 
Возможно тут Вы ожидали что каждая кривая хранит контейнер значений своего типа - но это не так. VectorCurve хранит 3 контейнера для каждой компоненты, СolorCurve - 4 контейнера
Код
C++ (Qt)
struct VectorCurve {
 ...
 Container<Key> xList;
 Container<Key> yList;
 Container<Key> zList;
};
 
struct Key {
 double time;
 double val;
 union {
    // опции сплайна
 };
};
Ну и работа с такими структурами мгновенно сваливается в бесконечное свитчевание по dataType. Масса кода дублируетcя т.к. его надо повторять для каждого контейнера x, y, z (a, r, g, b). Напр вместо одной вставки ключа - 3 или даже 4. Это уже просто неграмотно.

Очевидно нужны template. Но вот почему-то ничего хорошего не жду. Охотно играются с финтифлюшками на темплейтах, дают советы "на будущИе". но вот когда доходит до дела - следуют рекомендации типа " делай сам" или более мягкое "работает? - так ото не трогай". Ну ладно, посмотрим, может я и неправ.

Так как же привести это в божеский вид ?

Спасибо


Название: Re: Переделать старые структуры
Отправлено: kai666_73 от Август 23, 2017, 11:42
А вот кто и как эту курву пользует? Тут контекст использования играет ключевую роль.
Не зная оного, можно давать лишь абстрактные советы, насколько я понял, изрядно Вас нервирующие.

Типа (ну кроме template), сделать Curve абстрактным классом и...


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 23, 2017, 13:14
А вот кто и как эту курву пользует? Тут контекст использования играет ключевую роль.
В стартовом посте написано
Есть класс Curve (кривая) которая задается контейнером "ключей" (контрольных точек) + типом сплайна. Curve выдает значение параметра для заданного времени t (т.е. просто (редактируемый график).
Если так, то как минимум налицо простейший базовый ф-ционал: добавить/удалить контрольyую точку(и), изменить ее время и/или значение. И этого совершенно достаточно для построения, разработки структур данных (данная тема). И объяснять это специально не нужно, т.к. здесь малограмотных нет.

Не зная оного, можно давать лишь абстрактные советы, насколько я понял, изрядно Вас нервирующие.
Я совсем не против абстракции, ведь данные что я привел абстрактны - реальные структуры содержат много десятков членов. А вот обычная песенка сачка "надо знать задачу" - да, нервирует  :)



Название: Re: Переделать старые структуры
Отправлено: deMax от Август 23, 2017, 13:44
Может вместо union сделать 3 наследника или QVariant?

Зачем вы разные кривые в одну структуру засунули?


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 23, 2017, 13:58
Структуру поменять на класс, нечего с полями работать.
Интерфейс типа:
Цитировать
Curve c;
void c.setDoubles(QList<double>);
void c.setVectors(QList<Qpoint3D>);
void c.setColors(QList<QColor>);
double c.getDouble(QDateTime t);
Qvector3d c.getVector(QDateTime t);
QColor c.getColor(QDateTime t);

Вроде все просто, напрямую работать со структурой, это плодить одинаковый код.
Или тут есть некая хитрость? Опишите каким бы вы хотели видеть интерфейс, а мы подумаем как это реализовать.


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 23, 2017, 14:02
Я бы вообще сделал класс сплайн(или готовый взял) с тремя функциями:
Цитировать
class Spline {
static double     c.getDouble(const QList<double> &data,     const QDateTime t);
static Qpoint3D c.getVector (const QList<Qpoint3D> &data, const QDateTime t);
static QColor     c.getColor   (const QList<QColor> &data,     const QDateTime t);
};


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 23, 2017, 14:05
А вот кто и как эту курву пользует? Тут контекст использования играет ключевую роль.
В стартовом посте написано

Не стоит принижать роль контекста/вариантов использования. Я тоже считаю, что это имеет важное значение. В частности набор и тип векторов в кривой задаётся на этапе компиляции или может меняться в рантайме? В объекте типа Curve в рантайме можно поменять dataType и соответственно вектор данных? Доступ к элементам кривой предпочтителен в виде набора параметров в заданной точке, или желателен/необходим доступ к параметру в виде вектора. В зависимости ответов на эти вопросы реализация класса кривой, её компонентов, и работа с ними может различаться кардинально.


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 23, 2017, 17:14
В частности набор и тип векторов в кривой задаётся на этапе компиляции или может меняться в рантайме? В объекте типа Curve в рантайме можно поменять dataType и соответственно вектор данных?
Если юзер создал кривую типа "число" - то он никак не сможет преобразовать ее в тип "вектор" или "цвет", и наоборот. Можно только удалить кривую и создать новую, это нормально. А вот поменять тип сплайна (см класс Key) может. Сейчас тип сплайна один для всей кривой, но есть желание чтобы можно было задавать тип сплайна для каждого ключа (контрольной точки) индивидуально. 

Доступ к элементам кривой предпочтителен в виде набора параметров в заданной точке, или желателен/необходим доступ к параметру в виде вектора.
Да, есть векторные операции. напр сместить кривую или вписать ее в диапазон по х/y. Но они не крытычны, могут быть спокойно сделаны в цикле for. Главное - чтобы их (и другиx) не пришлось мучительно расписывать (дублировать) для каждого типа кривой.

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

Я бы вообще сделал класс сплайн(или готовый взял) с тремя функциями:
Цитировать
class Spline {
static double     c.getDouble(const QList<double> &data,     const QDateTime t);
static Qpoint3D c.getVector (const QList<Qpoint3D> &data, const QDateTime t);
static QColor     c.getColor   (const QList<QColor> &data,     const QDateTime t);
};
Опять "резвости" хоть отбавляй :) Вот параметры всего лишь одного из сплайнов (для каждого ключа)
Код
C++ (Qt)
double inRatioVector; // Incoming Vector
double outRatioVector; // Outgoing Vector
double inRatioAngle; // Incoming Angle
double outRatioAngle; // Outgoing Angle
double inWeight; // Incoming Weight
double outWeight; // Outgoing Weight
int ratioFlags; // Flags governing the interpolation
 


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 23, 2017, 19:34
Доступ к элементам кривой предпочтителен в виде набора параметров в заданной точке, или желателен/необходим доступ к параметру в виде вектора.
Да, есть векторные операции. напр сместить кривую или вписать ее в диапазон по х/y. Но они не крытычны, могут быть спокойно сделаны в цикле for. Главное - чтобы их (и другиx) не пришлось мучительно расписывать (дублировать) для каждого типа кривой.

Здесь, похоже, возникли непонятки из-за многозначности слова "вектор". Я имел в виду вектор как контейнер для каждого параметра. Например:

Код
C++ (Qt)
struct XYColorCurve
{
   vector<double> x;
   vector<double> y;
   vector<Color> c;
}
 

И "перпендикулярное" предыдущему представление:
Код
C++ (Qt)
struct XYColor
{
   double x;
   double y;
   Color c;
}
 
using XYColorCurve = vector<XYColor>;
 

Какой из двух вариантов предпочтителен? Это как раз зависит от вариантов использования. Например, для передачи координат в буферы OpenGL может быть предпочтителен первый вариант. А если больше приходится работать с отдельными "точками" - то второй.

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

В С++ способы организации классов и работы с ними довольно сильно различаются для случаев "compile time" и "run time". Грубо говоря: шаблоны - они про  "compile time", базовый класс -> наследник + виртуальные методы - они про "run time". Можно попытаться это совместить, но не факт что из этого что-то хорошее выйдет. Поэтому и нужно заранее знать, что для чего делается и как использоваться будет.

Опять "резвости" хоть отбавляй :) Вот параметры всего лишь одного из сплайнов (для каждого ключа)
Код
C++ (Qt)
double inRatioVector; // Incoming Vector
double outRatioVector; // Outgoing Vector
double inRatioAngle; // Incoming Angle
double outRatioAngle; // Outgoing Angle
double inWeight; // Incoming Weight
double outWeight; // Outgoing Weight
int ratioFlags; // Flags governing the interpolation
 

Вот этот набор параметров он формируется в  "compile time" или пользователь может его изменять в "run time"? Например, удалить из этого набора inWeight,  outWeight и добавить какой-нибудь Color?

Если набор параметров формируется в "compile time", то чем не подходит грубое:
Код
C++ (Qt)
struct RatioWeight
{
   double inRatioVector; // Incoming Vector
   double outRatioVector; // Outgoing Vector
   double inRatioAngle; // Incoming Angle
   double outRatioAngle; // Outgoing Angle
   double inWeight; // Incoming Weight
   double outWeight; // Outgoing Weight
   int ratioFlags; // Flags governing the interpolation
}
 
using RatioWeightCurve = map<Key, RatioWeight>;
 


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 24, 2017, 07:34
ViTech, для краткости цитирование опускаю. Разумеется хотелось бы иметь нормальную структуру (а не кучу разобщенных массивов). Предположим есть 1 тип данных (напр вектор) и 1 тип сплайна. Тогда
Код
C++ (Qt)
struct Key {
 double time;  // время  
 Vector vec;    // данные
 
 int splineOption1;   // параметры сплайна
 ...
 double splineOptionN;
};
Ну и кривая - просто контейнер Key, возможно еще с доп данными для всех ключей. Однако данные могут быть 3 типов, а сплайны 6 типов. Собсно это первое (и наверное главное) что хотят от template, задача очень банальна.

Сейчас по существу реализован вариант с "расслоением", т.е. заводится контейнер на каждую компоненту вектора (x, y, z). Очевидно такая работа "покомпонентно" весьма затратна с любой точки зрения. Помнится Вы говорили что template схопывает код - ну вот Вам и карты в руки, схлопывайте.


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 24, 2017, 09:14
Однако данные могут быть 3 типов, а сплайны 6 типов. Собсно это первое (и наверное главное) что хотят от template, задача очень банальна.
Жуткие структуры с жуткой логикой надо оборачивать в класс, а потом заменить. По шаблону могу предположить:
Код:
template<class T> Curve
{
  QMap<Key, T> data;
public:
  void getData(&T, QDateTime t)
}

Curve<QVector3D> c1;
Curve<QColor> c2;
Curve<double> c3;
если c1,c2,c3 нужно засунуть зачем то в контейнер, сделайте базовый класс от которого они будут унаследованы. Так как шаблоные функции не могут быть виртуальными, придется конкретизировать наследника(или может можно как нибудь обмануть плюсы?)
Код:
double data;
 static_cast<Curve<double>* >(curveBasePointer)->getData(&data);

Я так понял у вас типа хэш массива, QMap<Key, QVector3D> будет быстрее доступ к элементу чем в трёх итераторах искать QMap<Key, int x>, QMap<Key, int y>, QMap<Key, int z>.

Почти для всех типов QVector3D, QColor, double умножение деление есть, так что сплайн будет работать.
Ну разве только у вас не QColor, а struct XYColor{    double x;    double y;    Color c; }. Тогда придется в этой структуре определить базовые операции.


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 24, 2017, 10:30
Код:
template<class T> Curve
{
  QMap<Key, T> data;
public:
  void getData(&T, QDateTime t)
}
Это только тип данных, а есть еще тип сплайна - оставим сишный union (со всеми вытекающими)? И время - просто double (а не QDateTime), не простираются мои кривые неделями и годами  :)

Код
C++ (Qt)
Curve<QVector3D> c1;
Curve<QColor> c2;
Curve<double> c3;
 
Ни за что не додумался бы так сделать! :) Только вот что я буду делать с зоопарком разных (с точки зрения компилятора) классов - хз.

сделайте базовый класс от которого они будут унаследованы. Так как шаблоные функции не могут быть виртуальными, придется конкретизировать наследника..
Наконец-то хоть слабые намеки на содержательную часть. Ну хорошо, допустим я оперирую с базовым классом
Код
C++ (Qt)
struct Curve {
 ...
 ??? GetData( double time ) const;   // возвращает значение для времени time
 void SetData( double time. const ??? & value );   // устанавливает значение для времени time
 ...
};
 
Что вместо вопросиков?


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 24, 2017, 11:19
Это только тип данных, а есть еще тип сплайна - оставим сишный union (со всеми вытекающими)? И время - просто double (а не QDateTime), не простираются мои кривые неделями и годами  :)
QDateTime - для примера т.к. это универсально, в данном вопросе не важно.

Я правильно понял задачу? Задача:
есть класс который хранил либо массив точек, либо массив чисел, либо массив цветов. Для каждой точки массива устанавливается один из видов сплайна(всего их минимум 6). Требуется по времени извлечь аппроксимированную точку.

Цитировать
??? GetData( double time ) const;   // возвращает значение для времени time
Что вместо вопросиков?
хороший наводящий вопрос, будет QVariant  ;)   а код будет примерно такой:
Код:
QVariant GetData( double time ) const
switch(currentType) {
case (DOUBLE): double d; static_cast<Curve<double>* >(this)->getData(&d); return Qvariant(d);
....


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 24, 2017, 11:36
Если QVariant не нравиться, можно создать класс типа UnionData{union {double d; Color c; Vector3d v}} с тремя конструкторами и тремя функциями get и математикой(для сплайна). Тогда и шаблон в принципе не нужен.

Цитировать
Ну хорошо, допустим я оперирую с базовым классом
в принципе можно вместо curve->setData(d), писать ((Curve<double>)curve)->setData(d); если это не внутри шаблона, вы и так знаете тип.


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 24, 2017, 11:40
Итого:
class UnionData{union {double d; Color c; Vector3d v}} с тремя конструкторами и тремя функциями get и математикой(для сплайна)
class Key { double time, ..... }
Spline { QMap<Key, UnionData> map; void set(Key, UnionData); UnionData get(Key); }


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 24, 2017, 13:15
Сейчас по существу реализован вариант с "расслоением", т.е. заводится контейнер на каждую компоненту вектора (x, y, z). Очевидно такая работа "покомпонентно" весьма затратна с любой точки зрения. Помнится Вы говорили что template схопывает код - ну вот Вам и карты в руки, схлопывайте.

Не думаю, что работа "покомпонентно" затратна с любой точки зрения. Нужно разбираться в конкретных вариантах использования. Например, для расхода по памяти что лучше: несколько больших непрерывных кусков или куча мелких осколков? Если будет необходимость передавать массивы координат в OpenGL, то лучше это делать из покомпонентных контейнеров или собирать из разбросанных кусков? Это может показаться преждевременной оптимизацией, но если с этим ошибиться в начале, то потом может ожидать значительная переработка. Заранее могу сказать, что есть способ обращаться к покомпонентным контейнерам как к структуре(аналогу) по "вертикальному" срезу.

ViTech, для краткости цитирование опускаю. Разумеется хотелось бы иметь нормальную структуру (а не кучу разобщенных массивов). Предположим есть 1 тип данных (напр вектор) и 1 тип сплайна. Тогда
Код
C++ (Qt)
struct Key {
   double time;
   Vector vec;
 
   int splineOption1;
   ...
   double splineOptionN;
};
Ну и кривая - просто контейнер Key, возможно еще с доп данными для всех ключей. Однако данные могут быть 3 типов, а сплайны 6 типов. Собсно это первое (и наверное главное) что хотят от template, задача очень банальна.

Как бы не хотелось, чтобы "эти чёртовы кривые просто были и работали", и не отвлекали от реальных дел, но придётся уделить им внимание и силы, чтобы работали они как "надо и удобно" :). Нужно проработать предметную область этих кривых. Например, определить составные части:
Код
C++ (Qt)
template <class Key, class Data, class Option>
struct CurvePoint
{
   Key key;
   Data data;
   Option option;
};
 
enum class SplineType
{
   Type_1,
   Type_2;
   ...
};
 
template <class Point, SplineType _SplineType>
struct Curve
{
   vector<Point> points;
};
 

Где Option - это структура из набора опций, но можно и по другому представить.

Далее придётся писать кучу специализаций Curve для заданных Point, SplineType (или чего-то ещё), выявлять в них общий код, выносить его отдельно и т.п. Легко не будет, но без шаблонов может получиться значительно сложнее :).


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 25, 2017, 10:13
Если будет необходимость передавать массивы координат в OpenGL, то лучше это делать из покомпонентных контейнеров или собирать из разбросанных кусков?
Зачем приводить в пример OpenGL с которым Вы никогда не имели дела? "Разбросанные куски" для него не проблема (для этого есть stride), а вот склеивать 3D координаты из массивов x, y, z - такого еще не видел :) Да и вообще если (когда-нибудь) нужно будет передавать туда контрольные точки - то будет задействовано VBO, и для данных на карте формат будет свой

Не думаю, что работа "покомпонентно" затратна с любой точки зрения.
Вместо одного контейнера 3 или 4. Одни и те же ключи (время) и флаги в каждом. Операции вставки, удаления, поиска и др дублируется для каждого контейнера. Единственное что может это оправдать - соображение "зато без всяких template!". Но уж очень коряво

Код
C++ (Qt)
template <class Key, class Data, class Option>
struct CurvePoint
{
   Key key;
   Data data;
   Option option;
};
 
Такое рисовать всякий может, ну и что с ним дальше делать? Curve должна быть членом всяких классов, делать их всех тоже шаблонными совершенно нереально.


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 25, 2017, 10:19
Итого:
class UnionData{union {double d; Color c; Vector3d v}} с тремя конструкторами и тремя функциями get и математикой(для сплайна)
union не позволит иметь хоть что-то "выше травы" POD, напр есть хотя бы конструктор - все, с приветом, членом union этот класс быть не может
Тогда и шаблон в принципе не нужен.
??? Не понял

class Key { double time, ..... }
Spline { QMap<Key, UnionData> map; void set(Key, UnionData); UnionData get(Key); }
А можно как-то более внятно?  :)


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 25, 2017, 11:06
Ну например, что то типа этого. (не скорую руку, нет констант, не все области видимости сделал, но компилиться и смысл думаю понятен):
Код:
struct Options {
    int arg1, arg2;
};

struct Color{char r,g,b,a;};
struct Vector3{float x,y,z;};

class UnionData {
public:
    enum DataType { NO,DOUBLE, COLOR, VECTOR3 };
private:
    enum TYPE_SPLINE{T1, T2} typeSpline;
    Options options;

    DataType dataType = NO;
public:
    union {double d; Color c; Vector3 v3;};
    bool isDataType(DataType dataType) {return dataType == this->dataType;}

    UnionData() { dataType = NO; }
    UnionData(double d){ dataType = DOUBLE; this->d = d;}
    UnionData(Color c){ dataType = COLOR; this->c = c;}
    UnionData(Vector3 v3){ dataType = VECTOR3; this->v3 = v3;}
};

class Spline {
    QMap<double /*time*/, UnionData> map;

    void getData(double time, double *data){if(map[time].isDataType(UnionData::DOUBLE)) *data = map[time].d;}
    void getData(double time, Color *data){if(map[time].isDataType(UnionData::COLOR)) *data = map[time].c;}
    void getData(double time, Vector3 *data){if(map[time].isDataType(UnionData::VECTOR3)) *data = map[time].v3;}
public:
    template <typename T> void set(double time, T data) { map[time] = UnionData(data); }
    template<typename T> T get(double time) {T data; getData(time, &data); return data; }
};


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 25, 2017, 12:08
и смысл думаю понятен
Понятен, это еще один вариант "без всяких template" (get/set просто удобство доступа), по существу все на "варианте" (кстати самопальный "вариант" здесь вполне оправдан).

- хранится "по максимуму", что вообще-то не есть хорошо

- никакой проверки на этапе компиляции, напр если "вектору" попытались назначить "цвет" - придется ловить  это в runtime (понатыкать assert'ов)

Поэтому гордиться таким решением точно не получится, придется объяснять типа "ну это вот удобно, практично" и.т.п. :) Но и это не так, забыли про тип сплайна - а он ведь тоже зависит от типа данных, напр
Код:
double inRatioVector; // Incoming Vector
double outRatioVector; // Outgoing Vector
Это ведь для типа данных double, для вектора эти параметры тоже будут вектора (3 double)


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 25, 2017, 13:37
Вы так заранее всё знаете, кто с чем имел дело и с чем нет, какова реализация того или иного решения и к чему оно приводит, что становится не интересно отвечать в Ваших темах :).

Зачем приводить в пример OpenGL с которым Вы никогда не имели дела? "Разбросанные куски" для него не проблема (для этого есть stride), а вот склеивать 3D координаты из массивов x, y, z - такого еще не видел :) Да и вообще если (когда-нибудь) нужно будет передавать туда контрольные точки - то будет задействовано VBO, и для данных на карте формат будет свой
Если нет разницы передать данные в VBO одним(несколькими) большим куском (грубо говоря memcpy) или итерировать по мапе и копировать поэлементно/повекторно, то на этот аспект можно не обращать внимание. Ещё я никогда не имел дела с шейдерами тесселяции и геометрическим. Но подозреваю, что если их добавили в графический конвейер, то кому-то это нужно.

Вместо одного контейнера 3 или 4. Одни и те же ключи (время) и флаги в каждом. Операции вставки, удаления, поиска и др дублируется для каждого контейнера. Единственное что может это оправдать - соображение "зато без всяких template!". Но уж очень коряво
Если Вы других вариантов реализации здесь не видите, то и ладно. По-моему, тут есть пространство для размышлений. Часть из них я высказал ранее.

Такое рисовать всякий может, ну и что с ним дальше делать? Curve должна быть членом всяких классов, делать их всех тоже шаблонными совершенно нереально.

Дальше можно сделать объявления:
Код
C++ (Qt)
using QuadraticBezierPoint = CurvePoint<DateTimeKey, Vector3D, QuadraticBezierOption>;
using CubicBezierPoint = CurvePoint<DateTimeKey, Vector3D, CubicBezierOption>;
using OneMorePoint = CurvePoint<DateTimeKey, Vector3D, OneMoreOption>;
 
using QuadraticBezierCurve = Curve<QuadraticBezierPoint, SplineType::QuadraticBezier>
using CubicBezierCurve = Curve<CubicBezierPoint, SplineType::CubicBezier>
using OneMoreCurve = Curve<OneMorePoint, SplineType::OneMoreCurve>
 
и использовать их в членах классов, параметрах методов и т.п.


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 25, 2017, 17:26
Дальше можно сделать объявления:
Код
C++ (Qt)
using QuadraticBezierPoint = CurvePoint<DateTimeKey, Vector3D, QuadraticBezierOption>;
using CubicBezierPoint = CurvePoint<DateTimeKey, Vector3D, CubicBezierOption>;
using OneMorePoint = CurvePoint<DateTimeKey, Vector3D, OneMoreOption>;
 
using QuadraticBezierCurve = Curve<QuadraticBezierPoint, SplineType::QuadraticBezier>
using CubicBezierCurve = Curve<CubicBezierPoint, SplineType::CubicBezier>
using OneMoreCurve = Curve<OneMorePoint, SplineType::OneMoreCurve>
 
и использовать их в членах классов, параметрах методов и т.п.
Так "с водой выплеснули ребенка", теперь у меня уже нет ОДНОГО класса Curve, а есть масса разных классов которые можно использовать только конкретно, "по месту". Разумеется это не устраивает, простейший резон уже приводился - поместить в контейнер. Обратите внимание что исходный класс, несмотря на всю корявость/убогость реализации, не имеет этого дефекта - он один. Также говорилось что юзер может менять тип сплайна, поэтому его параметризация неприемлема.


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 25, 2017, 19:40
Так "с водой выплеснули ребенка", теперь у меня уже нет ОДНОГО класса Curve, а есть масса разных классов которые можно использовать только конкретно, "по месту". Разумеется это не устраивает, простейший резон уже приводился - поместить в контейнер. Обратите внимание что исходный класс, несмотря на всю корявость/убогость реализации, не имеет этого дефекта - он один. Также говорилось что юзер может менять тип сплайна, поэтому его параметризация неприемлема.

Поместить в контейнер кривые, это примерно то же самое, что поместить в контейнер все виджеты формы. Можно это сделать, но контейнер тогда будет из элементов наиболее общего и близкого типа - QWidget *. Со всеми вытекающими последствиями: что можно с элементами этого контейнера делать и как отличать один от другого.

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

Пусть есть конкретные классы QuadraticBezierCurve и CubicBezierCurve, оба наследуются от интерфейса Curve, который не шаблонный. Какие методы у этого Curve? Что можно/нужно с ним делать? В общем-то об этом и вопрошали во первых сообщениях сей темы :).

Считайте, что у кривой нет такой возможности: "Curve выдает значение параметра для заданного времени t (т.е. просто (редактируемый график)". Ну не может она выдать своих параметров, зажала :). Вместо этого может с переданными ей данными сделать что-то в соответствии со свои типом сплайна и своими внутренними параметрами.

Если юзер может изменять тип сплайна, то всегда ли можно это делать? Например, для построения сегмента QuadraticBezierCurve нужны 3 опорные точки, а для CubicBezierCurve уже 4. Где при преобразовании QuadraticBezierCurve -> CubicBezierCurve брать эту 4-ю точку? Или в сплайне был один набор параметров (с Ratio, Weight и пр.), а поменять надо в сплайн с другим набором параметров. Можно ли такое сделать? И как тогда должна выглядеть сигнатура метода в Curve, который такое преобразование выполняет?


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 26, 2017, 08:39
Если юзер может изменять тип сплайна, то всегда ли можно это делать? Например, для построения сегмента QuadraticBezierCurve нужны 3 опорные точки, а для CubicBezierCurve уже 4. Где при преобразовании QuadraticBezierCurve -> CubicBezierCurve брать эту 4-ю точку? Или в сплайне был один набор параметров (с Ratio, Weight и пр.), а поменять надо в сплайн с другим набором параметров. Можно ли такое сделать? И как тогда должна выглядеть сигнатура метода в Curve, который такое преобразование выполняет?
Ну чего Вы мудрите? Если юзер меняет тип сплайна, то конечно все старые опции будут утеряны, замещены параметрами нового сплайна по умолчанию. Никаких "конверсий" ему не обещали, это др задача (причем достаточно сложная). Сигнатура - обычный  сеттер
Код
C++ (Qt)
void Curve::SetSplineType( SplineType type );

Поместить в контейнер кривые, это примерно то же самое, что поместить в контейнер все виджеты формы. Можно это сделать, но контейнер тогда будет из элементов наиболее общего и близкого типа - QWidget *. Со всеми вытекающими последствиями: что можно с элементами этого контейнера делать и как отличать один от другого.
Нормальная параллель/аналогия. И что плохого (или глупого) в контейнере <QWidget *>? Много действий существует для всех его наследников. Не все конечно. Напр не все виджеты имеют методы value/setValue и значения эти разных типов. Разумеется "отличать" - забота вызывающего, напр
Код
C++ (Qt)
int GetIntValue( const QWidget * widget );
 
Даже если действовать примитивно, перебирая dynamic_cast, в такой ф-ции есть смысл. Мы можем не хранить виджеты как члены классы, а слить их в контейнер и дергать напр по имени. Виджет не имеет int value? Ну assert и все дела, вызывающий понимает что делает. Да, ф-ция не будет работать автоматом для тех виджетов что когда-нибудь будут созданы и тоже иметь value - ничего, переживем, допишем код.

Здесь подобная ситуация, только вариантов намного меньше. Операции "изменить время ключа" или "удалить ключ" явно общие и от типа данных не зависят. Вот что делать со значениями? Очевидно что без вызовов напр таких
Код
C++ (Qt)
double Curve::GetDoubleValue( double time ) const;
 
не обойтись. Как их реализовать не влезая в switch-разборки?  


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 26, 2017, 13:06
Если идти в русле геттеров/сеттеров и не разбираться, что из себя представляет кривая как объект какой-то предметной области, то можно попробовать делать так: ввести AbstractCurve и плодить наследников.

Код
C++ (Qt)
template <class Data, class Key>
struct Curve : AbstractCurve
{
   map<Key, Data> data;
}
 

В членах класса и контейнерах можно хранить AbstractCurve. Ну и в каждом методе, который будет получать такую курву в качестве параметра, будет лапша из dynamic_cast (или чуть облегчить её свитчем по dataType):
Код
C++ (Qt)
void doSomething( AbstractCurve * curve )
{
  if (dynamic_cast<Curve<double, DateTime>*>(curve))
  { ... }
  else if (dynamic_cast<Curve<Vector3D, DateTime>*>(curve))
  { ... }
  else if (dynamic_cast<Curve<Color, DateTime>*>(curve))
  { ... }
}
 

Можно ещё попробовать паттерн Visitor к AbstractCurve прикрутить. Возможно станет немного легче и такой лапши в каждом методе не будет (но она перенесётся в другое место :)).

Фигня? Конечно фигня :). Но чтобы такой фигни не было, надо продумывать, что это за сущность такая эта кривая. Какие методы должны быть у AbstractCurve, общие для всех типов кривых, а не просто геттеры/сеттеры её данных.



Название: Re: Переделать старые структуры
Отправлено: Igors от Август 27, 2017, 10:05
Но чтобы такой фигни не было, надо продумывать, что это за сущность такая эта кривая. Какие методы должны быть у AbstractCurve, общие для всех типов кривых, а не просто геттеры/сеттеры её данных.
А что тут "продумывать"? Базовый ф-ционал очевиден
Код
C++ (Qt)
struct CurveDouble {
..
 void AddKey      ( double time, double value );  // добавить контрольную точку  
 void DelNthKey  ( int keyIndex );  // удалить контрольную точку  
 
 double GetNthKeyTime( int keyIndex ) const;   // получить время
 double SetNthKeyValue( int keyIndex, double value ) const;  // получить значение
 
 void SetNthKeyTime( int keyIndex, double time );   // установить время
 void SetNthKeyValue( int keyIndex, double value );  // установить значение
 
 double GetInterpolatedValue( double time ) const;   // получить интерполированное значение  
 
 const SplineOptions & GetNthSplineOptions( int keyIndex ) const;  // получить параметры сплайна
 void  SetNthSplineOptions( int keyIndex, const SplineOptions & opt ) const;  // установить параметры сплайна
...
};
 
Это просто вытекает из стартового поста, даже как-то неудобно это разжевывать. Ни о чем больше НЕ спрашивается, есть простой и ясный ф-ционал, давайте не будем менять задачу а подумаем как его обобщить для разных типов данных и сплайнов. Заметим что простейшее использование template, напр
Код
C++ (Qt)
Curve<double>
Curve<Vector>
Curve<Color>
 
Экономит реализацию, но "обобщением" не является, класс Curve должен быть ОДИН (а не куча всего)


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 27, 2017, 14:19
А что тут "продумывать"? Базовый ф-ционал очевиден
...
Все методы с именем xxxKey или параметром keyIndex - это функционал контейнера (map<Key, Data> data в моём примере выше). Если нужен полный доступ к этим данным, то дублировать функционал контейнера смысла мало. Тем более называть методы иначе, чем они есть в контейнере. Лучше соблюдать требования концептов SequenceContainer (http://en.cppreference.com/w/cpp/concept/SequenceContainer), AssociativeContainer (http://en.cppreference.com/w/cpp/concept/AssociativeContainer) и прочих, которые подходят к поставленной задаче. Это позволит применять к ним стандартные алгоритмы, "range-based for loop" и прочие плюшки современного С++.

В AbstractCurve должны быть методы, в которых кривая проявляет себя как объект (с точки зрения ООП, какой-то предметной области), а не как хранилище данных. Например: printTo(QTextStream &), drawOn(QImage &), applyTo(AbstractCurve &).

Ни о чем больше НЕ спрашивается, есть простой и ясный ф-ционал, давайте не будем менять задачу а подумаем как его обобщить для разных типов данных и сплайнов. Заметим что простейшее использование template, напр
Код
C++ (Qt)
Curve<double>
Curve<Vector>
Curve<Color>
 
Экономит реализацию, но "обобщением" не является, класс Curve должен быть ОДИН (а не куча всего)
С такой постановкой задачи путь решения ведёт к union, variant и тому подобному, от чего Вы хотите уйти. Тем более, что кривая с данными Vector3D и кривая с Color - два разных класса, хоть они внешне и очень похожи. Это как классы коровы и лошади, как QLineEdit и QTextEdit. Почему бы тогда всё многообразие виджетов Qt не засунуть в один класс QWidget?

Одна из причин, по которой не получится шаблонами всё запихнуть в один класс, это то, что виртуальный метод нельзя сделать шаблонным (надеюсь понятно почему). А с желанием хранить множество разных кривых в одном контейнере, вам всё равно придётся отделять коров от лошадей: будь то dynamic_cast, switch(dataType), variant.canConvert и т.п.


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 28, 2017, 07:27
Почему так упорно выставляется требование "ОДИН класс"? Аргумент "поместить в контейнер" правда, но звучит не очень (ну подумаешь, контейнер). Вот гораздо более наглядный пример. Предположим QImage в Qt был бы реализован так
Код
C++ (Qt)
QImage<format_ARGB32>
QImage<format_GrayScale>
... // еще десяток таких
Какой кайф было бы с ним работать! :) Однако почему-то то же самое предлагается для класса Curve...


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 28, 2017, 07:55
- никакой проверки на этапе компиляции, напр если "вектору" попытались назначить "цвет" - придется ловить  это в runtime (понатыкать assert'ов)
Обращаясь к контейнеру разносолов на этапе компиляции ничего не проверить. А выдирая элемент он сам провериться.

Цитировать
- хранится "по максимуму", что вообще-то не есть хорошо
union, ничего лишнего не храниться. Но у меня ошибка, у вас наверное сплайн для каждой кривой одного типа, а я думал что для каждой точки свой тип сплайна.

Чем вам Curve как QList<QVariant> не нравиться? а типы как
Код:
template<typename T> Curve
{ template <typename T>struct Value<T>{T data, in, out; float someOptions[];}
 QMap<double,Value>  }


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 28, 2017, 08:03
Ну и работа с такими структурами мгновенно сваливается в бесконечное свитчевание по dataType. Масса кода дублируетcя т.к. его надо повторять для каждого контейнера x, y, z (a, r, g, b). Напр вместо одной вставки ключа - 3 или даже 4. Это уже просто неграмотно.
второй вариант: замените структуру классом и уберите внутрь логику, у вас уйдет дублирование кода.

p.s. вы бы показали пример кода который работает с данным классом, ну или гипотетический интерфейс (пусть его и сделать на плюсах нельзя, но мы постараемся натянуть на плюсы). А то не очень понятно зачем вам такой хитрый класс и как вы его используете.


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 28, 2017, 09:44
union, ничего лишнего не храниться.
Пример
Код
C++ (Qt)
union {
 double value;
 double coordinate[3];
 float color[4];
};
 
sizeof вернет 24 (макс размер)

Но у меня ошибка, у вас наверное сплайн для каждой кривой одного типа, а я думал что для каждой точки свой тип сплайна.
Тип сплайна сейчас один для всех точек, но в каждой точке сидят свои параметры сплайна (причем разные для разных типов данных)

Чем вам Curve как QList<QVariant> не нравиться? а типы как
Код:
template<typename T> Curve
{ template <typename T>struct Value<T>{T data, in, out; float someOptions[];}
 QMap<double,Value>  }
Опять я вынужден попросить Вас излагать свои мысли менее сумбурно. В первой строке Curve контейнер вариантов, но уже в следующей он шаблонный тип. Как Вас понять?  :)
Код
C++ (Qt)
Зачем, зачем ты торопился?
Зачем свою лошадку гнал?
Али урядника боялся
Али в контору задолжал?
Эта старая (печальная) песня явно о Вас  :)


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 28, 2017, 12:15
Почему так упорно выставляется требование "ОДИН класс"? Аргумент "поместить в контейнер" правда, но звучит не очень (ну подумаешь, контейнер). Вот гораздо более наглядный пример. Предположим QImage в Qt был бы реализован так
Код
C++ (Qt)
QImage<format_ARGB32>
QImage<format_GrayScale>
...
 
Какой кайф было бы с ним работать! :) Однако почему-то то же самое предлагается для класса Curve...

QImage работает с одним типом данных: цветом. Цвет может быть представлен в разных форматах, но важным является то, что они могут конвертироваться между собой и имеют обобщённый тип. Методы QImage оперируют одним конкретным типом QColor, а не множеством ColorInXxxFormat. Если Вы для своих данных найдете такой общий тип и внятные преобразования между ними, то тоже сможете делать так :).

Когда метод QImage возвращает цвет в QColor, то по нему нельзя узнать, в каком формате он хранился в том QImage, и в большинстве случаев это знание и на фиг не нужно. В вашем же случае наверняка захочется узнать, что же вернул какой-нибудь GetNthKeyValue(int keyIndex): координату или цвет? :)


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 29, 2017, 09:10
QImage работает с одним типом данных: цветом. Цвет может быть представлен в разных форматах, но важным является то, что они могут конвертироваться между собой и имеют обобщённый тип. Методы QImage оперируют одним конкретным типом QColor, а не множеством ColorInXxxFormat.
Как Вы гладко говорите :) Но разве можно конвертировать ARGB32 в GrayScale или RGB32? Такое преобразование по меньшей мере неоднозначно. А внутренний формат не волнует только до тех пор пока не случилось QImage::bits. Поэтому каких-то принципиальных различий нет

Если Вы для своих данных найдете такой общий тип и внятные преобразования между ними, то тоже сможете делать так :).
Да хотя бы то что предложил deMax
Цитировать
class UnionData {
public:
    enum DataType { NO,DOUBLE, COLOR, VECTOR3 };
private:
...
    DataType dataType = NO;
public:
    union {double d; Color c; Vector3 v3;};
    bool isDataType(DataType dataType) {return dataType == this->dataType;}

    UnionData() { dataType = NO; }
    UnionData(double d){ dataType = DOUBLE; this->d = d;}
    UnionData(Color c){ dataType = COLOR; this->c = c;}
    UnionData(Vector3 v3){ dataType = VECTOR3; this->v3 = v3;}
};
(здесь наверняка "щелкнет тумблер" типа "велик!", "костыли" - оно ж не "ис каропки"  :)). Зато по сути верно 

В вашем же случае наверняка захочется узнать, что же вернул какой-нибудь GetNthKeyValue(int keyIndex): координату или цвет?
Ну как "наверняка" - хотя неизбежно такие методы будут, но их будет мало. Большинство операций с разношерстными значениями могут быть успешно замкнуты внутри класса Curve. Как и QImage::fill использует внутренний формат, а не обобщенный ARGB32

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


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 29, 2017, 12:59
Может еще в таком направлении покопать, ну или мысли какие полезные возникнут:
Код:
#include <typeinfo>

class Base{
    static const QStringList typeId;
public:
    enum TYPE { NO = -1, INT, STR, DBL } type = NO;

    int getData(double, int &data);
    int getData(double, QString &data);
    int getData(double, double &data);
};

template <typename T> class BaseChild: public Base{
    friend Base;
protected:
    T data;
public:
    BaseChild(T data) : data(data) { type = (TYPE)typeId.indexOf(typeid(data).name()); }
};

const QStringList Base::typeId {"i", "7QString", "d"};
int Base::getData(double, int &data) { if(type == (int)INT) data = static_cast<BaseChild<int>*>(this)->data; }
int Base::getData(double, QString &data) { if(type == (int)STR) data = static_cast<BaseChild<QString>*>(this)->data; }
int Base::getData(double, double &data) { if(type == (int)DBL) data = static_cast<BaseChild<double>*>(this)->data; }

int main(int argc, char *argv[])
{
    QList<Base*> list;

    list << new BaseChild<int>(5);
    list << new BaseChild<QString>("5");
    list << new BaseChild<double>(5);

    for(auto i: list)  qDebug() << i->type;

    int a1;
    QString a2;
    double a3;

    list[0]->getData(1, a1);
    list[1]->getData(1, a2);
    list[2]->getData(1, a3);

    qDebug() << a1 << a2 << a3;

    return 0;
}


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 29, 2017, 13:51
Как Вы гладко говорите :) Но разве можно конвертировать ARGB32 в GrayScale или RGB32? Такое преобразование по меньшей мере неоднозначно. А внутренний формат не волнует только до тех пор пока не случилось QImage::bits. Поэтому каких-то принципиальных различий нет
Ясное дело, что при конвертации между разными форматами могут возникать искажения/потери информации о цвете. Но преобразования выполняются над одни общим типом: цветом. К потерям точности при преобразованиях double <-> float, или даже double <-> int Вы же с пониманием относитесь? В то же самое время для вашего случая, можете предложить адекватное преобразование Color <-> Vector3D?

Ну как "наверняка" - хотя неизбежно такие методы будут, но их будет мало. Большинство операций с разношерстными значениями могут быть успешно замкнуты внутри класса Curve. Как и QImage::fill использует внутренний формат, а не обобщенный ARGB32
То, что замыкается внутри QImage или Curve не так важно, как то, чем они оперируют снаружи (типы параметров публичных методов). QImage оперирует одним QColor. У вас получается {double, Color, Vector3D}. Можно их запихнуть в один variant. При этом ещё появляется switch по этому типу данных, который наверняка не отменяет switch по типу кривой. Оно Вам надо? :) Кроме того, в задаче ещё опции сплайнов фигурируют. Их тоже в union/variant пихать предлагаете?

Да, если класс Curve не шаблонный, то не остается ничего другого как общаться с ним через вариант или его аналог (напр старший, вмещающий тип). Но почему из этого автоматически следует что все должно быть на варианте? Такой вывод, мягко говоря, примитивен. Разве мы не можем сделать "начинку" класса на template?
Шаблоны ничего волшебного не делают. На текущий момент они в основном помогают избегать копипасты кода. Напишите класс Curve, как Вы его представляете, увидите там повторяющийся код, его и можно пытаться в шаблоны засунуть.

И, если нравится всё сваливать в одну кучу, и чтобы не изобретать велосипеды, можете обратить внимание на std::variant (http://en.cppreference.com/w/cpp/utility/variant) и std::any (http://en.cppreference.com/w/cpp/utility/any).


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 29, 2017, 15:28
..можете предложить адекватное преобразование Color <-> Vector3D?
По-моему оно аналогично преобразованию ARGB <-> RGB  (по крайней мере по числу компонент)

Их тоже в union/variant пихать предлагаете?
Да я, вообще-то, от Вас хотел услышать какие-то предложения :) Ну пока не очень..

И, если нравится всё сваливать в одну кучу, и чтобы не изобретать велосипеды, можете обратить внимание на ..
Как будто я вот ну захотел изобрести велосипед - и все тут! :) Но какой у меня выбор? Сидеть дальше с этим калом мамонта? Он уже достало, лезет из всех щелей, а о расширении ф-ционала говорить не приходится.


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 29, 2017, 19:13
Да я, вообще-то, от Вас хотел услышать какие-то предложения :) Ну пока не очень..
Одно из простых "решений в лоб" я предложил здесь (http://www.prog.org.ru/index.php?topic=31554.msg233386#msg233386). Если есть острая необходимость именно в один класс всё запихнуть, то можете поэкспериментировать с таким франкенштейном (требуется С++17):

Код
C++ (Qt)
#include <iostream>
#include <any>
#include <variant>
#include <vector>
#include <array>
#include <chrono>
 
using namespace std;
 
using Vector3D = array<double, 3>;
using Color = array<int, 4>;
using TimePoint = chrono::system_clock::time_point;
 
struct RatioOption
{
   double inRatioVector;
   double outRatioVector;
};
 
struct WeightOption
{
   int inWeight;
   int outWeight;
};
 
struct Curve
{
   using Key = variant<double, TimePoint>;
   using Point = variant<double, Vector3D, Color>;
   using Option = any;
   struct Data
   {
       Key key;
       Point point;
       Option option;
   };
   using Container = vector<Data>;
 
   Container data;
};
 
int main()
{
   Curve curve;
 
   curve.data.push_back( { 1.5, Color{24,32,64,128}, RatioOption{5.4, 8.7} } );
   curve.data.push_back( { TimePoint::clock::now(), Vector3D{1.2, 3.4, 5.6}, WeightOption{2,6} } );
 
   for (const auto & data : curve.data)
   {
       cout << "key = " << data.key // ??
            << "point = " << data.point // ??
            << "option = " << data.option // ??
            << endl;
   }
 
   return 0;
}
 

Как будто я вот ну захотел изобрести велосипед - и все тут! :) Но какой у меня выбор? Сидеть дальше с этим калом мамонта? Он уже достало, лезет из всех щелей, а о расширении ф-ционала говорить не приходится.

Мы с разных сторон к решению задачи подходим. Вы, похоже, заходите со стороны данных, чтобы загнать их в один класс и как-то удобно с ним работать. При этом Вы хотите совместить, грубо говоря, полиморфизм compile-time с полиморфизмом run-time. Но у них разные механизмы реализации и один не может заменить другой. Поэтому то, что хорошо ложится на шаблоны в compile-time, ни фига не работает run-time. Я захожу со стороны кривой как объекта: зачем она вообще нужна, к чему применяется, где/как/кем создаётся/редактируется и т.п. Но это нужно глубоко лезть в кроличью нору :) (и писать много(очень много) классов).


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 30, 2017, 11:48
Я захожу со стороны кривой как объекта: зачем она вообще нужна, к чему применяется, где/как/кем создаётся/редактируется и т.п. Но это нужно глубоко лезть в кроличью нору :) (и писать много(очень много) классов).
Это типовая проблема любой "архитектурной" темы. Разумеется реальные структуры намного сложнее, рассказ о них быстро перегружает слушателей информацией (которую обычно не так уж и легко осознать), ну и быстрый вывод (соскок) "та ну его нафиг во все это вникать - мне бы дай бог в свой проект вникнуть". Поэтому здесь я сознательно даю "по минимуму", по-другому просто не получится. Есть простейший ф-ционал вытекающий из понятия "кривая (график) от времени" - ВСЕ

..зачем она вообще нужна,
Ну а зачем нужен QImage? "Чтобы рисовать". Также и кривая - "чтобы получать значения для заданного времени". Слишком общий ответ? Так и вопрос такой же  :)

Если есть острая необходимость именно в один класс всё запихнуть..
Звучит как будто я хочу ну совсем уж что-то "эдакое" (может даже извращенное) :) По-моему напротив, мои потребности очень банальны. Как только класс становится "достаточно широко используемым" - он не может быть шаблонным, не пролазит тот шаблон во все дырки. Напр "шаблонный QImage" = бред собачий

..то можете поэкспериментировать с таким франкенштейном (требуется С++17):
Набросать структуры на варианте - полчаса максимум, и не так уж важно что использовать (буст, std или Qt). Но дальше-то жопа непролазная. Напр
Код
C++ (Qt)
struct RatioOption
{
   double inRatioVector;
   double outRatioVector;
};
 
так это "как сейчас", для одного типа данных double. Для 3 типов придется написать так
Код
C++ (Qt)
template <T>
struct RatioOption
{
   T inRatioVector;
   T outRatioVector;
};
 
Но это уже 3 разных типа. Итого я имею (3 типа данных) * (6 типов сплайна) = 18 классов. Разрывать их свитчем всякий раз - ну это не выход


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 30, 2017, 12:06
так это "как сейчас", для одного типа данных double. Для 3 типов придется написать так
Код
C++ (Qt)
template <T>
struct RatioOption
{
   T inRatioVector;
   T outRatioVector;
};
 
Но это уже 3 разных типа. Итого я имею (3 типа данных) * (6 типов сплайна) = 18 классов. Разрывать их свитчем всякий раз - ну это не выход
А давайте чуть предметнее, упростим задачу: 2 простых типа(int, double), 2 сплайна(сами приведите попроще из тех что есть) и попробуем набросать код без свитча.
inRatioVector нужен? я просто когда сплайн рисовал, брал N точек вперед и назад из массива и ничего не хранил.

допустим:
Код:
class Spline {
QMap<Time,QVariant> data;
QList<IdData,Qvarint> inData, outData;
Qvariant getData(Time time, SplineType st); //сюда можно вообще callback засунуть например, или разные сплайны будут требовать разные вспомогательные данные
}


Название: Re: Переделать старые структуры
Отправлено: deMax от Август 30, 2017, 12:12
Данные мы засунули в некоторую структуру(уже разобрались), теперь в ней будем хранить указатель на функцию под конкретный сплайн и QList<QVariant> - данные для каждой точки под каждый сплайн.

Код:
Spline{
  QList<UnionData> data;
  QList<UnionSplineData> dataForSpline;
  void(*splineFunction)();
}

естественно нужно определить умножение/сложение... чтобы функция сплайна оперировала с UnionType а не свитч на несколько типов


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 30, 2017, 15:43
Но это уже 3 разных типа. Итого я имею (3 типа данных) * (6 типов сплайна) = 18 классов. Разрывать их свитчем всякий раз - ну это не выход
Хорошо, Вы ссылаетесь на QImage как на образец, который наиболее похож на решение задачи по хранению данных кривых. Да, QImage не шаблонный, но они возможные комбинации параметров шаблона переместили в QImage::Format, который на текущий момент (Qt 5.9) насчитывает 25 позиций и иногда пополняется. Можете сделать аналогично enum Curve::Format{ DateTime_Double, DateTime_Vector3D, DateTime_Color, ..., Key_Point_Option} и свитчевать по этому формату.

Далее про шаблонный template <T> struct RatioOption{}. Вы предполагаете, что там может быть три типа (на самом деле не важно сколько, важно, что больше одного). В Qt повсеместно можно обнаружить перегрузки методов для QPoint/QPointF, QRect/QRectF и т.п. Они не выносят тип в шаблон, они зафиксировали какой-то целочисленный и вещественный типы и дублируют методы для случаев, когда эти типы надо различать. Можете сделать так же RatioOption и RatioOptionF и дублировать методы для них.

Как я говорил раньше, QImage хранит один тип данных: цвет, пусть и в разных форматах. Вы же хотите хранить разные типы данных {double, Vector3D, Color} ещё и отягощенные множеством SplineOption. Поэтому я считаю, что не стоит ориентироваться на QImage. Не надо всё скидывать в одну кучу, а потом героически разгребать её :).

Я бы стремился к такому варианту:
Код
C++ (Qt)
#include <iostream>
#include <vector>
#include <array>
#include <chrono>
#include <memory>
 
using namespace std;
 
using Vector3D = array<double, 3>;
using Color = array<int, 4>;
using TimePoint = chrono::system_clock::time_point;
 
struct EmptyOption
{};
 
template <class T>
struct RatioOption
{
   T inRatioVector;
   T outRatioVector;
};
 
template <class T>
struct WeightOption
{
   T inWeight;
   T outWeight;
};
 
struct AbstractCurve
{
public:
   virtual ~AbstractCurve(){}
 
   virtual void printTo(ostream & stream) const = 0;
};
 
template <class Key, class Point, class Option = EmptyOption>
struct Curve final : public AbstractCurve
{
   struct Data
   {
       Key key;
       Point point;
       Option option;
   };
 
   using Container = vector<Data>;
   Container data;
 
   void printTo(ostream & stream) const override
   {
       stream << "Generic curve [" << endl;
       for (const auto & i : data)
       {
           stream << "    ["
                  << " key = " << i.key
                  << ", point = " << i.point
                  << ", option = " << i.option
                  << " ]" << endl;
       }
       stream << "]" << endl;
   }
};
 
int main()
{
   auto coord_curve = make_unique<Curve<TimePoint, Vector3D>>();
   coord_curve->data.push_back({TimePoint(1s), Vector3D{1.2, 3.4, 5.6}, EmptyOption()});
   coord_curve->data.push_back({TimePoint(2s), {5.6, 3.4, 1.2}, {}});
 
   auto color_curve = make_unique<Curve<double, Color>>();
   color_curve->data.push_back({1.7, Color{1, 2, 3, 4}, {}});
   color_curve->data.push_back({2.5, {5, 6, 7, 8}});
 
   auto coord_ratio_curve = make_unique<Curve<TimePoint, Vector3D, RatioOption<double>>>();
   coord_ratio_curve->data.push_back({TimePoint(1h), {1.2, 3.4, 5.6}, {1.4, 4.1}});
   coord_ratio_curve->data.push_back({TimePoint(2h), {5.6, 3.4, 1.2}, {2.3, 5.7}});
 
   auto color_weight_curve = make_unique<Curve<double, Color, WeightOption<int>>>();
   color_weight_curve->data.push_back({5.8, Color{1, 2, 3, 4}, {1, 2}});
   color_weight_curve->data.push_back({7.2, {5, 6, 7, 8}, {3, 4}});
 
   vector<unique_ptr<AbstractCurve>> curves;
   curves.push_back(move(coord_curve));
   curves.push_back(move(color_curve));
   curves.push_back(move(coord_ratio_curve));
   curves.push_back(move(color_weight_curve));
 
   for (const auto & curve : curves)
       curve->printTo(cout);
 
   return 0;
}
* Полный текст в аттаче, тут убрал перегрузку вывода в поток, чтобы не захлямлять код.

Соответственно нужно стремиться к методам в AbstractCurve, которые не зависят от типов данных кривых: printTo(Stream), saveTo(Storage), loadFrom(Storage), drawIn(QImage), drawBy(QPainter) и т .п. Если требуется редактировать эти кривые в GUI, то для различных типов кривых, я так подозреваю, могут потребоваться разные визуальные редакторы. Для сопоставления кривая <-> редактор, скорей всего, от dynamic_cast или свитча не уйти, се ля ви.

Для сравнения с монолитным Curve (http://www.prog.org.ru/index.php?topic=31554.msg233434#msg233434) можете попробовать туда добавить метод printTo(ostream & stream). И заодно проследить, чтобы в кривую с координатами кто-нибудь цвет не добавил :).


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 31, 2017, 07:24
Я бы стремился к такому варианту:
Понял, шаблонный класс наследует базовый, (нешаблонный и с виртуалами) и дальше пытаемся все сделать на этих виртуалах. Собсно это единственный способ "замкнуть" темплейты внутри класса что я знаю. Знатоки шаблонов, так ли это? Кстати где же вы вообще?  :)

Только почему надо делать это для класса Curve? То же подход но для класса Key мне кажется более логичным. Схема
Код
C++ (Qt)
struct Curve {
...
QVector<Key *> mKeys;  
...
};
 
struct Key {
 ...
 virtual MyVariant GetValue( void );
 virtual void SetValue( const MyVariant & );
 ...
};
 
template <class DataType, class SplineType>
struct CTypedKey : public Key {
...
 virtual MyVariant GetValue( void )  { return mData; }
 virtual void SetValue( const MyVariant & v ) { mData = v; }
...
 DataType mData;
 SplineType mSpline;
};

ViTech, просьба "менее академично".  Время - просто double, делать его тоже шаблонным (так, для примера) не нужно. Использоваться повсеместно будет базовый класс, поэтому ему надо назвать просто и удобно "Curve" (а не тыкать всякий раз в нос "Abstract") и.т.п.

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


Название: Re: Переделать старые структуры
Отправлено: Igors от Август 31, 2017, 07:57
А давайте чуть предметнее, упростим задачу: 2 простых типа(int, double), 2 сплайна(сами приведите попроще из тех что есть) и попробуем набросать код без свитча.
Давайте. Сейчас, для единственного типа double, это выглядит так (все на С, методов нет, только ф-ции)
Код
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);
 
   .....
 }
}
Простейшая интерполяция - линейная, т.е. точки соединены прямой и все. Формально тоже сплайн, параметров нет
Код
C++ (Qt)
double InterpolateLinear( Curve * curve, double t )
{
  Key * key1 = FindUpperKey(curve, t);  // находим первый ключ с временем больше t
  Key * key0 = GetPreviousKey(key1);   // и предыдущий
 
// интерполируем
  double relativeT = (t - key0->keyTime) / (key1->keyTime - key0->keyTime);
  return key0->keyData * (1 - relativeT) + key1->keyData * relativeT;
}
 
Кстати: FindUpperKey соответствует std::upper_bound (а не std::lower_bound). Это имеет значение т.к. ключи с одинаковым временем разрешены.

Ладно, теперь пример сплайна с параметрами.
Код
C++ (Qt)
// спец случай - постоянное значение до след ключа
  if (TestFlag(key0->spline.ratio.flag, BIT_HOLD)) return key0->keyData;
 
// спец случай - линейное значение до след ключа
  if (TestFlag(key0->spline.ratio.flag, BIT_LINEAR)) return ...
 
// интерполируем
  double relativeT = (t - key0->keyTime) / (key1->keyTime - key0->keyTime);
  double k[4];
  CalcCoefficients(t, k);
  return key0->keyData * k[0] +
            key1->keyData * k[1] +
            key0->spline.ratio.outRatioVector * k[2] +
            key1->spline.ratio.inRatioVector * k[3];
 
Параметры in/outRatioVector и флаги могут настраиваться (как юзером так и втихаря) индивидуально для каждого ключа. Другие сплайны могут потребовать больше соседних точек (один вообще все). В общем нет особого смысла в это вдаваться - есть какая-то математика и она работает.

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


Название: Re: Переделать старые структуры
Отправлено: ViTech от Август 31, 2017, 12:27
Поэтому я считаю, что не стоит ориентироваться на QImage.
Я и не собирался что-то из него брать. Просто это хороший пример когда данные разные, но шаблонный класс совершенно неприемлем.
Почему совершенно неприемлем? Можно QImage принять за интерфейс, сделать его методы виртуальными, а классы с конкретными форматами реализовать в шаблонах. И вместо текущего способа создания объекта:
Код
C++ (Qt)
   QImage * image = new QImage(100, 100, QImage::Format_ARGB32);
было бы, например:
Код
C++ (Qt)
   QImage * image = new QFormattedImage<Format_ARGB32>(100, 100);
И теперь прикиньте, если бы Вы захотели расширить QImage каким-то своим форматом, то в каком случае это было бы проще сделать?

Только почему надо делать это для класса Curve? То же подход но для класса Key мне кажется более логичным. Схема
...
Делать можно по-всякому, я же не знаю тонкостей поставленной задачи. В случае с QVector<Key *> в кривой могут оказаться CTypedKey с разными DataType. Это допустимо? Если нет, то как будете это отслеживать?

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


Название: Re: Переделать старые структуры
Отправлено: Igors от Сентябрь 01, 2017, 09:49
Почему совершенно неприемлем? Можно QImage принять за интерфейс, сделать его методы виртуальными, а классы с конкретными форматами реализовать ...
Так я и говорю что нужен именно интерфейс БЕЗ шаблонов :) А в реализации они вполне возможны
 
В случае с QVector<Key *> в кривой могут оказаться CTypedKey с разными DataType. Это допустимо? Если нет, то как будете это отслеживать?
Сделаю конструкторы Key private a Curve friend'ом. Пока перевожу математику сплайнов на template, там тоже не все так уж беоблачно

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


Название: Re: Переделать старые структуры
Отправлено: ViTech от Сентябрь 01, 2017, 13:19
Умеете Вы всё в интересную сторону повернуть :).

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

Далее, в моём примере (http://www.prog.org.ru/index.php?topic=31554.msg233458#msg233458) соблюдается требование "Если юзер создал кривую типа "число" - то он никак не сможет преобразовать ее в тип "вектор" или "цвет", и наоборот." (формулировка которого, кстати, отсутствует в начальном сообщении, а появилась только после уточняющих вопросов) без каких-либо дополнительных действий, а в Вашем примере (http://www.prog.org.ru/index.php?topic=31554.msg233473#msg233473) это требование не соблюдается, если только не прилепить к нему костыли, в качестве которых Вы предлагаете приватные конструкторы и 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);
 
   .....
 }
}
С этим куском что-нибудь пытались делать? Уйти от свитча и перейти к виртуальным методам?


Название: Re: Переделать старые структуры
Отправлено: Igors от Сентябрь 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 (зову из виртуала)

Вообще "интрузивные контейнеры" (насколько помню так называется структура выше) - интересная тема


Название: Re: Переделать старые структуры
Отправлено: Old от Сентябрь 02, 2017, 07:38
Типичное "если бы да кабы" - вот так, с ни хрена, нагрузить код еще одним шаблоном (а вдруг понадобится?). Мягко говоря "заслуживает самого сурового осуждения"  :'( 
Каким шаблоном, это тот же typedef:
Код
C++ (Qt)
typedef double CurveTime;
 


Название: Re: Переделать старые структуры
Отправлено: ViTech от Сентябрь 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.


Название: Re: Переделать старые структуры
Отправлено: Igors от Сентябрь 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 налеплено много - возникают уже серьезные трудности с пониманием написанного. Впрочем это мое личное мнение, моя память хуже средней.


Название: Re: Переделать старые структуры
Отправлено: ViTech от Сентябрь 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 да и всё :).


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

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

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


Название: Re: Переделать старые структуры
Отправлено: ViTech от Сентябрь 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? Там тоже рисуются кривые с разными типами сплайна в отдельных точках.


Название: Re: Переделать старые структуры
Отправлено: Igors от Сентябрь 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-мерную. А уж доставать наружу потроха сплайнов - полная дичь, это глубоко личные подробности кривой. 

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


Название: Re: Переделать старые структуры
Отправлено: ViTech от Сентябрь 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 редактируются кривые.

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


Название: Re: Переделать старые структуры
Отправлено: Old от Сентябрь 05, 2017, 12:25
ViTech, а вы отчаянный. :)


Название: Re: Переделать старые структуры
Отправлено: ViTech от Сентябрь 05, 2017, 12:46
ViTech, а вы отчаянный. :)

А вдруг :).


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

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

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

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


Название: Re: Переделать старые структуры
Отправлено: Bepec от Сентябрь 06, 2017, 11:09
Я прям вижу как Igors разрывает на части, из-за противоречия между "хочу расширяемость" и "не плодите сущностей".


Название: Re: Переделать старые структуры
Отправлено: ViTech от Сентябрь 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, да мало ли ещё откуда появляются.


Название: Re: Переделать старые структуры
Отправлено: Igors от Сентябрь 06, 2017, 13:09
Код
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, то, как говорится: хозяин - барин :). Я же предпочитаю второй вариант.
Второй вариант как раз то о что "разбивают ноги". Кто такой Time? Ах, сейчас просто double, это так, "на будущее". Кто такой PointGenerator? Надо открывать хедер, скорее всего еще и исходник. А там еще куда-то отфутболят. От этого лазания по бесконечному делегированию быстро устаем. Кто мешал сразу делать содержательную часть - хотя бы найти пару точек кривой? ЗАЧЕМ нужна прокладка? Какую "гибкость" мы хотели этим создать ???

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

Но может быть такой сценарий использования, что параметры сплайна используются при интерполяции, загружаются из файла и в программе не редактируются. Может эти ключевые точки формируются во внешнем продвинутом редакторе, снимаются с датчиков motion capture, да мало ли ещё откуда появляются.
Да, и из файлов, и из очень многих других мест (все и не помню). И что? Разве это как-то влияет на структуру данных?


Название: Re: Переделать старые структуры
Отправлено: ViTech от Сентябрь 06, 2017, 14:01
Второй вариант как раз то о что "разбивают ноги". Кто такой Time? Ах, сейчас просто double, это так, "на будущее". Кто такой PointGenerator? Надо открывать хедер, скорее всего еще и исходник. А там еще куда-то отфутболят. От этого лазания по бесконечному делегированию быстро устаем. Кто мешал сразу делать содержательную часть - хотя бы найти пару точек кривой? ЗАЧЕМ нужна прокладка? Какую "гибкость" мы хотели этим создать ???

Исходники не нужны, достаточно заголовка с интерфейсом из чистых виртуальных методов. Если у вас об это "ноги разбивают", тут уже помочь ничем не могу. Равно как и с пониманием "гибкости".

Не считал чего больше, но оба аспекта (интерполяция и редактирование) юзаются очень интенсивно. Только никак не пойму какое отношение это имеет к данной теме:?  :)

Я про то, что это разные варианты использования. И в каждом варианте нужен свой набор способностей от "кривой", которые я разделил в интерфейсах. Нравится всё держать в одном месте - на здоровье :). Из этого сообщения (http://www.prog.org.ru/index.php?topic=31554.msg233614#msg233614) можете начинать читать с CurveGenerator (не обращая внимание на PointGenerator и EditableCurve) и далее про Interpolator. Но там тоже много классов, от которых Вам станет грустно :).

Но может быть такой сценарий использования, что параметры сплайна используются при интерполяции, загружаются из файла и в программе не редактируются. Может эти ключевые точки формируются во внешнем продвинутом редакторе, снимаются с датчиков motion capture, да мало ли ещё откуда появляются.
Да, и из файлов, и из очень многих других мест (все и не помню). И что? Разве это как-то влияет на структуру данных?

Для меня структура данных не так важна, как набор методов, который может измениться в зависимости от того, будет ли "кривая" редактироваться или нет. Но в Вашем случае да, структура данных не изменится.


Название: Re: Переделать старые структуры
Отправлено: deMax от Сентябрь 06, 2017, 16:00
Мне кажеться Igors должен открыть предметную область где он их применяет. А то я уже забыл что нужно сделать и в чем спор двух философов.
Ну и если у автора уже есть решения, зачем искать все возможные решения?


Название: Re: Переделать старые структуры
Отправлено: ViTech от Сентябрь 06, 2017, 18:01
... в чем спор двух философов.

Спор довольно стар как мир: "крупный монолит" vs "мелкие кирпичи" :). Можно из кирпичей что-то причудливое строить, можно из монолита куски выдалбливать, в конечном итоге могут получиться похожие конструкции. Кому что нравится :).


Название: Re: Переделать старые структуры
Отправлено: Bepec от Сентябрь 06, 2017, 19:13
Спор прост - Igors хочет маленький кирпичик с функционалом большого монолита :D


Название: Re: Переделать старые структуры
Отправлено: Igors от Сентябрь 07, 2017, 10:06
Мне кажеться Igors должен открыть предметную область где он их применяет. А то я уже забыл что нужно сделать и в чем спор двух философов.
Все написано в стартовом посте. Попытка углубиться в предметную часть уже была (привел примеры 2 простых сплайнов как Вы просили). Ну, как и следовало ожидать, эффект "больше инфы" нулевой. Согласен, тема себя исчерпала, наша полемика с ViTech ни к чему не ведет, очевидно каждая сторона останется при своем мнении :)

Возможно я создам новую тему где постараюсь по-другому "расставить акценты", надо только хорошо обдумать чтобы не получилось "как всегда" :) Там поговорим