图形学-二维图形的裁剪1.Cohen 2.Liang

这篇博客介绍了如何使用C++实现图形类CP2,并在View类中定义了DrawClipWindow函数进行矩形区域的绘制。同时,文章详细阐述了直线裁剪算法,包括编码函数EnCode和裁剪函数ClipTest,用于处理直线与窗口边界的关系,实现了对直线的裁剪操作。此外,还展示了在鼠标点击事件中如何更新直线并进行裁剪显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Cohen

  1. 创建新类CP2
	class CP2  
	{
	public:
		CP2();
		virtual ~CP2();
	public:
		double x;
		double y;
		UINT rc;
	};
  1. 右键view类,添加如下几个全局变量。(前面类型,后面名称)
    CP2 p0; CP2 p1; double wyt; double wxr; double wyb; double wxl;
  2. 在构造函数给后面四个变量赋初始值(可以改一改数值)。
	wxl=300,wyb=100,wxr=500,wyt=200;
  1. 在view类中创建函数
    DrawClipWindow(CDC *pDC)中的函数代码为:
	CRect rect(wxl,wyb,wxr,wyt);
	pDC->Rectangle(rect);
  1. 在.cpp文件include“P2.h”,引入刚才第一步创建的类。

  2. 然后在OnDraw()函数里面调用。

	DrawClipWindow(pDC);
  1. 鼠标传值:
	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);

  1. view类添加全局变量flag,在构造函数初始值为0.
  2. 创建编码函数Encode(CP2 &pt)
	这些放在整个文件的最上面:
	#define LEFT 0x1    //代表:0001
	#define RIGHT 0x2    //代表:0010
	#define BOTTOM 0x4   //代表:0100
	#define TOP 0x8   //代表:1000
	
	Encode函数代码:
	void CMy1112View::EnCode(CP2 &pt)
	{
	pt.rc=0;
	if(pt.x<wxl)
	     pt.rc=pt.rc | LEFT;
	else if(pt.x>wxr)
	     pt.rc=pt.rc | RIGHT;
	if(pt.y<wyb)
	     pt.rc=pt.rc | BOTTOM;
	else if(pt.y>wyt)
	     pt.rc=pt.rc | TOP; 
	}

  1. 创建一个裁剪菜单,类向导为:
	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);

LB

  1. 右键ClipeTest()函数,代码:
	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<tmax)
	ReturnValue=FALSE;
	else if(t<tmin)
	tmin=t;
	}
	else//平行于窗口边界的直线
	{
	if(v<0.0)//直线在窗口外可直接删除
	ReturnValue=FALSE;
	}
	}
	return(ReturnValue);

  1. 菜单LB裁剪函数:
	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);
		}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值