图形学作业 带宽度的直线绘制 C++实现

#include<iostream>
#include<graphics.h>
#include<conio.h>
#include<cmath>
#include<windows.h>
#define PI 3.1415926
using namespace std;

//优化后的Bresenham算法,能够处理斜率不存在,斜率为负数,斜率绝对值大于一等情况,并且可以根据需要自动调整两点顺序,具有良好的通用性
//使用只需要输入两点的横纵坐标值即可
void Bresenham(const int& x1, const int& y1, const int& x2, const int& y2)
{
	int dx = x2 - x1, dy = y2 - y1;
	enum MainChangeDirection { x, y };//用一个枚举变量记录直线的主要变化方向(x方向或者y方向)
	MainChangeDirection Direction;
	if (abs(dx) >= abs(dy))
		Direction = x;
	else Direction = y;
	if ((Direction == x && x1 > x2) || (Direction == y && y1 > y2))//如果在主要变化方向上的次序相反了,则递归调用自身即可
	{
		Bresenham(x2, y2, x1, y1);
		return;
	}

	if (dx == 0)//处理斜率不存在的特殊情况
	{
		for (int y = y1; y <= y2; ++y)
		{
			putpixel(x1, y, RED);
		}
		Sleep(1);
		return;
	}


	double k = double(dy) / dx;
	if (Direction == x)//处理主要变化方向为x轴的情况
	{
		int x = x1, y = y1;
		if (k >= 0)//主要变化方向为x轴并且斜率大于等于零
		{
			int e = -dx;
			for (; x <= x2; ++x)
			{
				putpixel(x, y, RED);
				e += 2 * dy;
				if (e > 0)
				{
					y++;
					e -= 2 * dx;
				}
			}
		}
		else if (k < 0)//主要变化方向为x轴且斜率小于零
		{
			int e = dx;
			for (; x <= x2; ++x)
			{
				putpixel(x, y, RED);
				e += 2 * dy;
				if (e <= 0)
				{
					y--;
					e += 2 * dx;
				}
			}
		}
	}
	else if (Direction == y)
	{
		int y = y1, x = x1;
		if (k >= 0)//主要变化方向为y轴方向并且斜率大于等于零
		{
			int e = -dy;
			for (; y <= y2; ++y)
			{
				putpixel(x, y, RED);
				e += 2 * dx;
				if (e > 0)
				{
					x++;
					e -= 2 * dy;
				}
			}
		}
		else if (k < 0)//主要变化方向为y轴方向并且斜率小于零
		{
			int e = dy;
			for (; y <= y2; ++y)
			{
				putpixel(x, y, RED);
				e += 2 * dx;
				if (e <= 0)
				{
					x--;
					e += 2 * dy;
				}
			}
		}
	}
	Sleep(1);
	return;
}

