基于MFC的线段裁剪算法的实现

基于MFC的线段裁剪算法的实现

一、新建MFC项目

此处就不再赘述,没有 M F C MFC MFC基础的可以先看第一个 M F C MFC MFC程序。

项目名为 L i n e c l i p p i n g Lineclipping Lineclipping

二、宏定义设置

在适当位置设置宏。

#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8
#define XL 100
#define XR 300
#define YT 100
#define YB 250

三、全局变量初始化

const UINT N = 8;
CPoint ptset[N];
int flag = 0;

四、窗口初始化

void CLineclippingView::OnDraw(CDC* pDC)
{
	CLineclippingDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	CPen newpen(PS_SOLID, 1, RGB(0, 0, 0));
	CPen *old = pDC->SelectObject(&newpen);
	pDC->Rectangle(CRect(XL, YT, XR, YB));
	ptset[0] = CPoint(120, 150);
	ptset[1] = CPoint(170, 110);
	ptset[2] = CPoint(0, 190);
	ptset[3] = CPoint(350, 150);
	ptset[4] = CPoint(0, 250);
	ptset[5] = CPoint(150, 230);
	ptset[6] = CPoint(200, 50);
	ptset[7] = CPoint(120, 150);
	pDC->TextOutW(0, 20, L"双击鼠标左键,出现要剪切的线段");
	pDC->SelectObject(old);
}

五、线段初始化

类向导添加消息中的 W M _ L B U T T O N D B L C L K WM\_LBUTTONDBLCLK WM_LBUTTONDBLCLK处理程序。

void CLineclippingView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CDC *pDC = GetDC();
	CPen newpen(PS_SOLID, 1, RGB(255, 0, 0));
	CPen *old = pDC->SelectObject(&newpen);
	flag = 1;
	for (int i = 0; i < N; i++) {
		pDC->MoveTo(ptset[i]);
		pDC->LineTo(ptset[i + 1]);
		i++;
	}
	CView::OnLButtonDblClk(nFlags, point);
}

六、线段裁剪算法实现

设置 I D ID ID I D _ C l i p l i n e ID\_Clipline ID_Clipline,添加事件处理函数 O n C l i p l i n e ( ) OnClipline() OnClipline()

