, идентичный (вплоть до последнего пикселя) исходному объекту класса
Closed_polyline
.
Проверка того, что объект класса
Polygon
действительно представляет собой многоугольник, оказывается на удивление запутанной. Проверка пересечений, которая реализована в функции
Polygon::add
, является наиболее сложной во всей графической библиотеке. Если вас интересуют кропотливые
геометрические манипуляции с координатами, взгляните на код. И это еще не все. Посмотрим, что произойдет, когда мы попытаемся создать объект класса
Polygon
лишь из двух точек. Лучше предусмотреть защиту от таких попыток.
void Polygon::draw_lines const
{
if (number_of_points < 3)
error("Меньше трех точек вводить нельзя.");
Closed_polyline::draw_lines;
}
Проблема заключается в том, что инвариант класса
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 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) реализует простой способ размещения фигуры поверх другой (используя функцию