Не намудрил ли я с проектированием?:)
От: maugli71 Россия  
Дата: 13.07.05 06:59
Оценка:
Нужно сделать векторный редактор. Решил попробовать шаблоны в действии. Итак..

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 превращается в монстра вместо того чтобы быть носителем данных.

Да, и еще. Для создания фигур и различных реализаций графики использую шаблон Абстрактная фабрика

Как бы сделать красиво и правильно или забить и так сойдет?
Удачной охоты..
Re: Ну ты и намудрил... :)
От: loki1000 Украина  
Дата: 13.07.05 09:36
Оценка:
Здравствуйте, maugli71, Вы писали:

ИМХО делай так:
1. Есть класс абстрактной фигуры Shape с операциями (виртуальными функциями) Draw, Rotate, Scale, etc;
2. От Shape наследуются классы конкретных фигур (Circle, Rectangle и т.д.);
3. Есть класс абстрактного графического контекста Graphics, позволяющий рисовать примитивы a-la DrawCircle, DrawLine, etc;
4. От Graphics наследуются конкретные реализации GraphicsOpenGL и GraphicsGDI;
5. Рулит полиморфизм, руками кастовать ничего не надо.


ЗЫ: надеюсь, понятно объяснил...
Re[2]: Ну ты и намудрил... :)
От: maugli71 Россия  
Дата: 13.07.05 09:47
Оценка:
Здравствуйте, loki1000, Вы писали:

Дык так все и сделано. Вопрос где хранить данные фигур. Для разных реализаций графики данные могут быть в разных форматах.
А так конечно полиморфизм рулит безказяф
Удачной охоты..
Re[3]: Ну ты и намудрил... :)
От: loki1000 Украина  
Дата: 13.07.05 11:32
Оценка:
Здравствуйте, maugli71, Вы писали:

M>Дык так все и сделано. Вопрос где хранить данные фигур. Для разных реализаций графики данные могут быть в разных форматах.


Гм, возможно я что-то не так понял... У тебя векторный редактор, так? Какие у вектора могут быть "разные форматы"?!
А данные фигур хранить в самих фигурах (инкапсуляция, понимаешь ли )
Re[4]: Ну ты и намудрил... :)
От: maugli71 Россия  
Дата: 13.07.05 11:49
Оценка:
Здравствуйте, loki1000, Вы писали:

L>Гм, возможно я что-то не так понял... У тебя векторный редактор, так? Какие у вектора могут быть "разные форматы"?!


Например в GDI структура POINT а в GDIPlus GPPOINT. Кисть LOGBRUSH в GDI в OpenGL подругому. Или в как в Дельфях есть клас TPen. У него свойства Style(TPenStyle) Mode(TPenMode). Понятно что в резудьтате все в GDI превращается но готовые классы удобнее применять. Или координаты хранить при использовании GDI в целочисленном формате а в OpenGL в вещественном. Или ты предлагаешь их привести к какомунибудь общему формату? Небудет ли приведение типов тормозить потом?

L>А данные фигур хранить в самих фигурах (инкапсуляция, понимаешь ли )


Так вот если я в фигуре буду хранить например GPPoint умрет абстракция
Удачной охоты..
Re[5]: Ну ты и намудрил... :)
От: loki1000 Украина  
Дата: 13.07.05 13:57
Оценка:
Здравствуйте, 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>ЗЫ: есть такой принцип: "отделение данных от представления"...


Чего и добиваюсь Спасибо за ответы
Re[6]: Ну ты и намудрил... :)
От: adontz Грузия http://adontz.wordpress.com/
Дата: 18.07.05 20:15
Оценка:
Здравствуйте, loki1000, Вы писали:

L>"premature optimization is a root of all evel in programming" (c)


Полная цитата "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." © Дональд Кнут или Роберт Флойд (уже никто не помнит, кто именно)

Компьютерная графика замечательно попадает в оставшиеся 3%

L>ЗЫ: есть такой принцип: "отделение данных от представления"...


В данном случае он не подходит. Данные тут напрямую связаны с представлением. Если кривая безье по разному рисуется на OpenGL и GDI и DirectX, то от отделения данных от представления хорошо никому не станет.
Я бы посоветовал изначально жёско завязатся на OpenGL, потому что
  1. OpenGL это, в отличие от многих других библиотек, стандартизированная отрисовка.
  2. OpenGL, в отличие от многих других библиотек, доступна на практически всех мыслимых платформах
  3. Многие векторные форматы файлов создавались с расчётом на отрисовку с помошью OpenGL
A journey of a thousand miles must begin with a single step © Lau Tsu
Re[7]: Ну ты и намудрил... :)
От: maugli71 Россия  
Дата: 19.07.05 05:57
Оценка:
Здравствуйте, adontz, Вы писали:

L>>ЗЫ: есть такой принцип: "отделение данных от представления"...


A>В данном случае он не подходит. Данные тут напрямую связаны с представлением. Если кривая безье по разному рисуется на OpenGL и GDI и DirectX, то от отделения данных от представления хорошо никому не станет.


Если я правильно понял то так как данные напрямую связаны с представлением я хочу сделать так чтобы данные были специфичны для различных график, но при этом сам объект, скажем Bezier был абстрактен. Говоря по-русски у меня есть абстрактный класс Shape от которого порождаются конкретные фигуры. В Shape включено поле типа ShapeData которое в свою очередь является прародителем для данных конкретных фигур, таких как DataLineGDI, DataLineOGL, DataLineGDIPlus и т.д. В них хранятся данные специфичные для график. Ведь помимо координат, которые для всех график можно представить ввиде float есть скажем стиль пера которые представлен различно в разных графиках и при каждом выводе фигуры преобразовывать из общего формата к частному как то кривовато с моей точки зрения.

A>
  • OpenGL это, в отличие от многих других библиотек, стандартизированная отрисовка.

    Являюсь новичком в графике. Что означает "стандартизированная"? GDI разве нестандартизирована?

    A>
  • OpenGL, в отличие от многих других библиотек, доступна на практически всех мыслимых платформах

    Уверен что в моем случае хватит только платформ MS
  • Удачной охоты..
    Re[8]: Ну ты и намудрил... :)
    От: Cyberax Марс  
    Дата: 19.07.05 06:50
    Оценка:
    maugli71 wrote:

    > A>В данном случае он не подходит. Данные тут напрямую связаны с

    > представлением. Если кривая безье по разному рисуется на OpenGL и GDI
    > и DirectX, то от отделения данных от представления хорошо никому не
    > станет.
    > Если я правильно понял то так как данные напрямую связаны с
    > представлением я хочу сделать так чтобы данные были специфичны для
    > различных график, но при этом сам объект, скажем Bezier был
    > абстрактен. Говоря по-русски у меня есть абстрактный класс Shape от
    > которого порождаются конкретные фигуры. В Shape включено поле типа
    > ShapeData которое в свою очередь является прародителем для данных
    > конкретных фигур, таких как DataLineGDI, DataLineOGL, DataLineGDIPlus
    > и т.д.

    А вот это лучше убрать из абстрактного интерфейса фигуры. Например если
    захочется одну и ту же линию нарисовать на GDI и в контекст OGL. Что
    тогда делать?

    > В них хранятся данные специфичные для график. Ведь помимо координат,

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

    Значит при рисовании его надо хранить параллельно с фигурой.

    > # A> OpenGL это, в отличие от многих других библиотек,

    > стандартизированная отрисовка.
    > Являюсь новичком в графике. Что означает "стандартизированная"? GDI
    > разве нестандартизирована?

    На OGL есть открытый стандарт от SGI с несколькими реализациями.
    Стандарта на GDI нет.

    --
    С уважением,
    Alex Besogonov (alexy@izh.com)
    Posted via RSDN NNTP Server 1.9
    Sapienti sat!
    Re[9]: Ну ты и намудрил... :)
    От: maugli71 Россия  
    Дата: 19.07.05 07:06
    Оценка:
    Здравствуйте, Cyberax, Вы писали:

    C>А вот это лучше убрать из абстрактного интерфейса фигуры. Например если

    C>захочется одну и ту же линию нарисовать на GDI и в контекст OGL. Что
    C>тогда делать?

    В абстрактном Shape ссылка на абстрактный же ShapeData. Что в этом не так? Одну и ту же линию я не собираюсь рисовать в разных графиках одновременно. У меня есть разые типа график не для одновременного их применения а для того чтобы разобравшись с ними и выбрав какуюнибудь одну я на ней и остановился. Или я не правильно чего понял?

    >> В них хранятся данные специфичные для график. Ведь помимо координат,

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

    C>Значит при рисовании его надо хранить параллельно с фигурой.


    Кого его? Данные? Или стиль пера? Стиль пера один из атрибутов данных. Данные являются полем Shape.

    C>На OGL есть открытый стандарт от SGI с несколькими реализациями.

    C>Стандарта на GDI нет.

    Теперь понятно
    Удачной охоты..
    Re[10]: Ну ты и намудрил... :)
    От: Cyberax Марс  
    Дата: 19.07.05 07:55
    Оценка:
    maugli71 wrote:

    > C>А вот это лучше убрать из абстрактного интерфейса фигуры. Например если

    > C>захочется одну и ту же линию нарисовать на GDI и в контекст OGL. Что
    > C>тогда делать?
    > В абстрактном Shape ссылка на абстрактный же ShapeData. Что в этом не
    > так?

    В одну сущность объединили геометрические данные фигуры и низкоуровные
    данные для рендеринга.

    > Одну и ту же линию я не собираюсь рисовать в разных графиках одновременно.


    А вдруг потом захочется? Например сделать сложную сетку и наложить ее на
    два графика.

    > C>Значит при рисовании его надо хранить параллельно с фигурой.

    > Кого его? Данные? Или стиль пера? Стиль пера один из атрибутов данных.
    > Данные являются полем Shape.

    Да, создать отдельно объект типа Pen и хранить его. Рисование будет
    выглядеть примерно так:
    Shape shape=new SomeStrangeShape();
    Pen pen=getPen();
    
    context.render(shape,pen);


    Или:
    Shape shape=new SomeStrangeShape();
    ShapeRenderer renderer=new ShapeRenderer(context,getPen());
    
    renderer.render(shape);

    Второй подход даже лучше.

    --
    С уважением,
    Alex Besogonov (alexy@izh.com)
    Posted via RSDN NNTP Server 1.9
    Sapienti sat!
    Re[11]: Ну ты и намудрил... :)
    От: maugli71 Россия  
    Дата: 19.07.05 08:09
    Оценка:
    Здравствуйте, Cyberax, Вы писали:

    C>В одну сущность объединили геометрические данные фигуры и низкоуровные

    C>данные для рендеринга.

    Сразу прошу прощения за тупость Слишком новые для меня вопросы графики.
    "геометрические данные фигуры" есть координаты?
    "низкоуровные данные для рендеринга" есть перо?
    И все это хозяйство нужно держать порознь?

    C>Да, создать отдельно объект типа Pen и хранить его. Рисование будет

    C>выглядеть примерно так:
    C>
    C>Shape shape=new SomeStrangeShape();
    C>Pen pen=getPen();
    
    C>context.render(shape,pen);
    C>


    кто должен возвращать перо в getPen?

    C>Или:

    C>
    C>Shape shape=new SomeStrangeShape();
    C>ShapeRenderer renderer=new ShapeRenderer(context,getPen());
    
    C>renderer.render(shape);
    C>


    И что есть render и renderer?
    Удачной охоты..
    Re[11]: Ну ты и намудрил... :)
    От: maugli71 Россия  
    Дата: 19.07.05 10:02
    Оценка:
    Или может так:
    Есть базовый класс Shape. От него Line и Rect.
    Есть базовые классы Pen и Brush. От них порождаются PenOGL, PenGDI, BrushOGL и BrushGDI.

    Shape := TLine.Create(x1, y1, x2, y2);
    
    Graphics := Factory.CreateGraphicsOGL;
    Pen := PenOGL.Create(color, style, width);
    Graphics.DrawLine(Shape, Pen);
    
    Graphics := Factory.CreateGraphicsGDI;
    Pen := PenGDI.Create(color, style, width);
    Graphics.DrawLine(Shape, Pen);


    А нельзя в Shape включить объекты Pen и Shape (абстрактные) и меняя их рисовать в разных реализациях графики? Например:

    Shape := TLine.Create(x1, y1, x2, y2);
    
    Graphics := Factory.CreateGraphicsOGL;
    Shape.Pen := PenOGL.Create(color, style, width);
    Graphics.DrawLine(Shape);
    
    Graphics := Factory.CreateGraphicsGDI;
    Shape.Pen := PenGDI.Create(color, style, width);
    Graphics.DrawLine(Shape);


    Вроде стало немного лучше но приведение внутри Graphics.DrawLine все равно есть. Может как то без него можно..
    Удачной охоты..
    Re[8]: Ну ты и намудрил... :)
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 19.07.05 10:22
    Оценка:
    Здравствуйте, maugli71, Вы писали:

    A>>В данном случае он не подходит. Данные тут напрямую связаны с представлением. Если кривая безье по разному рисуется на OpenGL и GDI и DirectX, то от отделения данных от представления хорошо никому не станет.


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


    При рисовании преобразовывать не надо, надо (если только действительно надо) преобразовывать при чтении и записи файла, созраняя при этом исходные данные.

    M>Являюсь новичком в графике. Что означает "стандартизированная"? GDI разве нестандартизирована?


    Это значит что один и тот же код гарантированно отрисует одно и тоже на разных машинах.
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[9]: Ну ты и намудрил... :)
    От: maugli71 Россия  
    Дата: 19.07.05 10:35
    Оценка:
    Здравствуйте, adontz, Вы писали:

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


    A>При рисовании преобразовывать не надо, надо (если только действительно надо) преобразовывать при чтении и записи файла, созраняя при этом исходные данные.


    Есть абстрактный класс Graphics. От него порождаются GraphicsOGL и GraphicsGDI.
    Имеется абстрактный метод Graphics.DrawLine(Data) перекрываемый в дочерних классах. Data это абстрактный класс. От него LineData и т.д. Как неприводить класс Data в методе DrawLine? Что то я совсем запутался..
    Удачной охоты..
    Re[10]: Ну ты и намудрил... :)
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 19.07.05 10:59
    Оценка:
    Здравствуйте, 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 надо будет добавить методы вроде
    visual_object_base * visual_object_from_point(point pt);
    void * get_object_from_visual_object(visual_object_base * obj);
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[11]: Ну ты и намудрил... :)
    От: maugli71 Россия  
    Дата: 19.07.05 11:28
    Оценка:
    Здравствуйте, adontz, Вы писали:

    Огромное спасибо за столь расширенный ответ. Но у меня несколько другое видение архитектуры которую пока не вижу смысла переделывать. Чем например хуже объект который может сам себя записать/считать в поток/файл, прорисоваться используя определенную реализацию графики и наконец реализует метод типа PtInObject для перетаскиваний? Не могу я так быстро поменять свою точку зрения )))
    Еще раз спасибо за ответ.
    Удачной охоты..
    Re[12]: Ну ты и намудрил... :)
    От: adontz Грузия http://adontz.wordpress.com/
    Дата: 19.07.05 12:03
    Оценка:
    Здравствуйте, 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 это группа или простой объект или ещё что-то, а не вываливать её наружу.
    A journey of a thousand miles must begin with a single step © Lau Tsu
    Re[13]: Ну ты и намудрил... :)
    От: maugli71 Россия  
    Дата: 19.07.05 12:15
    Оценка:
    Здравствуйте, 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 объектов его состовляющих. Что я тут вывалил наружу не пойму? Если возможно — ногами не бить ))
    Удачной охоты..
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.