void CLineclippingView::OnClipline()
{
	// TODO: 在此添加命令处理程序代码
	CDC * pDC = GetDC();
	CPen newpen(PS_SOLID, 1, RGB(255, 0, 0));
	CPen *old = pDC->SelectObject(&newpen);
	if (flag != 1) {
		MessageBox(L"请先双击鼠标左击", L"警告!");
	}
	else {
		float x, y;
		int i;
		int code1, code2;
		RedrawWindow();
		for (int i = 0; i < N; i++, i++) {
			int c = 0;
			if (ptset[i].x < XL)
				c = c | LEFT;
			else if (ptset[i].x > XR)
				c = c | RIGHT;
			if (ptset[i].y > YB)
				c = c | BOTTOM;
			else if (ptset[i].y < YT)
				c = c | TOP;
			code1 = c;
			c = 0;
			if (ptset[i + 1].x < XL)
				c = c | LEFT;
			else if (ptset[i + 1].x > XR)
				c = c | RIGHT;
			if (ptset[i + 1].y > YB)
				c = c | BOTTOM;
			else if (ptset[i + 1].y < YT)
				c = c | TOP;
			code2 = c;
			if (code1 != 0 && code2 != 0 && (code1&code2) == 0) {
				if ((LEFT&code1) != 0) {
					x = XL;
					y = (float)ptset[i].y + (ptset[i + 1].y - ptset[i].y)*(XL - ptset[i].x) / (ptset[i + 1].x - ptset[i].x);
				}
				else if ((RIGHT&code1) != 0) {
					x = XR;
					y = (float)ptset[i].y + (ptset[i + 1].y - ptset[i].y)*(XR - ptset[i].x) / (ptset[i + 1].x - ptset[i].x);
				}
				else if ((BOTTOM&code1) != 0) {
					y = YB;
					x = (float)ptset[i].x + (ptset[i + 1].x - ptset[i].x)*(YB - ptset[i].y) / (ptset[i + 1].y - ptset[i + 1].y);
				}
				else if ((TOP&code1) != 0) {
					y = YT;
					x = (float)ptset[i].x + (ptset[i + 1].x - ptset[i].x)*(YT - ptset[i].y) / (ptset[i + 1].y - ptset[i].y);
				}
				ptset[i].x = (long)x;
				ptset[i].y = (long)y;
				if ((LEFT&code2) != 0) {
					x = XL;
					y = (float)ptset[i].y + (ptset[i + 1].y - ptset[i].y)*(XL - ptset[i].x) / (ptset[i + 1].x - ptset[i].x);
				}
				else if ((RIGHT&code2) != 0) {
					x = XR;
					y = (float)ptset[i].y + (ptset[i + 1].y - ptset[i].y)*(XR - ptset[i].x) / (ptset[i + 1].x - ptset[i].x);
				}
				else if ((BOTTOM&code2) != 0) {
					y = YB;
					x = (float)ptset[i].x + (ptset[i + 1].x - ptset[i].x)*(YB - ptset[i].y) / (ptset[i + 1].y - ptset[i + 1].y);
				}
				else if ((TOP&code2) != 0) {
					y = YT;
					x = (float)ptset[i].x + (ptset[i + 1].x - ptset[i].x)*(YT - ptset[i].y) / (ptset[i + 1].y - ptset[i].y);
				}
				ptset[i + 1].x = (long)x;
				ptset[i + 1].y = (long)y;
				pDC->MoveTo(ptset[i].x, ptset[i].y);
				pDC->LineTo(ptset[i + 1].x, ptset[i + 1].y);
			}
			if (code1 == 0 && code2 == 0) {
				pDC->MoveTo(ptset[i].x, ptset[i].y);
				pDC->LineTo(ptset[i + 1].x, ptset[i + 1].y);
			}
			if (code1 == 0 && code2 != 0) {
				pDC->MoveTo(ptset[0].x, ptset[0].y);
				if ((LEFT&code2) != 0) {
					x = XL;
					y = (float)ptset[i].y + (ptset[i + 1].y - ptset[i].y)*(XL - ptset[i].x) / (ptset[i + 1].x - ptset[i].x);
				}
				else if ((RIGHT&code2) != 0) {
					x = XR;
					y = (float)ptset[i].y + (ptset[i + 1].y - ptset[i].y)*(XR - ptset[i].x) / (ptset[i + 1].x - ptset[i].x);
				}
				else if ((BOTTOM&code2) != 0) {
					y = YB;
					x = (float)ptset[i].x + (ptset[i + 1].x - ptset[i].x)*(YB - ptset[i].y) / (ptset[i + 1].y - ptset[i + 1].y);
				}
				else if ((TOP&code2) != 0) {
					y = YT;
					x = (float)ptset[i].x + (ptset[i + 1].x - ptset[i].x)*(YT - ptset[i].y) / (ptset[i + 1].y - ptset[i].y);
				}
				ptset[i + 1].x = (long)x;
				ptset[i + 1].y = (long)y;
				pDC->LineTo(ptset[i + 1].x, ptset[i + 1].y);
			}
			if (code1 != 0 && code2 == 0) {
				pDC->MoveTo(ptset[i + 1].x, ptset[i + 1].y);
				if ((LEFT&code1) != 0) {
					x = XL;
					y = (float)ptset[i].y + (ptset[i + 1].y - ptset[i].y)*(XL - ptset[i].x) / (ptset[i + 1].x - ptset[i].x);
				}
				else if ((RIGHT&code1) != 0) {
					x = XR;
					y = (float)ptset[i].y + (ptset[i + 1].y - ptset[i].y)*(XR - ptset[i].x) / (ptset[i + 1].x - ptset[i].x);
				}
				else if ((BOTTOM&code1) != 0) {
					y = YB;
					x = (float)ptset[i].x + (ptset[i + 1].x - ptset[i].x)*(YB - ptset[i].y) / (ptset[i + 1].y - ptset[i + 1].y);
				}
				else if ((TOP&code1) != 0) {
					y = YT;
					x = (float)ptset[i].x + (ptset[i + 1].x - ptset[i].x)*(YT - ptset[i].y) / (ptset[i + 1].y - ptset[i].y);
				}
				ptset[i].x = (long)x;
				ptset[i].y = (long)y;
				pDC->LineTo(ptset[i].x, ptset[i].y);
			}
		}
	}
}

七、实现效果

