新建一个文档命名为1124,文档类型为单文档。
创建CP2类
右键1124 classes,点击new class新建一个类CP2:
在CP2类中声明三个域:(double x;double y;UINT rc;)
找到cpp文件,在里面引用CP2这个类:(#include “P2.h”)
在CView类中新建两个CP2类型的变量p0、p1和四个成员变量(定义矩形的四个方向的边界):
(这四个边界变量用double、int都可以)
在构造函数中给这四个变量赋值。
CMy11122View::CMy11122View()
{
// TODO: add construction code here
wxl=-300,wyb=-100,wxr=300,wyt=100;
}
新建函数DrawClipWindow(CDC*pDC),用来画矩形。
void CMy11122View::DrawClipWindow(CDC*pDC)
{
CRect rect(wxl,wyb,wxr,wyt);
pDC->Rectangle(rect);
}
在OnDraw函数中调用画矩形函数
void CMy11122View::OnDraw(CDC* pDC)
{
CMy11122Doc* pDoc = Getdocument();
ASSERT_VALID(pDoc);
DrawClipWindow(pDC);//绘制裁剪窗口
// TODO: add draw code for native data here
}
增加鼠标点击函数:
-
新建成员变量flag(用来判断赋值给p0还是p1,以及画线)
-
在构造函数中将flag初始化为0
CMy11122View::CMy11122View()
{
// TODO: add construction code here
wxl=300,wyb=100,wxr=700,wyt=400;
flag=0;
}
3. 双击WM_LBUTTONDOWN添加该函数,点击Add and Edit编辑函数。
4. 在函数中编写如下代码:
void CMy11122View::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CDC*pDC=GetDC();
if(flag==0)
{
p0.x=point.x;
p0.y=point.y;
flag=1;
}
else
{
p1.x=point.x;
p1.y=point.y;
pDC->MoveTo(p0.x,p0.y);
pDC->LineTo(p1.x,p1.y);
flag=0;
}
CView::OnLButtonDown(nFlags, point);
}
创建编码函数:
#define LEFT 0x1 //代表:0001
#define RIGHT 0x2 //代表:0010
#define BOTTOM 0x4 //代表:0100
#define TOP 0x8 //代表:1000
void CMy1112View::EnCode(CP2 &pt)
{
pt.rc=0;
if(pt.xwxr)
pt.rc=pt.rc | RIGHT;
if(pt.ywyt)
pt.rc=pt.rc | TOP;
}
创建Cohen函数:
添加代码:(我用的方法是在函数开始时用白色画笔覆盖所画的线,再重画裁剪后得到的线)
void CMy11122View::OnCohen()
{
CDC*pDC=GetDC();
CPen NewPen,*pOldPen;
NewPen.CreatePen(PS_SOLID,1,RGB(255,255,255));
pOldPen=pDC->SelectObject(&NewPen);
pDC->MoveTo(p0.x,p0.y);
pDC->LineTo(p1.x,p1.y);
pDC->SelectObject(pOldPen);
// TODO: Add your command handler code here
CP2 p;//交点坐标
EnCode(p0);//起点编码
EnCode(p1);//终点编码
while(p0.rc!=0 || p1.rc!=0)//处理至少一个顶点在窗口外
{
if((p0.rc & p1.rc)!=0)//简弃之
{
return;
}
if(0==p0.rc)//确保p0位于窗口之外
{
CP2 Temp;
Temp=p0;
p0=p1;
p1=Temp;
}
UINT RC=p0.rc;
double k=(p1.y-p0.y)/(p1.x-p0.x);//斜率
if(RC & LEFT)//p0点位于窗口的左侧
{
p.x=wxl;//计算交点y坐标
p.y=k*(p.x-p0.x)+p0.y;
}
else if(RC & RIGHT)//p0点位于窗口的右侧
{
p.x=wxr;//计算交点y坐标
p.y=k*(p.x-p0.x)+p0.y;
}
else if(RC & BOTTOM)//p0点位于窗口的下侧
{
p.y=wyb;//计算交点x坐标
p.x=(p.y-p0.y)/k+p0.x;
}
else if(RC & TOP)//p0点位于窗口的上侧
{
p.y=wyt;//计算交点x坐标
p.x=(p.y-p0.y)/k+p0.x;
}
EnCode(p);
p0=p;
}
pDC->MoveTo(p0.x,p0.y);
pDC->LineTo(p1.x,p1.y);
}
为Cohen添加菜单函数:
-
在此处双击:
-
双击“帮助”后的空白处
-
编辑菜单属性
-
在空白处右键建立类向导:
点击Edit Code,将Cohen函数复制到OnCohen中来:
运行,用鼠标任意点两点,画线
点击裁剪:
裁剪多条直线效果(此方法只能画一条线裁剪一次):
梁友栋裁剪算法:
把EnCode和Cohen函数中的裁剪部分算法换成LBLineClip函数即可。
void CMy11122View::OnCohen()
{
CDC*pDC=GetDC();
CPen NewPen,*pOldPen;
NewPen.CreatePen(PS_SOLID,1,RGB(255,255,255));
pOldPen=pDC->SelectObject(&NewPen);
pDC->MoveTo(p0.x,p0.y);
pDC->LineTo(p1.x,p1.y);
pDC->SelectObject(pOldPen);
double tmax,tmin,dx,dy;
dx=p1.x-p0.x;dy=p1.y-p0.y;tmax=0.0,tmin=1.0;
if(ClipTest(-dx,p0.x-wxl,tmax,tmin)) //窗口边界的左、右、下、上顺序裁剪直线
{
if(ClipTest(dx,wxr-p0.x,tmax,tmin))
{
if(ClipTest(-dy,p0.y-wyb,tmax,tmin))
{
if(ClipTest(dy,wyt-p0.y,tmax,tmin))
{
if(tmin<1.0)//判断直线终点
{
p1.x=p0.x+tmin*dx;
p1.y=p0.y+tmin*dy;
}
if(tmax>0.0)//判断直线的起点
{
p0.x=p0.x+tmax*dx;
p0.y=p0.y+tmax*dy;
}
}
}
}
}
pDC->MoveTo(p0.x,p0.y);
pDC->LineTo(p1.x,p1.y);
}
BOOL CMy11122View::ClipTest(double u,double v,double &tmax,double &tmin)//裁剪测试函数
{
double t;
BOOL ReturnValue=TRUE;
if(u<0.0)//从裁剪窗口的外部到内部,计算起点处的tmax
{
t=v/u;
if(t>tmin)
ReturnValue=FALSE;
else if(t>tmax)
tmax=t;
}
else
{
if(u>0.0)//从裁剪窗口的内部到外部,计算终点处的tmin
{
t=v/u;
if(t


