问题 A: 简单几何绘图
题目文字描述
时间限制: 1 Sec 内存限制: 128 MB Special Judge
提交: 844 解决: 157
题目描述
本题要求实现简单基本几何:圆, 线(段)以及矩形的绘制。实现后的效果如下所示:
这里渲染使用的是OpenGL, 窗口管理使用的是GLUT。渲染和窗口管理的代码由我们给出, 不需要自己实现。
你的任务是实现圆, 线(段)以及矩形三个几何元素的相关内容:
对于圆, 给定圆心(x, y) 和半径
对于线段, 给定起点(x1,y1)和终点(x2,y2)
对于矩形,给定左(left),上(top),右(right),下(bottom)四个值。
对于每个几何对象,要求实现void input(std::istream &in) 接口,能够从in (std::in或者文件)获取坐标(半径)信息,
实现 void display(BlackBoard &board) 接口,将几何对象绘制到BlackBoard 对象 board上面,
实现 void print(std::ostream &out) 接口,将几何对象的几何坐标(半径)信息打印到 out (std::out 或者文件);
打印格式描述如下:
对于圆: Circle{center_X: 100, center_Y: 10, radius: 100}
对于线(段):Line{point1_X: -500, point1_Y: -130, point2_X:-30, point2_Y:-100}
对于矩形:Rectangle{left: -130, top: -130, right: -30, bottom: -100}
每打印一个对象需要换行,每个对象的元素之间需要空格,比如对于圆的例子,应该是: Circle{center_X:#100,#center_Y:#10,#radius:#100}, #代表空格。
由于在OJ上面的提交你看不到绘图效果,所以下面给出一个已经写好绘图渲染以及窗口管理的相关代码,你可以先在自己的电脑进行本地调试,通过了再进行OJ的提交。
本地端调试代码模板
输入
每行一个几何对象的对应的坐标或者半径信息
对于每一行(每一个对象)
第一个数字代表几何对象的类型,1代表圆,2代表线(段),3代表矩形。
后面接所需的几何坐标或者半径。
最后一行输入一个0,代表结束输入,开始绘制。
输出
输出如题目描述中的print函数所要求的格式。
样例输入 Copy
2 -500 -130 -30 -100
3 -130 -130 -30 -100
1 100 10 100
1 100 10 120
1 100 10 140
1 100 10 160
1 100 10 180
1 100 10 200
0
样例输出 Copy
Line{point1_X: -500, point1_Y: -130, point2_X: -30, point2_Y: -100}
Rectangle{left: -130, top: -130, right: -30, bottom: -100}
Circle{center_X: 100, center_Y: 10, radius: 100}
Circle{center_X: 100, center_Y: 10, radius: 120}
Circle{center_X: 100, center_Y: 10, radius: 140}
Circle{center_X: 100, center_Y: 10, radius: 160}
Circle{center_X: 100, center_Y: 10, radius: 180}
Circle{center_X: 100, center_Y: 10, radius: 200}
题目截图
代码
/*
*2020年12月7号晚9点
*by——
/ * -----------------------------------------------------------------------*/
#include <fstream>
#include <iostream>
#include <math.h>
#include <vector>
#include "GL/glut.h"
using namespace std;
/*********************************************************
* the code below is for render and window manager
* ********************************************************/
typedef void (*CallbackFunction)();
typedef void (*KeyboardFunction)(unsigned char key, int x, int y);
typedef void (*ReshapeFunction)(int width, int height);
typedef void (*MouseButtonFunction)(int button, int state, int x, int y);
typedef void (*MouseMotionFunction)(int x, int y);
typedef void (*IdleFunction)(void);
typedef void (*TimerFunction)(int value);
class BlackBoard
{
public:
void InitCommandLine(int *argc, char **argv);
void InitWindowSize(int width, int height);
void UpdateWindowSize(int width, int height);
// 设置窗口绘制回调函数
void InitDisplayCallback(CallbackFunction callback);
// 设置键盘事件回调函数
void InitKeyboardCallback(KeyboardFunction callback);
// 设置窗口缩放事件回调函数
void InitReshapeCallback(ReshapeFunction callback);
// 设置鼠标点击事件回调函数
void InitMouseButtonCallback(MouseButtonFunction callback);
// 设置鼠标移动事件回调函数
void InitMouseMotionCallback(MouseMotionFunction callback);
// 设置空闲状态回调函数
void InitIdleCallback(IdleFunction callback);
// 启动一个定时器,注意,只会触发一次,不会周期触发
// 需要周期触发可在回调函数中,再次启动一个同样的定时器
void InstallTimerCallback(unsigned int millis, TimerFunction callback, int value);
// 创建并显示窗口,仅调用一次,之后,将进入事件循环
void Show();
// 标志窗口需要更新,通常是数据发生变化后,用于主动要求窗口重绘
void Update();
// 以下函数只用于绘制回调函数中,通常时,程序调用Update或系统发起Update-> 窗口重绘(事件循环调用绘制回调函数) -> 用以下函数绘制图形
// 设置颜色,r/g/b为三色分量,0-1之间,
// 如纯红为1,0,0;
// 纯白为1,1,1
void SetColor(double r, double g, double b);
// 清屏
void Clear();
// 讲绘制图像显示出来
void Flush();
// 画线,参数为两个端点的x、y坐标
void DrawLine(int x1, int y1, int x2, int y2);
// 画圆,参数为圆圆心x、y,半径
void DrawCircle(int x, int y, int r);
private:
int _width, _height;
};
using std::cout;
using std::endl;
void BlackBoard::InitCommandLine(int *argc, char **argv)
{
glutInit(argc, argv);
}
void BlackBoard::InitWindowSize(int width, int height)
{
_width = width;
_height = height;
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(0, 0);
glutInitWindowSize(_width, _height);
glutCreateWindow("BlackBoard");
}
void BlackBoard::UpdateWindowSize(int width, int height)
{
_width = width;
_height = height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
void BlackBoard::InitDisplayCallback(CallbackFunction callback)
{
glutDisplayFunc(callback);
}
void BlackBoard::InitKeyboardCallback(KeyboardFunction callback)
{
glutKeyboardFunc(callback);
}
void BlackBoard::InitReshapeCallback(ReshapeFunction callback)
{
glutReshapeFunc(callback);
}
void BlackBoard::InitMouseButtonCallback(MouseButtonFunction callback)
{
glutMouseFunc(callback);
}
void BlackBoard::InitMouseMotionCallback(MouseMotionFunction callback)
{
glutMotionFunc(callback);
}
void BlackBoard::InitIdleCallback(IdleFunction callback)
{
glutIdleFunc(callback);
}
void BlackBoard::InstallTimerCallback(unsigned int millis, TimerFunction callback, int value)
{
glutTimerFunc(millis, callback, value);
}
void BlackBoard::Show()
{
glutMainLoop();
}
void BlackBoard::SetColor(double r, double g, double b)
{
glColor3f(r, g, b);
}
void BlackBoard::Update()
{
glutPostRedisplay();
}
void BlackBoard::DrawLine(int x1, int y1, int x2, int y2)
{
glBegin(GL_LINES);
glVertex2f(GLfloat(x1) / _width * 2, GLfloat(y1) / _height * 2);
glVertex2f(GLfloat(x2) / _width * 2, GLfloat(y2) / _height * 2);
glEnd();
}
void BlackBoard::DrawCircle(int x, int y, int r)
{
const int CIRCLE_SEGMENTATION = 360;
const GLfloat Pi = 3.1415926536f;
GLfloat x0 = GLfloat(x) / _width * 2;
GLfloat y0 = GLfloat(y) / _height * 2;
glBegin(GL_LINE_LOOP);
for (int i = 0; i < CIRCLE_SEGMENTATION; ++i)
{
glVertex2f(x0 + GLfloat(r) * cos(2 * Pi * i / CIRCLE_SEGMENTATION) / _width * 2, y0 + GLfloat(r) * sin(2 * Pi * i / CIRCLE_SEGMENTATION) / _height * 2);
}
glEnd();
}
void BlackBoard::Clear()
{
glClear(GL_COLOR_BUFFER_BIT);
}
void BlackBoard::Flush()
{
glFlush();
}
/*********************************************************
* the code above is for render and window manager
* ********************************************************/
/*********************************************************
* the code below is for 2D geometry manager.
* it is what you need to implement.
* !Notify: this is just a example class, it doesn't mean
* you don't need implement other class(es).
* Just implement the function in your free.
* ********************************************************/
/***************只需要交这里的,这是开头****************************************************************/
/**********************************/
//圆类
class Circle
{
private:
int x, y, radius;
public:
//默认构造函数
Circle()
{
x = 0;
y = 0;
radius = 0;
}
void input_circle(std::istream& is);
void display_circle(BlackBoard& board);
void print_circle(std::ostream& out);
};
void Circle::input_circle(std::istream& is)
{
is >> x >> y >> radius;
}
void Circle::print_circle(std::ostream& out)
{
out << "Circle{center_X: " << x;
out << ", center_Y: " << y;
out << ", radius: " << radius << "}" << std::endl;
}
void Circle::display_circle(BlackBoard& board)
{
board.DrawCircle(x, y, radius);
}
/***************************/
//直线类
class Line
{
int x1, y1, x2, y2;
public:
//默认构造函数
Line()
{
x1 = 0;
y1 = 0;
x2 = 0;
y2 = 0;
}
void input_line(std::istream& is);
void display_line(BlackBoard& board);
void print_line(std::ostream& out);
};
void Line::input_line(std::istream& is)
{
is >> x1 >> y1 >> x2 >> y2;
}
void Line::display_line(BlackBoard& board)
{
board.DrawLine(x1, y1, x2, y2);
}
void Line::print_line(std::ostream& out)
{
out << "Line{point1_X: " << x1 << ", point1_Y: " << y1;
out << ", point2_X: " << x2 << ", point2_Y: " << y2;
out << "}" << std::endl;
}
/*********************************************/
//矩形类
class Rectangle
{
private:
int left, right, top, bottom;
public:
//默认构造函数
Rectangle()
{
left = 0;
right = 0;
top = 0;
bottom = 0;
}
void input_rectangle(std::istream& is);
void display_rectangle(BlackBoard& board);
void print_rectangle(std::ostream& out);
};
void Rectangle::input_rectangle(std::istream& is)
{
is >> left >> top >> right >> bottom;
}
void Rectangle::print_rectangle(std::ostream& out)
{
out << "Rectangle{left: " << left << ", top: ";
out << top << ", right: " << right << ", bottom: " << bottom << "}" << std::endl;
}
void Rectangle::display_rectangle(BlackBoard& board)
{
board.DrawLine(left, top, right, top);
board.DrawLine(left, top, left, bottom);
board.DrawLine(left, bottom, right, bottom);
board.DrawLine(right, top, right, bottom);
}
/*******************************************/
//一个继承圆类、直线类、矩形类的子类Shape
class Shape :public Circle, public Line, public Rectangle
{
//Shape类只有构造函数和flag
public:
//确定输入圆还是其他的
int flag;
public:
//默认构造函数,坐标值全部赋为0,flag为0
Shape():Circle(),Line(),Rectangle()
{
flag = 0;
}
};
/******************************************/
class FigureManager
{
private:
Shape p[11];
//确定数目
int count;
public:
//默认构造函数
FigureManager();
static FigureManager &handle()
{
static FigureManager manager;
return manager;
}
// FigureManager类析构函数
virtual ~FigureManager() {}
// FigureManager类接口.
public:
void input(std::istream& is);
void display(BlackBoard& board);
void print(std::ostream& out);
}; // class FigureManager类定义结束.
FigureManager::FigureManager()
{
count = 0;
}
void FigureManager::input(std::istream& is)
{
while (is>>p[count].flag )
{
if (p[count].flag == 0)//退出循环
break;
if (p[count].flag == 1)//圆
{
p[count].input_circle(std::cin);
count++;
}
else if (p[count].flag == 2)//线
{
p[count].input_line(std::cin);
count++;
}
else if (p[count].flag == 3)//矩形
{
p[count].input_rectangle(std::cin);
count++;
}
}
}
void FigureManager::display(BlackBoard& board)
{
for (int i = 0; i < count; i++)
{
if (p[i].flag == 1)//圆
{
p[i].display_circle(board);
}
else if (p[i].flag == 2)//线
{
p[i].display_line(board);
}
else if (p[i].flag == 3)//矩形
{
p[i].display_rectangle(board);
}
}
}
void FigureManager::print(std::ostream& out)
{
for (int i = 0; i < count; i++)
{
if (p[i].flag == 1)//圆
{
p[i].print_circle(std::cout);
}
else if (p[i].flag == 2)//线
{
p[i].print_line(std::cout);
}
else if (p[i].flag == 3)//矩形
{
p[i].print_rectangle(std::cout);
}
}
}
/***************提交截止位置****************************************************************/
// 如果你的实现需要一些必要的初始化,可放在这个函数中,main函数会调用
// 如果没有,则忽略
void InitiateFigureManager()
{
}
/*********************************************************
* the code above is for 2D geometry manager.
* it is what you need to implement.
* !Notify: this is just a example class, it doesn't mean
* you don't need implement other class(es).
* Just implement the function in your free.
* ********************************************************/
/*********************************************************
* the code below is program main function.
* ********************************************************/
// 提供绘图环境的对象
BlackBoard board;
// 可忽略
void ReshapeCallback(int width, int height)
{
board.UpdateWindowSize(width, height);
}
// 窗口用于处理键盘输入的回调函数入口,这里只处理了一件事,按q退出程序,可忽略
// 注意,这里的键盘输入是窗口的键盘输入,而不是命令行的
void KeyboardCallback(unsigned char key, int x, int y)
{
switch (key)
{
case 'q':
exit(0);
break;
}
}
// 窗口用于绘制的回调函数入口,最终会调用FigureManager的display函数
// 本次作业无需改动DisplayCallback,绘制图形应在FigureManager中完成。
void DisplayCallback()
{
board.Clear();
FigureManager::handle().display(board);
board.Flush();
}
int main(int argc, char *argv[])
{
// 如果你的实现需要一些必要的初始化,可放在这个函数中,main函数会调用
// 如果没有,则忽略
InitiateFigureManager();
// 这里可切换输入方式:
// 1、从test.txt文件输入,以方便调试时键盘输入费时。
// 2、从命令行输入,以帮助在没有完全编写好代码时,无法用test.txt测试
#if 0
std::ifstream input("test.txt");
if (!input.is_open())
{
std::cout << "Error opening input file";
exit(1);
}
FigureManager::handle().input(input);
#else
FigureManager::handle().input(std::cin);
#endif
// 以下代码用于初始化窗口等、可忽略
board.InitCommandLine(&argc, (char **)argv);
board.InitWindowSize(1000, 800);
board.InitDisplayCallback(DisplayCallback);
board.InitKeyboardCallback(KeyboardCallback);
board.InitReshapeCallback(ReshapeCallback);
FigureManager::handle().print(std::cout);
board.Show();
return 0;
}
运行结果
用vector实现
- Vector实现仅仅是对FigrureManager类进行了一点改动
- 目的是练习使用vector,及用iterator进行遍历
- 代码如下
/*********Vector实现*************************/
//圆类
class Circle
{
private:
int x, y, radius;
public:
//默认构造函数
Circle()
{
x = 0;
y = 0;
radius = 0;
}
void input_circle(std::istream& is);
void display_circle(BlackBoard& board);
void print_circle(std::ostream& out);
};
void Circle::input_circle(std::istream& is)
{
is >> x >> y >> radius;
}
void Circle::print_circle(std::ostream& out)
{
out << "Circle{center_X: " << x;
out << ", center_Y: " << y;
out << ", radius: " << radius << "}" << std::endl;
}
void Circle::display_circle(BlackBoard& board)
{
board.DrawCircle(x, y, radius);
}
/***************************/
//直线类
class Line
{
int x1, y1, x2, y2;
public:
//默认构造函数
Line()
{
x1 = 0;
y1 = 0;
x2 = 0;
y2 = 0;
}
void input_line(std::istream& is);
void display_line(BlackBoard& board);
void print_line(std::ostream& out);
};
void Line::input_line(std::istream& is)
{
is >> x1 >> y1 >> x2 >> y2;
}
void Line::display_line(BlackBoard& board)
{
board.DrawLine(x1, y1, x2, y2);
}
void Line::print_line(std::ostream& out)
{
out << "Line{point1_X: " << x1 << ", point1_Y: " << y1;
out << ", point2_X: " << x2 << ", point2_Y: " << y2;
out << "}" << std::endl;
}
/*********************************************/
//矩形类
class Rectangle
{
private:
int left, right, top, bottom;
public:
//默认构造函数
Rectangle()
{
left = 0;
right = 0;
top = 0;
bottom = 0;
}
void input_rectangle(std::istream& is);
void display_rectangle(BlackBoard& board);
void print_rectangle(std::ostream& out);
};
void Rectangle::input_rectangle(std::istream& is)
{
is >> left >> top >> right >> bottom;
}
void Rectangle::print_rectangle(std::ostream& out)
{
out << "Rectangle{left: " << left << ", top: ";
out << top << ", right: " << right << ", bottom: " << bottom << "}" << std::endl;
}
void Rectangle::display_rectangle(BlackBoard& board)
{
board.DrawLine(left, top, right, top);
board.DrawLine(left, top, left, bottom);
board.DrawLine(left, bottom, right, bottom);
board.DrawLine(right, top, right, bottom);
}
/*******************************************/
//一个继承圆类、直线类、矩形类的子类Shape
class Shape :public Circle, public Line, public Rectangle
{
//Shape类只有构造函数和flag
public:
//确定输入圆还是其他的
int flag;
public:
//默认构造函数,坐标值全部赋为0,flag为0
Shape() :Circle(), Line(), Rectangle()
{
flag = 0;
}
};
/******************************************/
class FigureManager
{
private:
//定义Shape类的向量
vector<Shape> p;
//Shape类的对象,用于输入
Shape temp;
//注意,vectro<Shape>的调用是不需要长度计数的,引用时直接调用迭代器vector库的iterator
public:
//默认构造函数
FigureManager();
static FigureManager& handle()
{
static FigureManager manager;
return manager;
}
// FigureManager类析构函数
virtual ~FigureManager() {}
// FigureManager类接口.
public:
void input(std::istream& is);
void display(BlackBoard& board);
void print(std::ostream& out);
}; // class FigureManager类定义结束.
FigureManager::FigureManager()
{
}
void FigureManager::input(std::istream& is)
{
while (is >> temp.flag)
{
if (temp.flag == 0)//退出循环
break;
if (temp.flag == 1)//圆
{
//输入圆
temp.input_circle(std::cin);
//输入的对象进入vector
p.push_back(temp);
}
else if (temp.flag == 2)//线
{
//输入线
temp.input_line(std::cin);
//输入的对象进入vector p
p.push_back(temp);
}
else if (temp.flag == 3)//矩形
{
//输入矩形
temp.input_rectangle(std::cin);
//输入的矩形进入vector p
p.push_back(temp);
}
}
}
void FigureManager::display(BlackBoard& board)
{
for (vector<Shape>::iterator it=p.begin();it<p.end();++it)
{
if ((*it).flag == 1)//圆
{
//显示圆
(*it).display_circle(board);
}
else if ((*it).flag == 2)//线
{
//显示线
(*it).display_line(board);
}
else if ((*it).flag == 3)//矩形
{
//显示矩形
(*it).display_rectangle(board);
}
}
}
void FigureManager::print(std::ostream& out)
{
for (vector<Shape>::iterator it = p.begin(); it < p.end(); ++it)
{
if ((*it).flag == 1)//圆
{
//显示圆
(*it).print_circle(std::cout);
}
else if ((*it).flag == 2)//线
{
//显示线
(*it).print_line(std::cout);
}
else if ((*it).flag == 3)//矩形
{
//显示矩形
(*it).print_rectangle(std::cout);
}
}
}
/***************截止位置*****************************/
用抽象类实现
- 仅仅改了类的定义和使用
- 代码如下
/****************虚函数实现***************************/
//抽象类,基类Shape
class Shape
{
//Shape类只有纯虚函数
public:
virtual void input(std::istream& is) = 0;
virtual void display(BlackBoard& board) = 0;
virtual void print(std::ostream& out) = 0;
};
/********************************************/
//圆类
class Circle:public Shape
{
private:
int x, y, radius;
public:
//默认构造函数
Circle()
{
x = 0;
y = 0;
radius = 0;
}
virtual void input(std::istream& is);
virtual void display(BlackBoard& board);
virtual void print(std::ostream& out);
};
void Circle::input(std::istream& is)
{
is >> x >> y >> radius;
}
void Circle::print(std::ostream& out)
{
out << "Circle{center_X: " << x;
out << ", center_Y: " << y;
out << ", radius: " << radius << "}" << std::endl;
}
void Circle::display(BlackBoard& board)
{
board.DrawCircle(x, y, radius);
}
/***************************/
//直线类
class Line :public Shape
{
int x1, y1, x2, y2;
public:
//默认构造函数
Line()
{
x1 = 0;
y1 = 0;
x2 = 0;
y2 = 0;
}
virtual void input(std::istream& is);
virtual void display(BlackBoard& board);
virtual void print(std::ostream& out);
};
void Line::input(std::istream& is)
{
is >> x1 >> y1 >> x2 >> y2;
}
void Line::display(BlackBoard& board)
{
board.DrawLine(x1, y1, x2, y2);
}
void Line::print(std::ostream& out)
{
out << "Line{point1_X: " << x1 << ", point1_Y: " << y1;
out << ", point2_X: " << x2 << ", point2_Y: " << y2;
out << "}" << std::endl;
}
/*********************************************/
//矩形类
class Rectangle :public Shape
{
private:
int left, right, top, bottom;
public:
//默认构造函数
Rectangle()
{
left = 0;
right = 0;
top = 0;
bottom = 0;
}
virtual void input(std::istream& is);
virtual void display(BlackBoard& board);
virtual void print(std::ostream& out);
};
void Rectangle::input(std::istream& is)
{
is >> left >> top >> right >> bottom;
}
void Rectangle::print(std::ostream& out)
{
out << "Rectangle{left: " << left << ", top: ";
out << top << ", right: " << right << ", bottom: " << bottom << "}" << std::endl;
}
void Rectangle::display(BlackBoard& board)
{
board.DrawLine(left, top, right, top);
board.DrawLine(left, top, left, bottom);
board.DrawLine(left, bottom, right, bottom);
board.DrawLine(right, top, right, bottom);
}
/******************************************/
class FigureManager
{
private:
//定义Shape类的向量
Shape* p[100];
//计数用
int count;
public:
//默认构造函数
FigureManager();
static FigureManager& handle()
{
static FigureManager manager;
return manager;
}
// FigureManager类析构函数
virtual ~FigureManager() {}
// FigureManager类接口.
public:
void input(std::istream& is);
void display(BlackBoard& board);
void print(std::ostream& out);
}; // class FigureManager类定义结束.
FigureManager::FigureManager()
{
count = 0;
}
void FigureManager::input(std::istream& is)
{
int flag;
while (std::cin >> flag)
{
if (flag == 1)//代表圆
{
p[count] = new Circle;
p[count]->input(std::cin);
count++;
}
if (flag == 2)//代表直线
{
p[count] = new Line;
p[count]->input(std::cin);
count++;
}
if (flag == 3)//代表方形
{
p[count] = new Rectangle;
p[count]->input(std::cin);
count++;
}
if (flag == 0)
break;//退出,停止输入
}
}
void FigureManager::display(BlackBoard& board)
{
for (int i = 0; i < count; i++)
{
p[i]->display(board);
}
}
void FigureManager::print(std::ostream& out)
{
for (int i = 0; i < count; i++)
{
p[i]->print(std::cout);
}
}
/***************提交截止位置****************************************************************/