在这里插入图片描述

  • 11
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
MFC中提供了多边形裁剪的相关函数,可以使用以下代码实现: ```c++ void ClipPolygon(CDC* pDC, CPoint* pts, int nCount, CRect rectClip) { // 定义裁剪区域的左、右、上、下边界 int nLeft = rectClip.left; int nRight = rectClip.right; int nTop = rectClip.top; int nBottom = rectClip.bottom; // 定义裁剪区域的四个顶点 CPoint ptsClip[4]; ptsClip[0] = CPoint(nLeft, nTop); ptsClip[1] = CPoint(nRight, nTop); ptsClip[2] = CPoint(nRight, nBottom); ptsClip[3] = CPoint(nLeft, nBottom); // 定义裁剪后的顶点序列 CPoint ptsResult[50]; int nResultCount = 0; // 对每条裁剪边进行裁剪 for (int i = 0; i < 4; i++) { CPoint ptStart = pts[nCount - 1]; for (int j = 0; j < nCount; j++) { CPoint ptEnd = pts[j]; // 判断线段裁剪边之间的位置关系 bool bStartIn = PtInPolygon(ptStart, ptsClip, 4); bool bEndIn = PtInPolygon(ptEnd, ptsClip, 4); if (bStartIn && bEndIn) // 线段裁剪区域内,直接添加到结果序列中 { ptsResult[nResultCount++] = ptEnd; } else if (bStartIn && !bEndIn) // 线段裁剪区域内部到外部,计算交点并添加到结果序列中 { CPoint ptIntersect = GetIntersection(ptStart, ptEnd, ptsClip[i], ptsClip[(i + 1) % 4]); ptsResult[nResultCount++] = ptIntersect; } else if (!bStartIn && bEndIn) // 线段裁剪区域外部到内部,计算交点并添加到结果序列中 { CPoint ptIntersect = GetIntersection(ptStart, ptEnd, ptsClip[i], ptsClip[(i + 1) % 4]); ptsResult[nResultCount++] = ptIntersect; ptsResult[nResultCount++] = ptEnd; } else // 线段裁剪区域外部,不做处理 { } // 更新起点 ptStart = ptEnd; } // 将当前裁剪边的结果序列作为下一条裁剪边的输入序列 nCount = nResultCount; memcpy(pts, ptsResult, sizeof(CPoint) * nResultCount); nResultCount = 0; } // 绘制裁剪后的多边形 if (nCount > 0) { pDC->MoveTo(pts[0]); for (int i = 1; i < nCount; i++) { pDC->LineTo(pts[i]); } pDC->LineTo(pts[0]); } } // 判断点是否在多边形内 bool PtInPolygon(CPoint pt, CPoint* pts, int nCount) { int nCross = 0; for (int i = 0; i < nCount; i++) { CPoint pt1 = pts[i]; CPoint pt2 = pts[(i + 1) % nCount]; if (((pt1.y <= pt.y) && (pt2.y > pt.y)) || ((pt1.y > pt.y) && (pt2.y <= pt.y))) { double d = (double)(pt.y - pt1.y) / (double)(pt2.y - pt1.y); if (pt.x < pt1.x + d * (pt2.x - pt1.x)) { nCross++; } } } return (nCross % 2 == 1); } // 计算线段裁剪边的交点 CPoint GetIntersection(CPoint pt1, CPoint pt2, CPoint pt3, CPoint pt4) { double d1 = (double)(pt1.y - pt3.y) * (double)(pt4.x - pt3.x) - (double)(pt1.x - pt3.x) * (double)(pt4.y - pt3.y); double d2 = (double)(pt2.y - pt1.y) * (double)(pt4.x - pt3.x) - (double)(pt2.x - pt1.x) * (double)(pt4.y - pt3.y); double d = d1 / d2; CPoint pt; pt.x = (int)(pt1.x + d * (pt2.x - pt1.x)); pt.y = (int)(pt1.y + d * (pt2.y - pt1.y)); return pt; } ``` 该函数接受五个参数:绘图设备上下文(CDC*)、多边形顶点序列(CPoint*)、多边形顶点数(int)、裁剪区域(CRect)。在函数中,首先定义裁剪区域的边界和四个顶点,然后对每条裁剪边进行裁剪,最终得到裁剪后的多边形顶点序列,并绘制出来。裁剪过程中,使用了判断点是否在多边形内、计算线段裁剪边的交点等函数。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值