Проблема заключается в том, что инвариант класса
Polygon
— “точки образуют многоугольник” — невозможно проверить, пока не будут определены все точки. Иначе говоря, в соответствии с настоятельными рекомендациями мы не задаем проверку инварианта в конструкторе класса
Polygon
. И все же “предупреждение о трех точках” в классе
Polygon::draw_lines()
— совершенно недопустимый трюк. (См. также упр. 18.)
13.9. Класс Rectangle
Большинство фигур на экране являются прямоугольниками. Причина этого явления объясняется частично культурными традициями (большинство дверей, окон, картин, книжных шкафов, страниц и т.д. является прямоугольниками), а частично техническими особенностями (задать координаты прямоугольника проще, чем любой другой фигуры). В любом случае прямоугольник настолько широко распространен, что в системах графического пользовательского интерфейса он обрабатывается непосредственно, а не как многоугольник, имеющий четыре прямых угла.
struct Rectangle:Shape {
Rectangle(Point xy, int ww, int hh);
Rectangle(Point x, Point y);
void draw_lines() const;
int height() const { return h; }
int width() const { return w; }
private:
int h; // высота
int w; // ширина
};
Мы можем задать прямоугольник двумя точками (левой верхней и правой нижней) или одной точкой, шириной и высотой. Конструкторы этого класса могут иметь следующий вид:
Rectangle::Rectangle(Point xy,int ww,int hh)
:w(ww),h(hh)
{
if (h<=0 || w<=0)
error("Ошибка: отрицательная величина");
add(xy);
}
Rectangle::Rectangle(Point x,Point y)
:w(y.x–x.x),h(y.y–x.y)
{
if (h<=0 || w<=0)
error("Ошибка: отрицательная ширина или длина.");
add(x);
}
Каждый конструктор соответствующим образом инициализирует члены
h
и
w
(используя синтаксис списка инициализации; см. раздел 9.4.4) и хранит верхнюю левую точку отдельно в базовом классе
Shape
(используя функцию
add()
). Кроме того, в конструкторах содержится проверка ширины и длины — они не должны быть отрицательными.
Одна из причин, по которым некоторые системы графики и графического пользовательского интерфейса рассматривают прямоугольники как отдельные фигуры, заключается в том, что алгоритм определения того, какие пиксели попадают внутрь прямоугольника, намного проще и, следовательно, быстрее, чем алгоритмы проверки для других фигур, таких как
Polygon
и
Circle
. По этой причине понятие “заполнение цветом” — т.е. закраска пространства внутри прямоугольника — чаще применяется по отношению к прямоугольникам, чем к другим фигурам.
Заполнение цветом можно реализовать в конструкторе или в виде отдельной функции
set_fill_color()
(предусмотренной в классе
Shape
наряду с другими средствами для работы с цветом).
Rectangle rect00(Point(150,100),200,100);
Rectangle rect11(Point(50,50),Point(250,150));
Rectangle rect12(Point(50,150),Point(250,250)); // ниже rect11
Rectangle rect21(Point(250,50),200,100); // правее rect11
Rectangle rect22(Point(250,150),200,100); // ниже rect21
rect00.set_fill_color(Color::yellow);
rect11.set_fill_color(Color::blue);
rect12.set_fill_color(Color::red);
rect21.set_fill_color(Color::green);
В итоге получаем следующее изображение:
Если заполнение цветом не требуется, то прямоугольник считается прозрачным; вот почему вы видите желтый угол объекта
rect00
.
Фигуры можно передвигать в окне (см. раздел 14.2.3). Рассмотрим пример.
rect11.move(400,0); // вправо от rect21
rect11.set_fill_color(Color::white);
win12.set_label("rectangles 2");
В итоге получим изображение, приведенное ниже.
Заметьте, что только часть белого прямоугольника
rect11
помещается в окне. То, что выходит за пределы окна, “отрезается”; иначе говоря, на экране эта часть не отображается.
Обратите внимание на то, как фигуры накладываются одна на другую. Это выглядит так, будто вы кладете на стол один лист бумаги на другой. Первый лист окажется в самом низу. Наш класс
Window
(раздел Д.3) реализует простой способ размещения фигуры поверх другой (используя функцию
Window::put_on_top()
). Рассмотрим пример.
win12.put_on_top(rect00);
win12.set_label("rectangles 3");
В итоге получаем следующее изображение:
Отметьте, что мы можем видеть линии, образующие прямоугольник, даже если он закрашен. Если такое изображение нам не нравится, то линии можно удалить.