#include<iostream>
#include<graphics.h>
#include<conio.h>
using namespace std;
//分别用四个符号常量记录四个边界的编号,相当于C语言中的define宏定义
const unsigned TOP = 8;
const unsigned BOTTOM = 4;
const unsigned RIGHT = 2;
const unsigned LEFT = 1;
static unsigned xl, yb, xr, yt;
unsigned short Region_Coding(const unsigned& x, const unsigned& y)
{
unsigned short coding = 0;
if (y > yt)
coding += 8;
else if (y < yb)
coding += 4;
if (x > xr)
coding += 2;
else if (x < xl)
coding += 1;
return coding;
}
void CS_LineClip(const unsigned& x1, const unsigned& y1, const unsigned& x2, const unsigned& y2)
{
unsigned p1, p2;
//通过区域码函数分别求出两个点的区域码
p1 = Region_Coding(x1, y1);
p2 = Region_Coding(x2, y2);
//第一种情况:两点的区域码均在窗口内部,则直接画出该直线即可
if (p1 == 0 && p2 == 0)
{
line(x1, y1, x2, y2);
return;
}
//第二种情况,两点的区域码均不在窗口内部,则不绘制任何直线
else if ((p1 & p2) != 0)
{
return;
}
//第三种情况:即排除之前两种情况后的剩余情况,此时进行分类讨论
else
{
//首先处理斜率不存在的特殊情况,该情况下可以直接画出线
if ((x1 == x2 && y1 <= yb && y2 >= yt) || (x1 == x2 && y1 >= yt && y2 <= yb))
{
line(x1, yb, x2, yt);
return;
}
//求出直线的斜率。注意:此处一定要用到类型转换!否则求出的斜率很可能存在异常
double k = (double(y2) - double(y1)) / (double(x2) - double(x1));
if ((p1 & LEFT) != 0)//由于已经使得两点的横坐标升序排列,因此如果左边点在左边界的左边的话,则求出直线与左边界的交点,以交点代替第一个点递归执行函数
{
unsigned New_y1 = unsigned(k * (xl - x1) + y1 + 0.5);
CS_LineClip(xl, New_y1, x2, y2);
return;
}
if ((p2 & RIGHT) != 0)//运行到此处时直线左端点一定在左边界上或左边界的右边,此时对右端点进行类似检查:如果右端点在右边界的右边,则取直线与右边界的交点。
{
unsigned New_y2 = unsigned(k * (xr - x1) + y1 + 0.5);
CS_LineClip(x1, y1, xr, New_y2);
return;
}
//剩下的情况中只包含两点横坐标均在左右边界之间,但是纵坐标不在上下边界内的情况,需要分斜率正负进行讨论
if (k >= 0)
{
if ((p2 & TOP) != 0)//斜率为正且右边的点在上边界以上时,求出直线与上边界的交点来代替上点,递归调用自身即可
{
unsigned New_x2 = unsigned(x1 + (yt - y1) / k + 0.5);
CS_LineClip(x1, y1, New_x2, yt);
return;
}
if ((p1 & BOTTOM) != 0)//斜率为正且左边的点在下边界以下时,求出直线与下边界的交点来代替下点,递归调用自身
{
unsigned New_x1 = unsigned(x1 + (yb - y1) / k + 0.5);
CS_LineClip(New_x1, yb, x2, y2);
return;
}
}
if (k < 0)//斜率小于零的情况进行类似讨论即可
{
if ((p1 & TOP) != 0)
{
unsigned New_x1 = unsigned(x1 + (yt - y1) / k + 0.5);
CS_LineClip(New_x1, yt, x2, y2);
return;
}
if ((p2 & BOTTOM) != 0)
{
unsigned New_x2 = unsigned(x1 + (yb - y1) / k + 0.5);
CS_LineClip(x1, y1, New_x2, yb);
return;
}
}
}
}
int main(void)
{
int x1, y1, x2, y2;
cout << "请分别输入原始直线两端点的横纵坐标:";
cin >> x1 >> y1 >> x2 >> y2;
cout << "请分别输入裁剪窗口左下角和右上角的横纵坐标:";
cin >> xl >> yb >> xr >> yt;
cout << "原始直线和裁剪窗口如下图所示:(按任意键查看,查看后按任意键裁剪)";
_getch();
initgraph(800, 640);
line(x1, y1, x2, y2);//通过之前学过的Bresenham方法进行画线操作
rectangle(xl, yt, xr, yb);
_getch();
closegraph();
initgraph(800, 640);
CS_LineClip(x1, y1, x2, y2);
rectangle(xl, yt, xr, yb);
_getch();
closegraph();
return 0;
}
备注:graphics.h包需要自行百度免费下载