编写一个平面图形系统,实现类似Windows画图的功能:可以绘制基本的图形,比如矩形,圆形、直线段、椭圆等,可以设置形状的线条颜色/粗细/线型。要求:
1)定义一个命名空间Graphics;在该空间中开发图形系统。
2)编写一个表示画布的类Canvas,所有图形由该类维护,Canvas类有一个方法是保存绘图结果到一个bmp文件。保存bmp文件的代码在BmpIO.h和BmpIO.cpp中。Canvas类另一个方法是添加基本图形实例到画布中。其它方法根据需要自行添加。
3)编写抽象基类Shape,表示抽象的图形;
4)从Shape派生出至少两个子类,表示两种不同的图形;
5)在main函数中,生成Canvas对象,并向该对象添加几种图形实例,然后保存成位图文件。
6)尝试在Canvas中添加一个填充功能,使用FloodFill算法,从指定的种子点开始,用指定的颜色,填充一个封闭的区域。
shape.h
#ifndef _SHAPE_H_ #define _SHAPE_H_ #include
using namespace std; namespace Graphics { class Point { public: int x, y; public: Point() :x(0), y(0) {} Point(int _x, int _y) :x(_x), y(_y) {} double DistanceTo(const Point p); }; class Color { public: unsigned char r, g, b; static Color red, green, blue, white, black; public: Color() :r(0xFF), g(0xFF), b(0xFF) {} Color(unsigned char _r, unsigned char _g, unsigned char _b) : r(_r), g(_g), b(_b) {} Color(const Color &clr) :r(clr.r), g(clr.g), b(clr.b) {} friend bool operator==(const Color &c1, const Color &c2); }; class Shape { private: Color lineColor; public: Shape() :lineColor(Color::black) {} Shape(const Color _lineColor) : lineColor(_lineColor) {} Shape(const Shape &s) :lineColor(s.lineColor) {} void setLineColor(const Color _lineColor) { lineColor = _lineColor; }; Color getLineColor() const { return lineColor; } virtual void GetEdgePointList(vector &ptList) = 0; virtual Shape* Clone() const = 0; virtual ~Shape() {}; }; class Rect :public Shape { private: Point p; int width, height; public: Rect() :p(Point()), width(1), height(1) {} Rect(const Point &position, const int _width, const int _height) : p(position), width(_width), height(_height) {} Rect(const Color _lineColor, const Point &position, const int _width, const int _height) : Shape(_lineColor), p(position), width(_width), height(_height) {} Rect(const Rect &r) :Shape(r), p(r.p), width(r.width), height(r.height) {} Rect& operator=(const Rect &r); Shape* Clone() const; void GetEdgePointList(vector &ptList); ~Rect() {} }; class Circle :public Shape {//声明Circle类 private: Point p;//圆心p点 int r;//半径r public: Circle() :p(Point()), r(1) {}//默认构造函数 Circle(const Point &position, const int _r) :p(position), r(_r) {}//带参构造函数 Circle(const Color _lineColor, const Point &position, const int _r) : Shape(_lineColor), p(position), r(_r) {} Circle(const Circle&c) :Shape(c), p(c.p), r(c.r) {}//拷贝构造函数 Circle&operator=(const Circle &c);//拷贝赋值函数 Shape*Clone()const; void GetEdgePointList(vector &ptList); }; class Ellipse :public Shape {//声明椭圆类 public: Point p;//椭圆中心点 int a, b;//椭圆的半长轴与半短轴 private: Ellipse() :p(Point()), a(2), b(1) {}//无参构造函数,将a、b分别初始化为2、1 Ellipse(const Point &position, const int _a, const int _b) :p(position), a(_a), b(_b) {} Ellipse(const Color _lineColor, const Point &position, const int _a, const int _b) : Shape(_lineColor), p(position), a(_a), b(_b) {}//带参构造函数 Ellipse(const Ellipse&o) :Shape(o), p(o.p), a(o.a), b(o.b) {}//拷贝构造函数 Ellipse&operator=(const Ellipse &o);//拷贝赋值函数 Shape*Clone()const; void GetEdgePointList(vector &ptList); }; } #endif shape.cpp
#include "Shape.h" using namespace Graphics; Color Color::red(0xFF, 0x00, 0x00); Color Color::green(0x00, 0xFF, 0x00); Color Color::blue(0x00, 0x00, 0xFF); Color Color::white(0xFF, 0xFF, 0xFF); Color Color::black(0x00, 0x00, 0x00); bool Graphics::operator==(const Color &c1, const Color &c2) {//加上了Graphics return (c1.r == c2.r) && (c1.g == c2.g) && (c1.b == c2.b); } double Point::DistanceTo(const Point p) { return sqrt((p.x - x)*(p.x - x) + (p.y - y)*(p.y - y)); } Rect& Rect::operator=(const Rect &r) { if (this != &r) { setLineColor(r.getLineColor()); p = r.p; width = r.width; height = r.height; } return *this; } Shape* Rect::Clone() const { return new Rect(*this); } void Rect::GetEdgePointList(vector
&ptList) { ptList.clear(); for (int i = p.x; i < p.x + width; ++i) { ptList.push_back(Point(i, p.y)); ptList.push_back(Point(i, p.y + height)); } for (int j = p.y; j < p.y + height; ++j) { ptList.push_back(Point(p.x, j)); ptList.push_back(Point(p.x + width, j)); } } Circle& Circle::operator=(const Circle &c) { if (this != &c) { setLineColor(c.getLineColor()); p = c.p; r = c.r; } return *this; } Shape* Circle::Clone() const { return new Circle(*this); } void Circle::GetEdgePointList(vector &ptList) { ptList.clear(); if (r <= 0)return; double delta = std::fmax(1 / r, 1e-5); static const double two_pi = 3.1415926 * 2; for (double t = 0; t < two_pi; t += delta) { int x = static_cast (r*cos(t) + p.x); int y = static_cast (r*sin(t) + p.y); ptList.push_back(Point(x, y)); } } Ellipse&Ellipse::operator=(const Ellipse &o) { if (this != &o) { setLineColor(o.getLineColor()); p = o.p; a = o.a; b = o.b; } return *this; } Shape* Ellipse::Clone() const { return new Ellipse(*this); } void Ellipse::GetEdgePointList(vector &ptList) { ptList.clear(); if (a <= 0 || b <= 0)return; double delta = std::fmax(1 / (a), 1e-5); static const double two_pi = 3.1415926 * 2; for (double t = 0; t < two_pi; t += delta) { int x = static_cast (a*cos(t) + p.x); int y = static_cast (b*sin(t) + p.y); ptList.push_back(Point(x, y)); } } Canvas.h
#ifndef _CANVAS_H_ #define _CANVAS_H_ #include "Shape.h" #include
using namespace std; namespace Graphics { class Canvas { private: int width, height; Color bgColor; vector allShapes; unsigned char *pixels; private: void ConvertToBitmap(); void RemoveAllShapes(); public: Canvas() :bgColor(Color::white), width(640), height(480), pixels(nullptr) {} Canvas(int _width, int _height, Color _bgColor = Color::white) : width(_width), height(_height), bgColor(_bgColor) {} Canvas(const Canvas &c); Canvas& operator=(const Canvas &c); ~Canvas() { delete[]pixels; RemoveAllShapes(); } void Attach(const Shape &s) { allShapes.push_back(s.Clone()); } void ReDraw() {} void SaveToBitmap(const char *filename); }; } #endif Canvas.cpp
#include "Canvas.h" #include "BmpIO.h" using namespace Graphics; Canvas::Canvas(const Canvas &c) { bgColor = c.bgColor; width = c.width; height = c.height; /*vector
allShapes; unsigned char *pixels;*/ unsigned char*_ptemp = new unsigned char; _ptemp = c.pixels; pixels = _ptemp; vector temp = c.allShapes; allShapes = temp; } Canvas& Canvas::operator=(const Canvas &c) { if (this != &c) { delete[]pixels; for (unsigned int i = 0; i < allShapes.size(); ++i) { delete allShapes[i]; } bgColor = c.bgColor; width = c.width; height = c.height; /*vector allShapes; unsigned char *pixels;*/ unsigned char*_ptemp = new unsigned char; _ptemp = c.pixels; pixels = _ptemp; vector temp = c.allShapes; allShapes = temp; } return *this; } void Canvas::RemoveAllShapes() { for (auto x : allShapes)delete x; allShapes.clear(); } void Canvas::ConvertToBitmap() { if (nullptr != pixels) delete[]pixels; pixels = nullptr; int numPixels = width * height; if (numPixels < 1) return; pixels = new unsigned char[numPixels * 3]; for (int j = 0; j < numPixels; j++) { pixels[3 * j + 0] = bgColor.r; pixels[3 * j + 1] = bgColor.g; pixels[3 * j + 2] = bgColor.b; } vector ptList; for (auto x : allShapes) { x->GetEdgePointList(ptList); Color c = x->getLineColor(); for (auto p : ptList) { if (p.x >= 0 && p.x < width && p.y>0 && p.y < height) { int index = (p.x + p.y * width) * 3; pixels[index + 0] = c.r; pixels[index + 1] = c.g; pixels[index + 2] = c.b; } } } } void Canvas::SaveToBitmap(const char *filename) { ConvertToBitmap(); WriteBitmap(pixels, width, height, filename); } BmplO.h与BmplO.cpp略
展示效果: