Нужно сделать векторный редактор. Решил попробовать шаблоны в действии. Итак..
Shape предок фигур ShapeLine и ShapeRect. Graphics предок конкретных реализаций графики GraphicsOpenGL и GraphicsGDI. Shape и Graphics являются Abstraction и Implementor соответственно из шаблона Bridge. Реализации не применюятся совместно, просто хочу отделить графику от данных.
Данные фигур находятся в подклассах класса DataShape таких как DataShapeLineGDI, DataShapeRectGDI, DataShapeLineOpenGL, DataShapeRectOpenGL. DataShape является полем Shape. Вроде как данные нельзя хранить в самих фигурах потому как нарушается абстракция и реализация о чем говорилось в паттерне Bridge.
В классах графики при рисовании, например линии координаты и прочее берутся приведением класса DataShape к конкретному классу в данном случае DataShapeLineGDI или DataShapeLineOpenGL. Но приведение говорит о непродуманности архитектуры классов.
Далее. Необходимо производить с фигурами различные действия такие как поворот, размер, перемещение. Получается Shape.Rotate(Angle) {Data.Rotate(Angle)}. Как то некрасиво получается. Подклассы Shape выглядят какимито идиотами а DataShape превращается в монстра вместо того чтобы быть носителем данных.
Да, и еще. Для создания фигур и различных реализаций графики использую шаблон Абстрактная фабрика
Как бы сделать красиво и правильно или забить и так сойдет?
ИМХО делай так:
1. Есть класс абстрактной фигуры Shape с операциями (виртуальными функциями) Draw, Rotate, Scale, etc;
2. От Shape наследуются классы конкретных фигур (Circle, Rectangle и т.д.);
3. Есть класс абстрактного графического контекста Graphics, позволяющий рисовать примитивы a-la DrawCircle, DrawLine, etc;
4. От Graphics наследуются конкретные реализации GraphicsOpenGL и GraphicsGDI;
5. Рулит полиморфизм, руками кастовать ничего не надо.
Дык так все и сделано. Вопрос где хранить данные фигур. Для разных реализаций графики данные могут быть в разных форматах.
А так конечно полиморфизм рулит безказяф
Здравствуйте, maugli71, Вы писали:
M>Дык так все и сделано. Вопрос где хранить данные фигур. Для разных реализаций графики данные могут быть в разных форматах.
Гм, возможно я что-то не так понял... У тебя векторный редактор, так? Какие у вектора могут быть "разные форматы"?!
А данные фигур хранить в самих фигурах (инкапсуляция, понимаешь ли )
Здравствуйте, loki1000, Вы писали:
L>Гм, возможно я что-то не так понял... У тебя векторный редактор, так? Какие у вектора могут быть "разные форматы"?!
Например в GDI структура POINT а в GDIPlus GPPOINT. Кисть LOGBRUSH в GDI в OpenGL подругому. Или в как в Дельфях есть клас TPen. У него свойства Style(TPenStyle) Mode(TPenMode). Понятно что в резудьтате все в GDI превращается но готовые классы удобнее применять. Или координаты хранить при использовании GDI в целочисленном формате а в OpenGL в вещественном. Или ты предлагаешь их привести к какомунибудь общему формату? Небудет ли приведение типов тормозить потом?
L>А данные фигур хранить в самих фигурах (инкапсуляция, понимаешь ли )
Так вот если я в фигуре буду хранить например GPPoint умрет абстракция
Здравствуйте, maugli71, Вы писали:
M>Или ты предлагаешь их привести к какомунибудь общему формату?
Именно! Чем определяется вектор? Набором координат (парой/тройкой float`ов). Вот их и используй. А API`шные структуры спрячь внутри реализации.
M>Небудет ли приведение типов тормозить потом?
"premature optimization is a root of all evel in programming" (c)
ЗЫ: есть такой принцип: "отделение данных от представления"...
Re[6]: Ну ты и намудрил... :)
От:
Аноним
Дата:
13.07.05 15:06
Оценка:
Здравствуйте, loki1000, Вы писали:
M>>Или ты предлагаешь их привести к какомунибудь общему формату?
L>Именно! Чем определяется вектор? Набором координат (парой/тройкой float`ов). Вот их и используй. А API`шные структуры спрячь внутри реализации.
С координатами уговорил А как быть с цветами и атрибутами пера, кисти? Их тоже к общему?
L>ЗЫ: есть такой принцип: "отделение данных от представления"...
Компьютерная графика замечательно попадает в оставшиеся 3%
L>ЗЫ: есть такой принцип: "отделение данных от представления"...
В данном случае он не подходит. Данные тут напрямую связаны с представлением. Если кривая безье по разному рисуется на OpenGL и GDI и DirectX, то от отделения данных от представления хорошо никому не станет.
Я бы посоветовал изначально жёско завязатся на OpenGL, потому что OpenGL это, в отличие от многих других библиотек, стандартизированная отрисовка.
OpenGL, в отличие от многих других библиотек, доступна на практически всех мыслимых платформах
Многие векторные форматы файлов создавались с расчётом на отрисовку с помошью OpenGL
Здравствуйте, adontz, Вы писали:
L>>ЗЫ: есть такой принцип: "отделение данных от представления"...
A>В данном случае он не подходит. Данные тут напрямую связаны с представлением. Если кривая безье по разному рисуется на OpenGL и GDI и DirectX, то от отделения данных от представления хорошо никому не станет.
Если я правильно понял то так как данные напрямую связаны с представлением я хочу сделать так чтобы данные были специфичны для различных график, но при этом сам объект, скажем Bezier был абстрактен. Говоря по-русски у меня есть абстрактный класс Shape от которого порождаются конкретные фигуры. В Shape включено поле типа ShapeData которое в свою очередь является прародителем для данных конкретных фигур, таких как DataLineGDI, DataLineOGL, DataLineGDIPlus и т.д. В них хранятся данные специфичные для график. Ведь помимо координат, которые для всех график можно представить ввиде float есть скажем стиль пера которые представлен различно в разных графиках и при каждом выводе фигуры преобразовывать из общего формата к частному как то кривовато с моей точки зрения.
A> OpenGL это, в отличие от многих других библиотек, стандартизированная отрисовка.
Являюсь новичком в графике. Что означает "стандартизированная"? GDI разве нестандартизирована?
A> OpenGL, в отличие от многих других библиотек, доступна на практически всех мыслимых платформах
Уверен что в моем случае хватит только платформ MS
maugli71 wrote:
> A>В данном случае он не подходит. Данные тут напрямую связаны с > представлением. Если кривая безье по разному рисуется на OpenGL и GDI > и DirectX, то от отделения данных от представления хорошо никому не > станет. > Если я правильно понял то так как данные напрямую связаны с > представлением я хочу сделать так чтобы данные были специфичны для > различных график, но при этом сам объект, скажем Bezier был > абстрактен. Говоря по-русски у меня есть абстрактный класс Shape от > которого порождаются конкретные фигуры. В Shape включено поле типа > ShapeData которое в свою очередь является прародителем для данных > конкретных фигур, таких как DataLineGDI, DataLineOGL, DataLineGDIPlus > и т.д.
А вот это лучше убрать из абстрактного интерфейса фигуры. Например если
захочется одну и ту же линию нарисовать на GDI и в контекст OGL. Что
тогда делать?
> В них хранятся данные специфичные для график. Ведь помимо координат, > которые для всех график можно представить ввиде float есть скажем > стиль пера которые представлен различно в разных графиках и при каждом > выводе фигуры преобразовывать из общего формата к частному как то > кривовато с моей точки зрения.
Значит при рисовании его надо хранить параллельно с фигурой.
> # A> OpenGL это, в отличие от многих других библиотек, > стандартизированная отрисовка. > Являюсь новичком в графике. Что означает "стандартизированная"? GDI > разве нестандартизирована?
На OGL есть открытый стандарт от SGI с несколькими реализациями.
Стандарта на GDI нет.
Здравствуйте, Cyberax, Вы писали:
C>А вот это лучше убрать из абстрактного интерфейса фигуры. Например если C>захочется одну и ту же линию нарисовать на GDI и в контекст OGL. Что C>тогда делать?
В абстрактном Shape ссылка на абстрактный же ShapeData. Что в этом не так? Одну и ту же линию я не собираюсь рисовать в разных графиках одновременно. У меня есть разые типа график не для одновременного их применения а для того чтобы разобравшись с ними и выбрав какуюнибудь одну я на ней и остановился. Или я не правильно чего понял?
>> В них хранятся данные специфичные для график. Ведь помимо координат, >> которые для всех график можно представить ввиде float есть скажем >> стиль пера которые представлен различно в разных графиках и при каждом >> выводе фигуры преобразовывать из общего формата к частному как то >> кривовато с моей точки зрения.
C>Значит при рисовании его надо хранить параллельно с фигурой.
Кого его? Данные? Или стиль пера? Стиль пера один из атрибутов данных. Данные являются полем Shape.
C>На OGL есть открытый стандарт от SGI с несколькими реализациями. C>Стандарта на GDI нет.
maugli71 wrote:
> C>А вот это лучше убрать из абстрактного интерфейса фигуры. Например если > C>захочется одну и ту же линию нарисовать на GDI и в контекст OGL. Что > C>тогда делать? > В абстрактном Shape ссылка на абстрактный же ShapeData. Что в этом не > так?
В одну сущность объединили геометрические данные фигуры и низкоуровные
данные для рендеринга.
> Одну и ту же линию я не собираюсь рисовать в разных графиках одновременно.
А вдруг потом захочется? Например сделать сложную сетку и наложить ее на
два графика.
> C>Значит при рисовании его надо хранить параллельно с фигурой. > Кого его? Данные? Или стиль пера? Стиль пера один из атрибутов данных. > Данные являются полем Shape.
Да, создать отдельно объект типа Pen и хранить его. Рисование будет
выглядеть примерно так:
Здравствуйте, Cyberax, Вы писали:
C>В одну сущность объединили геометрические данные фигуры и низкоуровные C>данные для рендеринга.
Сразу прошу прощения за тупость Слишком новые для меня вопросы графики.
"геометрические данные фигуры" есть координаты?
"низкоуровные данные для рендеринга" есть перо?
И все это хозяйство нужно держать порознь?
C>Да, создать отдельно объект типа Pen и хранить его. Рисование будет C>выглядеть примерно так: C>
Здравствуйте, maugli71, Вы писали:
A>>В данном случае он не подходит. Данные тут напрямую связаны с представлением. Если кривая безье по разному рисуется на OpenGL и GDI и DirectX, то от отделения данных от представления хорошо никому не станет.
M>Ведь помимо координат, которые для всех график можно представить ввиде float есть скажем стиль пера которые представлен различно в разных графиках и при каждом выводе фигуры преобразовывать из общего формата к частному как то кривовато с моей точки зрения.
При рисовании преобразовывать не надо, надо (если только действительно надо) преобразовывать при чтении и записи файла, созраняя при этом исходные данные.
M>Являюсь новичком в графике. Что означает "стандартизированная"? GDI разве нестандартизирована?
Это значит что один и тот же код гарантированно отрисует одно и тоже на разных машинах.
Здравствуйте, adontz, Вы писали:
M>>Ведь помимо координат, которые для всех график можно представить ввиде float есть скажем стиль пера которые представлен различно в разных графиках и при каждом выводе фигуры преобразовывать из общего формата к частному как то кривовато с моей точки зрения.
A>При рисовании преобразовывать не надо, надо (если только действительно надо) преобразовывать при чтении и записи файла, созраняя при этом исходные данные.
Есть абстрактный класс Graphics. От него порождаются GraphicsOGL и GraphicsGDI.
Имеется абстрактный метод Graphics.DrawLine(Data) перекрываемый в дочерних классах. Data это абстрактный класс. От него LineData и т.д. Как неприводить класс Data в методе DrawLine? Что то я совсем запутался..
Здравствуйте, maugli71, Вы писали:
M>Есть абстрактный класс Graphics. От него порождаются GraphicsOGL и GraphicsGDI. M>Имеется абстрактный метод Graphics.DrawLine(Data) перекрываемый в дочерних классах. Data это абстрактный класс. От него LineData и т.д. Как неприводить класс Data в методе DrawLine? Что то я совсем запутался..
Потому что архитектура неправильная. (все голые указатели надо потом заменить на умные)
Есть класс line вида
struct point
{
float x;
float y;
}
struct line
{
point from;
point to;
float width;
int pattern_mask;
int pattern_length;
}
он то и хранится в файле.
Есть класс visual_object_base вида
class visual_object_base
{
public:
virtual ~visual_object_base()
{
}
}
всё что можно отрисовать наследуется от него.
Есть класс draw_manager вида
class draw_manager
{
public:
visual_object_base * get_visual_object_from_object(const line & obj);
void draw(visual_object_base * obj);
}
используется всё это хозяство как-то так
line l;
my_file >> line;
visual_object_base * vo = draw_manager.get_visual_object_from_object(line);
draw_manager.draw(vo);
если требуется интерактивность (например, схватить и перетащить линию) то в класс draw_namager надо будет добавить методы вроде
Огромное спасибо за столь расширенный ответ. Но у меня несколько другое видение архитектуры которую пока не вижу смысла переделывать. Чем например хуже объект который может сам себя записать/считать в поток/файл, прорисоваться используя определенную реализацию графики и наконец реализует метод типа PtInObject для перетаскиваний? Не могу я так быстро поменять свою точку зрения )))
Еще раз спасибо за ответ.
Здравствуйте, maugli71, Вы писали:
M>Чем например хуже объект который может сам себя записать/считать в поток/файл, прорисоваться используя определенную реализацию графики и наконец реализует метод типа PtInObject для перетаскиваний? Не могу я так быстро поменять свою точку зрения )))
Ничем. Просто есть такое понятие — инкапсуляция. Всё что тебе не нужно — тебе не должно быть видно.
В принципе объекты унаследованные от visual_object_base вполне могут реализовывать методы draw и is_point_in_object, но только чтобы пользоватся этими объектами совершенно не объязательно о них знать. и объект line тоже может реализовывать методы read(istream &) write (ostream &), но они не нужны visual_object.
Я просто отделил данные от представления. Код в конечном итоге станет чище.
Подумай сам, если графика векторная, то рано или поздно ты столкнёшься с группой объектов. Для группы is_point_in_object это логическое или над вызовами is_point_in_object для каждого члена группы. Всю эту логику вполне можно скрыть в draw_manager.is_point_in_object который сам разберётся object это группа или простой объект или ещё что-то, а не вываливать её наружу.
Здравствуйте, adontz, Вы писали:
A>В принципе объекты унаследованные от visual_object_base вполне могут реализовывать методы draw и is_point_in_object, но только чтобы пользоватся этими объектами совершенно не объязательно о них знать. и объект line тоже может реализовывать методы read(istream &) write (ostream &), но они не нужны visual_object. A>Я просто отделил данные от представления. Код в конечном итоге станет чище.
Тут я вобщем то согласен, буду курить.. думать.. ))
A>Подумай сам, если графика векторная, то рано или поздно ты столкнёшься с группой объектов. Для группы is_point_in_object это логическое или над вызовами is_point_in_object для каждого члена группы. Всю эту логику вполне можно скрыть в draw_manager.is_point_in_object который сам разберётся object это группа или простой объект или ещё что-то, а не вываливать её наружу.
Ну все правильно. Есть объект Symbol подкласс Shape. В его методе PtInObject происходит обращение к методам PtInObject объектов его состовляющих. Что я тут вывалил наружу не пойму? Если возможно — ногами не бить ))