void WideLine(const int& x1, const int& y1, const int& x2, const int& y2, const int& width)
{
	int dx = x2 - x1, dy = y2 - y1;
	enum MainChangeDirection { x, y };//用一个枚举变量记录直线的主要变化方向(x方向或者y方向)
	MainChangeDirection Direction;
	if (abs(dx) >= abs(dy))
		Direction = x;
	else Direction = y;
	if ((Direction == x && x1 > x2) || (Direction == y && y1 > y2))//如果在主要变化方向上的次序相反了,则递归调用自身即可
	{
		WideLine(x2, y2, x1, y1, width);
		return;
	}

	int mid_width = width >> 1;
	if (dx == 0)//处理斜率不存在的特殊情况
	{
		for (int y = y1; y <= y2; ++y)
		{
			Bresenham(x1 - mid_width, y, x1 + mid_width, y);
		}
		return;
	}
	if (dy == 0)//处理斜率为零的特殊情况
	{
		for (int x = x1; x <= x2; x++)
		{
			Bresenham(x, y1 - mid_width, x, y1 + mid_width);
		}
		return;
	}


	double k = double(dy) / dx;
	if (Direction == x)//处理主要变化方向为x轴的情况
	{
		int x = x1, y = y1;
		if (k >= 0)//主要变化方向为x轴并且斜率大于等于零
		{
			int e = -dx;
			for (; x <= x2; ++x)
			{
				int x_range = fabs(cos(atan(k))) * mid_width;
				int y_range = fabs(sin(atan(k))) * mid_width;
				int start_x, start_y, end_x, end_y;
				start_x = x - x_range;
				end_x = x + x_range;
				start_y = y + y_range;
				end_y = y - y_range;
				Bresenham(start_x, start_y, end_x, end_y);
				e += 2 * dy;
				if (e > 0)
				{
					y++;
					e -= 2 * dx;
				}
			}
		}
		else if (k < 0)//主要变化方向为x轴且斜率小于零
		{
			int e = dx;
			for (; x <= x2; ++x)
			{

				int x_range = fabs(cos(atan(k) + PI / 2)) * mid_width;
				int y_range = fabs(sin(atan(k) + PI / 2)) * mid_width;
				int start_x, start_y, end_x, end_y;
				start_x = x - x_range;
				end_x = x + x_range;
				start_y = y - y_range;
				end_y = y + y_range;
				Bresenham(start_x, start_y, end_x, end_y);
				e += 2 * dy;
				if (e <= 0)
				{
					y--;
					e += 2 * dx;
				}
			}
		}
	}
	else if (Direction == y)
	{
		int y = y1, x = x1;
		if (k >= 0)//主要变化方向为y轴方向并且斜率大于等于零
		{
			int e = -dy;
			for (; y <= y2; ++y)
			{

				int x_range = fabs(cos(atan(k))) * mid_width;
				int y_range = fabs(sin(atan(k))) * mid_width;
				int start_x, start_y, end_x, end_y;
				start_x = x - x_range;
				end_x = x + x_range;
				start_y = y + y_range;
				end_y = y - y_range;
				Bresenham(start_x, start_y, end_x, end_y);
				e += 2 * dx;
				if (e > 0)
				{
					x++;
					e -= 2 * dy;
				}
			}
		}
		else if (k < 0)//主要变化方向为y轴方向并且斜率小于零
		{
			int e = dy;
			for (; y <= y2; ++y)
			{

				int x_range = fabs(cos(atan(k))) * mid_width;
				int y_range = fabs(sin(atan(k))) * mid_width;
				int start_x, start_y, end_x, end_y;
				start_x = x - x_range;
				end_x = x + x_range;
				start_y = y + y_range;
				end_y = y - y_range;
				Bresenham(start_x, start_y, end_x, end_y);
				if (e <= 0)
				{
					x--;
					e += 2 * dy;
				}
			}
		}
	}
	return;
}

//以下是用来衔接两带宽度直线的“转弯”算法,相当于在指定点以半宽度作一个圆
void Turning(const int& x, const int& y, const int& width)
{
	int mid_width = width / 2;
	double angle;
	int dx, dy;
	for (double i = 0; i <= 360; i++)
	{
		angle = i / 180 * PI;
		dx = cos(angle) * mid_width;
		dy = sin(angle) * mid_width;
		Bresenham(x, y, x + dx, y + dy);
	}
}

//这是本次实验的核心函数,对于任意两个点,先判断是否需要进行转向,之后连接下一个点
void Draw_WideLines(const int* x, const int* y, const int& n, const int& width)
{
	initgraph(800, 640);
	for (int i = 0; i < n - 1; i++)
	{
		if (i != 0)
		{
			Turning(x[i], y[i], width);
		}
		WideLine(x[i], y[i], x[i + 1], y[i + 1], width);
	}
	_getch();
	closegraph();
}

int main(void)
{
	while (true)
	{
		int cmd;
		cout << "输入1开始程序,输入2退出程序:" << endl;
		cin >> cmd;
		if (cmd == 2)
		{
			cout << "程序已经退出" << endl;
			break;
		}
		cout << "绘图程序开始..." << endl;
		int num;
		cout << "请输入点的个数:";
		cin >> num;
		int* xArray = new int[num];
		int* yArray = new int[num];
		cout << "请输入这些点的横坐标:" << endl;
		for (int i = 0; i < num; i++)
		{
			cin >> xArray[i];
		}
		cout << "请输入这些点的纵坐标:" << endl;
		for (int i = 0; i < num; i++)
		{
			cin >> yArray[i];
		}
		int width;
		cout << "请输入线条的宽度:";
		cin >> width;
		cout << "参数已经确认,按任意键可开始绘图,绘图结束后按任意键可以返回..." << endl;
		_getch();
		Draw_WideLines(xArray, yArray, num, width);		
	}
	return 0;
}

注:头文件的库中<graphics.h>需要自行免费下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值