注意的几点:
1 链表做.缩放窗口不消失是因为OnDraw函数中遍历链表重绘,这也是所有绘制都放在OnDraw函数中的原因.
2 引用变量的使用.
3.实现效果如下(刚学的,下了个licecap.可制作gif),需要缩放窗口才能剪裁(其实是在刷新窗口):
先附上代码,有时间会解析(只要不出错,大概率不会解析):
1 View头文件:
//文件名是LineClipping //头文件中添加的代码 public: int menu; bool flag;//判断单击鼠标画出的是第一个端点还是第二个端点 struct PL* SavePoint;//建立存储结构体的链表 struct PL* p;//辅助建立存储结构体的链表 bool draw;//判断画出的线段是否需要剪裁 //创建矩形裁剪 double xmin, xmax;//左上角 double ymin, ymax;//右下角 //Cohen剪裁用到的函数 char CLineClippingView::EnCode(float px, float py);//确定点的编码 bool CLineClippingView::CohenSutherland(CPoint &p1, CPoint &p2); //LiangBarsky剪裁用到的函数 //double CLineClippingView::Max(double a, double b); //double CLineClippingView::Min(double a, double b); void CLineClippingView::exchange(CPoint &p1, CPoint &p2);//交换 bool CLineClippingView::LiangBarsky(CPoint &p1, CPoint &p2); bool CLineClippingView::LbUnEqual(CPoint &p1, CPoint &p2);//deltax,deltay都不等于零
2 源文件中的代码:
2.1 构造函数:
//构造函数中的初始化
CLineClippingView::CLineClippingView()
{
// TODO: 在此处添加构造代码
flag = true;
menu = 0;
draw = false;
xmin = 100;
xmax = 500;
ymin = 100;
ymax= 500;
p = NULL;
SavePoint = (struct PL*)malloc(sizeof(PL));
SavePoint->next = NULL;
2.2 OnDraw函数
void CLineClippingView::OnDraw(CDC* pDC)
{
CLineClippingDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
//绘制矩形窗口
pDC->Rectangle(xmin, ymin, xmax, ymax);
struct PL* traverse;
traverse = SavePoint->next;
while(traverse)
{
//点击完菜单后需要放缩一下窗口,刷新一下,才能显示剪裁后的结果
//CohenSutherland
if(menu == 2)
{
if(CohenSutherland(traverse->pointa, traverse->pointb))
{
pDC->MoveTo(traverse->pointa);
pDC->LineTo (traverse->pointb);
}
}
//LiangBarsky
if(menu == 3)
{
if(LiangBarsky(traverse->pointa, traverse->pointb))
{
pDC->MoveTo(traverse->pointa);
pDC->LineTo (traverse->pointb);
}
}
if(menu == 0)
{
pDC->MoveTo(traverse->pointa);
pDC->LineTo (traverse->pointb);
}
traverse = traverse->next;
}
free(traverse);
}
2.3 Cohen-Sutherland算法
//赋值编码函数
char CLineClippingView::EnCode(float px, float py)
{
unsigned char code = 0;
if(px < xmin) code = code | LEFT_EDGE;
else if(px > xmax) code = code | RIGHT_EDGE;
if(py > ymax) code = code | BOTTOM_EDGE;
else if(py < ymin) code = code | TOP_EDGE;
return code;
}
//Cohen-Sutherland
bool CLineClippingView::CohenSutherland(CPoint &p1, CPoint &p2)//注意用的是引用变量
{
int x, y;
bool finish, draw;
int code1, code2, code;
finish = false;
draw = false;
while(!finish)
{
code1 = EnCode(p1.x, p1.y);
code2 = EnCode(p2.x, p2.y);
//if判断完全可见,else判断完全不可见
if((code1 == 0) && (code2 == 0))
{
finish = true;
draw = true;
}
else if(code1 & code2)
{
finish = true;
draw = false;
}
//分段
else
{
//code是不可见点的编码
if(code1 != 0)
code = code1;
else
code = code2;
//求交处理
if ((LEFT_EDGE & code)!=0)
{
x = xmin;
y = p1.y + (p2.y - p1.y)*(xmin - p1.x) / (p2.x - p1.x);
}
else if ((RIGHT_EDGE & code)!=0)
{
x = xmax;
y = p1.y + (p2.y - p1.y)*(xmax - p1.x) / (p2.x - p1.x);
}
else if ((BOTTOM_EDGE & code)!=0)
{
y = ymax;
x = p1.x + (p2.x - p1.x)*(ymax - p1.y) / (p2.y - p1.y);
}
else if ((TOP_EDGE & code)!=0)
{
y = ymin;
x = p1.x + (p2.x - p1.x)*(ymin - p1.y) / (p2.y - p1.y);
}
if (code == code1)
{
p1.x = x; p1.y = y; code1 = EnCode(p1.x, p1.y);
}
else
{
p2.x = x; p2.y = y; code2 = EnCode(p2.x, p2.y);
}
}
}
return draw;
CDC *pDC = GetDC();
OnDraw(pDC);
ReleaseDC(pDC);
}
2.4Liang-Brasky
//交换
void CLineClippingView::exchange(CPoint &p1, CPoint &p2)
{
CPoint p;
p = p1;
p1 = p2;
p2 = p;
}
//deltax, deltay都不为零的情况
bool CLineClippingView::LbUnEqual(CPoint &p1, CPoint &p2)
{
double deltax, deltay;
double tmax, tmin;
deltax = p2.x - p1.x;
deltay = p2.y - p1.y;
if((deltax>0) && (deltay>0))
{
tmax = min(1, min((xmax-p1.x)/deltax, (ymax-p1.y)/deltay));
tmin = max(0, max((xmin-p1.x)/deltax, (ymin-p1.y)/deltay));
}
else if((deltax>0) && (deltay<0))
{
tmax = min(1, min((xmax-p1.x)/deltax, (ymin-p1.y)/deltay));
tmin = max(0, max((xmin-p1.x)/deltax, (ymax-p1.y)/deltay));
}
if(tmin < tmax)
{
p1.x = deltax * tmin + p1.x;
p1.y = deltay * tmin + p1.y;
p2.x = deltax * tmax + p1.x;
p2.y = deltay * tmax + p1.y;
draw = true;
}
else
{
draw = false;
}
return(draw);
}
bool CLineClippingView::LiangBarsky(CPoint &p1, CPoint &p2)
{
double deltax;
double deltay;
draw = false;
deltax = p2.x - p1.x;
deltay = p2.y - p1.y;
if((deltax>0) && (deltay>0))
{
return(LbUnEqual(p1, p2));
}
else if((deltax<0) && (deltay<0))
{
exchange(p1, p2);
return(LbUnEqual(p1, p2));
}
else if((deltax>0) && (deltay<0))
{
return(LbUnEqual(p1, p2));
}
else if((deltax<0) && (deltay>0))
{
exchange(p1, p2);
return(LbUnEqual(p1, p2));
}
//deltax = 0
else if(deltax == 0)
{
if((xmin > p1.x) || (xmax < p1.x))
draw = false;
else
{
p2.y = max(ymin, max(p1.y, p2.y));
p1.y = min(ymax, min(p1.y, p2.y));
if(p1.y < p2.y)
draw = true;
else
draw = false;
}
}
//deltay = 0
else if(deltay == 0)
{
if((ymin > p1.y) || (ymax < p1.y))
draw = false;
else
{
p2.x = max(xmin, max(p1.x, p2.x));
p1.x = min(xmax, min(p1.x, p2.x));
if(p1.x < p2.x)
draw = true;
else
draw = false;
}
}
}
2.5响应函数.2.5节代码看不懂的话看前两篇.
void CLineClippingView::OnWindow()
{
// TODO: 在此添加命令处理程序代码
menu = 1;
MessageBox(L"鼠标左键单击两次建立矩形窗口");
}
void CLineClippingView::OnCohen()
{
// TODO: 在此添加命令处理程序代码
menu = 2;
MessageBox(L"进行Cohen-Sutherland裁剪");
}
void CLineClippingView::OnLiang()
{
// TODO: 在此添加命令处理程序代码
menu = 3;
MessageBox(L"进行Liang-Barsky裁剪");
}
void CLineClippingView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(flag)
{
p = (struct PL*)malloc(sizeof(PL));
p->pointa = point;
}
else
{
p->pointb = point;
p->next = SavePoint->next;
SavePoint->next = p;
}
flag = !flag;
CDC *pDC = GetDC();
OnDraw(pDC);
ReleaseDC(pDC);
CView::OnLButtonDown(nFlags, point);
}



