平面上的形状编辑
一、设计目的:
实现一个平面上的形状编辑程序。
二、程序功能简介:
- 按照下图给出的层次关系来定义类。
2.所有形状支持无参数构造,有参数构造,拷贝构造,析构。
3.所有形状支持平移操作,需要重载 operator+。
4.所有形状(除去无意义的),均支持计算周长。
5.所有形状(除去无意义的),均支持 Draw()操作,此时只要显示形状的名 称,位置等信息。
6.需要实现一个 CShapeArray 类,该类类似一个数组,用来存放编辑过程中的 平面形状。该类需要支持:添加,插入,删除,查询,复制等操作。可以支持形 状编辑中需要的针对形状的操作。
7.主程序中实现用户输入形状及其参数,然后把形状存入 6 中定义的 CShapeArray。在输入形状的同时,用户可以查询当前已经输入的形状(可按名 称(需要对每个平面形状加入名称),位置来查询)。支持用户对形状的复制,粘 贴(粘贴时假设用户指定粘贴的位置)。同时支持用户对形状的删除操作。
8.输入和处理好的形状可以存入文件,并从文件中读入。
9.支持对当前所有形状的 Draw()。
三、详细介绍:
1、关于程序使用的代码风格
本程序使用 Visual Studio 2010 编写,并按照规范风格,将类、函数、变量的声明、 其他头文件的引用等写在头文件(*.h 文件)中,并使用头文件保护符(#pragma once)保护以免重复编译,具体函数的定义等则写在对应的源文件中。函数的注 释说明写在头文件函数声明处,函数内部具体代码说明写在源文件代码处。
2、程序中类的声明
本程序定义了以下几个类(其中由于 CPoint 为 VS 中的保留类名,改用 CCPoint):
class CShape;
class CCircle : public CShape;
class CCPoint : public CShape;
class CLine : public CShape;
class CRectangle : public CShape;
class CPolygon : public CShape;
class CTriangle : public CPolygon;
class CShapeArray;
基类 CShape 定义如下,其中函数
virtual void Draw(void);
virtual void Calc(void);
virtual void saveToFile(ofstream&);
virtual CShape& loadFromFile(ifstream&);
virtual int exist();
为虚函数,具体根据继承的子类不同而有不同定义,体现了 C++ 的多态性;变量 const static int SHAPE_CIRCLE 等用于区分不同子类的具体类型,用于全局函 数 loadFromFile()从文件加载形状信息。
class CShape {
public: const static int SHAPE_CIRCLE = 1;
const static int SHAPE_POINT = 2;
const static int SHAPE_LINE = 3;
const static int SHAPE_POLYGON = 4;
const static int SHAPE_RECTANGLE = 5;
const static int SHAPE_TRIANGLE = 6;// 无参数构造
CShape(void);
// 有参数构造
CShape(char * );
// 析构函数
~CShape(void);
// 拷贝构造
CShape(const CShape & );
// 获取名称
char * getName();
// 显示名称等信息,使用虚函数
virtual void Draw(void);
// 计算并显示周长,使用虚函数
virtual void Calc(void);
// 保存至文件
virtual void saveToFile(ofstream & );
// 从文件读取
virtual CShape & loadFromFile(ifstream & );
// 判断形状是否存在
virtual int exist()protected:
// 图形的名称 char* name; int shape;
};
子类 CCircle, CCPoint, CLine, CRectangle, CPolygon 继承于基类 CShape,类 CTriangle 继承于类 CPolygon,分别表示具体的形状,并分别定义了各自的 Draw(),Calc(), saveToFile,loadFromFile 等函数。
类 CShapeArray 用于存放编辑过程中的平面形状,支持:添加,插入,删除,查 询,复制等操作。使用 vector<CShape*> vec 来保存添加进的 CShape 对象的指针。 其定义如下:
class CShapeArray {
public: CShapeArray(void);~CShapeArray(void);
// 添加
void add(CShape * );// 插入
void insert(int, CShape);
// 删除
void del(int);
// 清除全部
void clear(void);
// 查询
CShape * get(int);
// 复制
void copy(int, int);
// 显示所有元素
void drawAll(void);
// 获取元素数目
int getSize(void);
// 根据名称查询
int findByName(char * );private: vector < CShape * >vec;
};
3、全局变量及全局函数
/**********************全局变量声明**********************/
// 保存到的文件名
const static char *fname = "D:\\dat.txt";
// CShapeArray 对象
CShapeArray arr;
// 记录要复制的形状所在位置
int copyPos = -1;
/************************函数声明************************/
// 输入数字进行选择
int input(char *, int);
// 清屏
void clr();
// 暂停
void pause();
// 选择操作
void inputOp();
// 选择形状
void inputShape();
// 查询
void inputQuery();// 输入位置查询
void inputPos();
// 输入名称查询
void inputName();
// 复制
void inputCopy();
// 粘贴
void inputPaste();
// 删除
void inputDel();
// 保存至文件
void saveToFile();
// 从文件读取
void loadFromFile();
// 输入矩形
CRectangle* inputRectangle();
// 输入圆形
CCircle* inputCircle();
// 输入多边形
CPolygon* inputPolygon();
// 输入三角形
CTriangle* inputTriangle();
// 输入点
CCPoint* inputPoint();
// 输入直线
CLine* inputLine();
4、程序的使用
程序启动即进入功能选择主菜单。用户通过输入数字并按回车进行功能的选择,如果用户输入的不是数字,或数字超出了输入范围,则提示输入错误需要重 新输入(该功能由 input 函数实现)。
添加形状时,根据用户选择的形状不同,要求输入的参数也不同,如果输入 的参数能构成相应形状(如三角形两边之和要大于第三边,此功能由 exist 函数 实现),则添加该形状至对象 CShapeArray arr 中,否则提示错误而不保存。输入形状的名称时,支持输入中英文,并可包含空格。
5、程序的稳定性
本程序能自动纠正部分用户输入错误,以及从文件读取时发生的错误,并给出相应提示信息。
6、运行结果
启动后提示输入数字选择操作:
选择操作输入形状,选择要输入的形状为圆形:
输入圆心坐标和半径,按回车键确认:
选择操作“2.查询已输入”,选择“3.显示全部”:
保存至文件(默认保存至 D:\dat.txt 中):
从文件读取(默认从 D:\dat.txt 中读取):
四、部分源码
// 多边形的存在性判断
int CPolygon: :exist() {// 此函数没有考虑输入的点重合时的情况float * length = new float[edges];float lengthAll = 0;// 计算各边长for (int i = 0; i < edges; i++) {if (i == 0) {length[i] = sqrt(pow((px[edges - 1] - px[0]), 2) + pow((py[edges - 1] - py[0]), 2));} else {length[i] = sqrt(pow((px[i - 1] - px[i]), 2) + pow((py[i - 1] - py[i]), 2));}lengthAll += length[i];}float lengthHalf = lengthAll / 2.0;// 如果一边之长大于等于其他所有边之和,即该边长大于等于全长的一半, 多边形不存在for (int i = 0; i < edges; i++) {if (length[i] >= lengthHalf) return 0;}return 1;
}// 输入数字进行选择
int input(char * promote, int choices) {while (1) {cout << "\n" << promote << endl;int x;cin >> x;if (x > 0 && x <= choices) {return x;} else {clr();// 重置 cin 状态为 ios_base::goodbit,// 清空输入缓冲区中的错误数据,// 避免输入字母造成的死循环cin.clear();cin.sync();cout << "输入错误,请重新输入!" << endl;}}
}// 清屏
void clr() {system("CLS");
}// 暂停
void pause() {system("PAUSE");
}// 选择操作
void inputOp() {int r;while (1) {clr();r = input("-----------------------------------------------------------------\n\选择操作:\n\1.输入形状 2.查询已输入 3.复制 4.粘贴\n\5.删除 6.保存至文件 7.从文件读入 8.退出\n\-----------------------------------------------------------------", 8);switch (r) {case 1:// 输入形状 inputShape(); break;case 2:// 查询已输入if (!arr.getSize()) {cout << "没有数据!" << endl;} else {inputQuery();}break;case 3:// 复制 inputCopy(); break;case 4:// 粘贴 inputPaste(); break;case 5:// 删除inputDel();break;case 6:// 保存至文件saveToFile();break;case 7:// 从文件读入loadFromFile();break;case 8:// 退出exit(0);}}
}// 保存至文件
void saveToFile() {ofstream fs(fname);int num = arr.getSize();fs << num << endl;for (int i = 0; i != num; i++) {arr.get(i) - >saveToFile(fs);}fs.close();cout << "已保存至" << fname << endl;pause();
}// 从文件加载
void loadFromFile() {arr.clear();ifstream fs("D:\\dat.txt", ios: :in);if (!fs.good()) {// 发生错误,退出cout << "Error!" << endl;pause();return;}CShape * s;int shape;int num = 0;fs >> num;for (int i = 0; i < num; i++) {if (fs.eof()) {// 发生错误,退出cout << "Error!" << endl;pause();return;}shape = -1;fs >> shape;switch (shape) {case CShape::SHAPE_CIRCLE:s = new CCircle();break;case CShape::SHAPE_LINE:s = new CLine();break;case CShape::SHAPE_POINT:s = new CCPoint();break;case CShape::SHAPE_POLYGON:s = new CPolygon();break;case CShape::SHAPE_RECTANGLE:s = new CRectangle();break;case CShape::SHAPE_TRIANGLE:s = new CTriangle();break;default:// 发生错误,退出cout << "Error!" << endl;pause();return;}s - >loadFromFile(fs);arr.add(s);}fs.close();cout << "已从" << fname << "读取完成" << endl;pause();
}