6.4.2 Библиотека фигур.

   


Назад  |  Вперёд

Начнем с определения общего понятия фигуры. Определение должно быть таким, чтобы им можно было воспользоваться (как базовым классом shape) в разных классах, представляющих все конкретные фигуры (окружности, квадраты и т.д.). Оно также должно позволять работать со всякой фигурой исключительно с помощью интерфейса, определяемого классом shape:

           struct shape {
              static shape* list;
              shape* next;

              shape() { next = list; list = this; }

              virtual point north() const = 0;
              virtual point south() const = 0;
              virtual point east() const = 0;
              virtual point west() const = 0;
              virtual point neast() const = 0;
              virtual point seast() const = 0;
              virtual point nwest() const = 0;
              virtual point swest() const = 0;

              virtual void draw() = 0;
              virtual void move(int, int) = 0;
           };

Фигуры помещаются на экран функцией draw(), а движутся по нему с помощью move(). Фигуры можно помещать относительно друг друга, используя понятие точек контакта. Для обозначения точек контакта используются названия сторон света в компасе: north - север, ... , neast - северо-восток, ... , swest - юго-запад. Класс каждой конкретной фигуры сам определяет смысл этих точек и определяет, как рисовать фигуру. Конструктор shape::shape() добавляет фигуру к списку фигур shape::list. Для построения этого списка используется член next, входящий в каждый объект shape. Поскольку нет смысла в объектах типа общей фигуры, класс shape определен как абстрактный класс.

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

           class line : public shape {
           /*
             отрезок прямой ["w", "e" ]
             north() определяет точку - `` выше центра отрезка и
             так далеко на север, как самая его северная точка''
           */
             point w, e;
           public:
             point north() const
               { return point((w.x+e.x)/2,e.y<w.y?w.y:e:y); }
             point south() const
               { return point((w.x+e.x)/2,e.y<w.y?e.y:w.y); }
             point east() const;
             point west() const;
             point neast() const;
             point seast() const;
             point nwest() const;
             point swest() const;

             void move(int a, int b)
                { w.x +=a; w.y +=b; e.x +=a; e.y +=b; }
             void draw() { put_line(w,e); }

             line(point a, point b) { w = a; e = b; }
             line(point a, int l) { w = point(a.x+l-1,a.y); e = a; }
           };

Аналогично определяется прямоугольник:

           class rectangle : public shape {
           /*   nw ------ n ----- ne
                |                  |
                |                  |
                w         c        e
                |                  |
                |                  |
                sw ------ s ----- se
           */
              point sw, ne;
           public:
              point north() const { return point((sw.x+ne.x)/2,ne.y); }
              point south() const { return point((sw.x+ne.x)/2,sw.y); }
              point east() const;
              point west() const;
              point neast() const { return ne; }
              point seast() const;
              point nwest() const;
              point swest() const { return sw; }

              void move(int a, int b)
              { sw.x+=a; sw.y+=b; ne.x+=a; ne.y+=b; }
              void draw();

              rectangle(point,point);
           };

Прямоугольник строится по двум точкам. Конструктор усложняется, так как необходимо выяснять относительное положение этих точек:

           rectangle::rectangle(point a, point b)
           {
             if (a.x <= b.x) {
                if (a.y <= b.y) {
                   sw = a;
                   ne = b;
                }
                else {
                   sw = point(a.x,b.y);
                   ne = point(b.x,a.y);
                }
             }
             else {
                if (a.y <= b.y) {
                   sw = point(b.x,a.y);
                   ne = point(a.x,b.y);
                }
                else {
                   sw = b;
                   ne = a;
                }
             }
           }

Чтобы нарисовать прямоугольник, надо нарисовать четыре отрезка:

           void rectangle::draw()
           {
             point nw(sw.x,ne.y);
             point se(ne.x,sw.y);
             put_line(nw,ne);
             put_line(ne,se);
             put_line(se,sw);
             put_line(sw,nw);
           }

В библиотеке фигур есть определения фигур и функции для работы с ними:

           void shape_refresh();      // нарисовать все фигуры
           void stack(shape* p, const shape* q); // поместить p над q

Функция обновления фигур нужна, чтобы работать с нашим примитивным представлением экрана; она просто заново рисует все фигуры. Отметим, что эта функция не имеет понятия, какие фигуры она рисует:

           void shape_refresh()
           {
             screen_clear();
             for (shape* p = shape::list; p; p=p->next) p->draw();
             screen_refresh();
           }

Наконец, есть одна действительно сервисная функция, которая рисует одну фигуру над другой. Для этого она определяет юг (south()) одной фигуры как раз над севером (north()) другой:

           void stack(shape* p, const shape* q) // поместить p над q
           {
             point n = q->north();
             point s = p->south();
             p->move(n.x-s.x,n.y-s.y+1);
           }

Представим теперь, что эта библиотека является собственностью некоторой фирмы, продающей программы, и, что она продает только заголовочный файл с определениями фигур и оттранслированные определения функций. Все равно вы сможете определить новые фигуры, воспользовавшись для этого купленными вами функциями.


Назад  |  Вперёд


OtDiatlovaOU
К началу книги

Оформление и дизайн книги OtDiatlovaOU.
Вся книга, архив.