Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>1) точками отрезков прямых линий; КЛ>2) точками кривых Безье 3-го порядка; КЛ>3) точками arc'ов.
КЛ>Собственно, мы ничего нового не придумываем. В языке векторной графики PostScript уже давно выделены эти 3 примитива, и с помощью них представляется любая картинка.
вот эти три класса и должны быть в иерархии классов
Кирилл Лебедев wrote: > G>есть одно небольшое препятствие. для круга m_Points.size() будет > стремится к бесконечности. > Вовсе нет. Коллега сказал, что максимальное количество точек для круга — > 3600. Но и это можно оптимизировать. Круг и эллипс легко представляются > с помощью 4-х кривых Безье 3-го порядка. Для задания каждой такой кривой > необходимы 4 точки. Соответственно, для 4-х состыкованных кривых, > представляющих круг, нужно всего 12 (!) точек.
Но тогда у вас фигуры будут выглядеть так:
То есть даже в прямоугольнике будут ненужные описания кривых.
Далее, рисование окружности/эллипса происходит в десятки раз быстрее,
чем рисование кривых Безье. А значит для нормальной скорости нам нужно
добавить в фигуру еще и набор эллипсов:
А ведь в фигуре еще может содержаться текст! Или фигура может состоять
из композиции нескольких фигур.
> Собственно, мы ничего нового не придумываем. В языке векторной графики > PostScript уже давно выделены эти 3 примитива, и с помощью них > представляется любая картинка.
А к чему усложнять? Любая реальная фигура представима в виде набора
окружностей достаточно маленького радиуса.
Нам ведь кроме представления еще нужно и уметь осмысленно манипулировать
фигурами.
Например, как в вашем случае будет выглядеть изменение радиуса окружности?
Кирилл Лебедев wrote: > A>И что с того? Оверхед в 114 виртуальных таблиц? > A>И самое главное: что это доказывает? > Дело не в 114 виртуальных таблицах, а в трудоемкости создания и > сопровождения 114 классов фигур. Это бессмысленно тем более, что можно > обойтись всего *одним (1!)* классом.
Ага, одним классом с баааальшим switch'ем.
> Принципиальная ошибочность доказывается очень просто: с увеличением > разнообразия фигур и операций по их преобразованию "стройная" иерархия > классов в стиле подхода *"по классу на фигуру"* просто разлетается.
Почему? Преобразования замечательно делаются в таком подходе — мы просто
выделяем трансформаторы в отдельную иерархию.
> Жаль, если это *Вам* непонятно. Возможно, *Вам* имеет смысл > посопровождать ряд графических редакторов, написанных в стиле "по классу > на фигуру" и, так сказать, воочию убедиться в ошибочности данного подхода.
Кхм. Именно сейчас это и делаю — ошибочности подхода пока не вижу.
У меня сделано так:
1. Базовый класс (точнее интерфейс) IWidget имеет методы для проверки
попадания, передвижения, вращения и описания регионов (то есть областей,
которые объект может закрывать) объекта.
2. У IWidget'а есть наследники IConnectorWidget, ITextWidget...
3. Есть специальный интерфейс ICompositeWidget, позволяющий задавать
виджеты, состоящие из нескольких дочерних виджетов.
4. Есть конкретные потомки ICustomDrawWidget (с потомком IActiveXWidget)
и т.п.
Для трансформации используется механизм FOURCC (Four-Character Code) —
каждый виджет экспортирует набор FOURCC в которые он может превращаться,
и у каждого типа виджетов есть свой FOURCC. Если мне нужно преобразовать
один тип в другой — то трансформатор просто смотрит можно ли построить
цепочку преобразований из одного FOURCC в другой.
Здравствуйте, genre, Вы писали:
G>вот эти три класса и должны быть в иерархии классов
Возможно. А зачем их (отрезок, кривую и дугу) представлять в виде классов?
Код рисования фигуры на устройстве будет выглядеть так:
size_t i = 0;
while (i < m_Points.size())
{
switch (m_Flags[i])
{
case PF_MOVE:
dc.MoveTo(m_Points[i]);
i++;
break;
case PF_LINE:
dc.LineTo(m_Points[i]);
i++;
break;
case PF_CURVE:
ASSERT((i + 2) < m_Points.size());
dc.CurveTo(m_Points[i], m_Points[i + 1], m_Points[i + 2]);
i += 3;
break;
}
}
C>То есть даже в прямоугольнике будут ненужные описания кривых.
Как видите, не будет.
C>Далее, рисование окружности/эллипса происходит в десятки раз быстрее, C>чем рисование кривых Безье. А значит для нормальной скорости нам нужно C>добавить в фигуру еще и набор эллипсов:
Глифы TrueType и Type1 шрифтов представляют собой комбинацию отрезков прямых линий и кривых Безье. Как видите, выводятся нормально — не тормозят.
Алгоритм же рисования повернутого эллипса, который я вычитал в одной из "умных" книжек, настолько непростой и глючный, что — ей богу — проще использовать кривые Безье. Собственно говоря, профессиональные пакеты для создания векторной графики так и поступают. То же Corel Draw.
C>А ведь в фигуре еще может содержаться текст! Или фигура может состоять C>из композиции нескольких фигур.
Я не случайно обратил Ваше внимание на язык PostScript. Там эта проблема уже решена.
C>Например, как в вашем случае будет выглядеть изменение радиуса окружности?
Очень просто. Я пересчитаю точки фигуры точно так же, как если бы это был полигон.
Здравствуйте, Cyberax, Вы писали:
C>Ага, одним классом с баааальшим switch'ем.
Откуда Вы взяли огромный switch?
C>Почему? Преобразования замечательно делаются в таком подходе — мы просто C>выделяем трансформаторы в отдельную иерархию.
Я говорил о двух вещах:
1) О том, что иерархия начинает разрастаться, и ее трудно сопровождать. Согласитесь, 115 классов — это уже перебор.
2) О том, что фигуры становится трудно трансформировать. Как пример, Вам нужно сделать скос эллипса или прямоугольника. Если Вы задаете эллипс при помощи rect'а (левая верхняя и правая нижняя точки), то скос без создания новой фигуры (например, полигона) Вам будет сделать сложно.
C>Кхм. Именно сейчас это и делаю — ошибочности подхода пока не вижу.
Вам приходится:
1) писать класс для каждой фигуры;
2) писать иерархию классов для преобразования фигур.
На мой взгляд, это трудоемко да и не нужно. Понятно, что у Вас может быть другое мнение.
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Здравствуйте, genre, Вы писали:
G>>вот эти три класса и должны быть в иерархии классов КЛ>Возможно. А зачем их (отрезок, кривую и дугу) представлять в виде классов?
а что б switch-ей не писать на каждый чих.
C>>Кхм. Именно сейчас это и делаю — ошибочности подхода пока не вижу. КЛ>Вам приходится: КЛ>1) писать класс для каждой фигуры; КЛ>2) писать иерархию классов для преобразования фигур.
КЛ>На мой взгляд, это трудоемко да и не нужно. Понятно, что у Вас может быть другое мнение.
Выскажу свое мнение. В один класс все запихивать действительно не надо.
И Делать развесистую иерархию тоже не стоит.
Надо разделить действительно разные сущности, например полигоны, и кривые безье. у иж из них делать иерархию, в итоге она получится маленькая и по делу.
А еще лучше как-то так(упрощенно):
class Element{
virtual void Draw()=0;
}
class Polygon:public Draw{
...
}
class Figure{
...
std::vector<Element*> elements;
}
вот собственно Figure и будет самой фигурой, которая агрегирует в себе различные элементы.
но вообще все сильно зависит от задачи.
требования эффективности могут накладывать свои ограничения.
Здравствуйте, genre, Вы писали:
G>Надо разделить действительно разные сущности, например полигоны, и кривые безье.
Можно спросить: почему Вы решили, что полигоны и кривые Безье — это разные сущности? (Вопрос серьезный.)
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Здравствуйте, SleepyDrago, Вы писали:
SD>>Было бы интересно увидеть развитие ваших идей до интерфейса исходя из базового примера фигур круг/квадрат и 2х устройств просмотра. КЛ>Как ни странно, круг и квадрат — это не две разных фигуры, а одна. Т.е. иерархия классов в стиле: КЛ>
КЛ>// Базовый класс фигуры.
КЛ>class TFigure {...};
КЛ>// Круг.
КЛ>class TCircle : public TFigure {...};
КЛ>// Квадрат.
КЛ>class TQuadrate : public TFigure {...};
КЛ>
КЛ>- принципиально ошибочна.
Я понял причину Вашего спора — если поглядеть на название данного форума, то Вы находитесь по разные стороны от "/"
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Здравствуйте, genre, Вы писали:
G>>а что б switch-ей не писать на каждый чих. КЛ>Какие конкретно switches Вы хотите убрать этой иерархией? Re[13]: Параллельная иерархия классов
Здравствуйте, Кирилл Лебедев, Вы писали:
КЛ>Здравствуйте, genre, Вы писали:
G>>Надо разделить действительно разные сущности, например полигоны, и кривые безье. КЛ>Можно спросить: почему Вы решили, что полигоны и кривые Безье — это разные сущности? (Вопрос серьезный.)
да я не решал
в каком-то из сообщений треда так было разделено я и написал что в голову первое пришло.
Кирилл Лебедев wrote: > Код рисования фигуры на устройстве будет выглядеть так:
Вы прямо цитируете пример из учебника как НЕ надо писать код и для чего
был придуман полиморфизм. Вы это специально?
> C>Далее, рисование окружности/эллипса происходит в десятки раз быстрее, > C>чем рисование кривых Безье. А значит для нормальной скорости нам нужно > C>добавить в фигуру еще и набор эллипсов: > Глифы TrueType и Type1 шрифтов представляют собой комбинацию отрезков > прямых линий и кривых Безье. Как видите, выводятся нормально — не тормозят.
Простите, я знаю что говорю. Тот же GDI рисует окружности _намного_
быстрее кривых Безье. Хотя бы из-за того, что не всегда нормально
работает аппаратное ускорение для кривых Безье.
> Алгоритм же рисования повернутого эллипса, который я вычитал в одной из > "умных" книжек, настолько непростой и глючный, что — ей богу — проще > использовать кривые Безье. Собственно говоря, профессиональные пакеты > для создания векторной графики так и поступают. То же Corel Draw.
Вы знаете внутренности CD?
> C>А ведь в фигуре еще может содержаться текст! Или фигура может состоять > C>из композиции нескольких фигур. > Я не случайно обратил Ваше внимание на язык PostScript. Там эта проблема > уже решена.
Еще раз. PS, PDF, bitmap — это конечные _представления_. Они не
предоставляют нормальной поддержки для манипуляции объектами.
> C>Например, как в вашем случае будет выглядеть изменение радиуса окружности? > Очень просто. Я пересчитаю точки фигуры точно так же, как если бы это > был полигон.
_КАК_ вы определите какие точки принадлежат окружности?
Кирилл Лебедев wrote: > C>Ага, одним классом с баааальшим switch'ем. > Откуда Вы взяли огромный switch?
Смотрите свое другое письмо
> C>Почему? Преобразования замечательно делаются в таком подходе — мы просто > C>выделяем трансформаторы в отдельную иерархию. > Я говорил о двух вещах: > 1) О том, что иерархия начинает разрастаться, и ее трудно сопровождать. > Согласитесь, 115 классов — это уже перебор.
Всего 115 классов? Какая мелочь, у меня их за тысячу перевалило.
Вы лучше подумайте как вы метод 'Draw' со switch'ем в 115 case'ов
сопровождать будете.
> 2) О том, что фигуры становится трудно трансформировать. Как пример, Вам > нужно сделать скос эллипса или прямоугольника.
Заданием матрицы отображения. При этом координаты точек модели не
меняются, а просто изменяется метод их перевода в глобальные координаты.
Именно так и работают все нормальные рисовальные системы, кстати.
GDI, кстати, это прямо поддерживает — смотрите метод SetWorldTransform.
> C>Кхм. Именно сейчас это и делаю — ошибочности подхода пока не вижу. > Вам приходится: > 1) писать класс для каждой фигуры;
Да.
> 2) писать иерархию классов для преобразования фигур. > На мой взгляд, это *трудоемко* да и *не нужно*. Понятно, что у Вас может > быть другое мнение.
Расскажите как это сделать правильно и проще. Я не вижу более простого
способа.
Кирилл Лебедев wrote: > G>Надо разделить действительно *разные* сущности, например полигоны, и > кривые безье. > Можно спросить: почему Вы решили, что полигоны и кривые Безье — это > *разные сущности*? (Вопрос серьезный.)
Кривые поддерживают принципиально больше возможностей управления. И при
этом принципиально медленнее рисуются.
1) Кроме иерархии классов существуют еще и другие способы устранения свитчей. Вы уверены, что именно этот свитч нужно устранять именно иерархией классов?
2) Вы уверены, что этот свитч нужно вообще устранять? Его размер ограничен, и он никогда не разрастется.
А>1) Кроме иерархии классов существуют еще и другие способы устранения свитчей. Вы уверены, что именно этот свитч нужно устранять именно иерархией классов?
ну так предложите свой способ. А>2) Вы уверены, что этот свитч нужно вообще устранять? Его размер ограничен, и он никогда не разрастется.
его размер зависит от очень большого количества параметров.
вполне может быть что и тремя классами ограничится не получится, отличия же могут быть не только по типу фигуры.
Здравствуйте, Cyberax, Вы писали:
C>Вы прямо цитируете пример из учебника как НЕ надо писать код и для чего C>был придуман полиморфизм. Вы это специально?
Полиморфизм — лишь один из инструментов организации кода, который в ряде случаев не только не полезен, но и вреден. Где-то выгоднее использовать иерархию и виртуальные функции, где-то — массив и указатели, где-то — перечисление, где-то — union, где-то — просто структуру.
Сожаления о том, что там не используется полиморфизм, эмоционально понятны, но профессионально "не прокатывают".
C>Простите, я знаю что говорю. Тот же GDI рисует окружности _намного_ C>быстрее кривых Безье. Хотя бы из-за того, что не всегда нормально C>работает аппаратное ускорение для кривых Безье.
И что с того? К чему нам такое ускорение, если оно нам не нужно? Повторюсь, глифы TrueType и Type1 шрифтов используют кривые Безье.
C>Вы знаете внутренности CD?
Мне приходилось проводить research на тему того, как лучше организовать классы фигур для редактора векторной графики.
C>Еще раз. PS, PDF, bitmap — это конечные _представления_. Они не C>предоставляют нормальной поддержки для манипуляции объектами.
1) Bitmap упомянули Вы, а не я.
2) Что касается PS и PDF, то тут Вы ошибаетесь.
В любом случае, приведите конкретные примеры, чтобы было понятно, о чем речь.
C>_КАК_ вы определите какие точки принадлежат окружности?
Преобразую в полигон и проверю.
Здравствуйте, Аноним, Вы писали:
А>1) Кроме иерархии классов существуют еще и другие способы устранения свитчей. Вы уверены, что именно этот свитч нужно устранять именно иерархией классов?
Перечислите эти способы, пожалуйста, с объяснениями чем оно принципиально отличается.
Вместо полиморфизма, конечно, можно использовать объект с кучей делегатов, например. Или аналогичные извращения — смысл от этого не изменится, так как все равно останется точки использования полиморфного поведения.
А>2) Вы уверены, что этот свитч нужно вообще устранять? Его размер ограничен, и он никогда не разрастется.
Во-первых, кроме этого свитча будет еще с десяток подобных (в других методах). Во-вторых, этот свитч очень даже разрастется.
У меня моим первым детским проектом был растровый редактор на Бейсике (QuickBasic'е, а не на VisualBasic!), потом этот растровый редактор стал векторным и там был как раз такой свитч. При размере редактора в 140Кб кода на Бейсике поддерживать основную функцию рисования стало невозможно У меня там в итоге даже свой рендерер шрифтов был (шрифты сам рисовал с помощью "черепашьей графики").