MFC——直线段截取的Cohen-Sutherland算法

本文介绍了如何在MFC环境中利用Cohen-Sutherland算法进行直线截取。首先,文章讲解了算法的预备知识,包括MFC编程、Cohen-Sutherland算法和橡皮线绘制。接着,详细描述了实现过程,包括在OnDraw中绘制矩形,动态橡皮线的实现以及编码规则。在实现过程中,遇到的两个问题分别是斜率计算和橡皮线清除,这些问题都得到了解决。最后,提供了代码实现细节。
摘要由CSDN通过智能技术生成

实现目标:

用一个左下角为(100,100),右上角为(800,400)的矩形做直线截取。有用户手动输入一个直线,将该直线在矩形内的部分截取,区域的部分消失。其中,用户绘制直线时,使用的是动态直线。

预备知识:

1)MFC编程相关知识
2)了解Cohen-Sutherland算法
3)了解橡皮线的绘制

过程描述:

1)在Ondraw函数中先画好矩形

2)由左键按下,鼠标移动,左键松开,三个函数,实现橡皮线,并且记录起点与终点的位置。到此完成程序的框架。下面实现具体的算法。橡皮线的实现使用 p->SetROP2(R2_NOT)函数。这是正规的橡皮线实现方法,想具体了解橡皮线的使用方法,可以百度该函数名加橡皮线即可

3)创建函数int CODE(CPoint p)用来传进来一个点坐标,返还一个四位二进制code值。该code值用于判断点的位置。直线的两个端点的编码表示出了线段的方位。对于任一点(x,y),根据其坐标所在的区域,赋予一个4位的二进制码D3D2D1D0。
编码规则如下:
(1)若x<wxl,D0=1,否则D0=0;
(2)若x>wxr,D1=1,否则D1=0;
(3)若y<wyb,D2=1,否则D2=0;
(4)若y>wyt,D3=1,否则D3=0。

4)在左键松开的函数中实现截取功能,
Step1 判断
裁剪一条线段时,先求出直线段端点p1和p2的编码code1和code2,然后:
a) 若code1|code2=0,对直线段简取之;
b) 若code1&code2≠0,对直线段简弃之;
Step2 裁剪
求直线和窗口边界的交点,对直线裁剪
确保p1位于窗口外;若p1在窗口内,则交换p1,p2。
根据p1的编码从低位开始找编码值为1的地方,确定要求交的窗口边界,求出直线段与相应窗口边界的交点,用交点代替p1.
重复上述过程

结果

在这里插入图片描述

遇到的问题

1、当画的直线斜率过大时,截取的直线只会从四个角作为起点。解决:之后将斜率的计算换成浮点计算就解决问题了。
2.由于使用橡皮线,直线的清除与重绘很麻烦。我直线截取的实现是通过用一条白色的线覆盖上一条线实现的。这个问题的解决占用了我很大一部分时间。

下面是代码


// 直线截取View.cpp: C直线截取View 类的实现
//

#include "stdafx.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义,并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "直线截取.h"
#endif

#include "直线截取Doc.h"
#include "直线截取View.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CPoint m_ptSpoint = CPoint(0, 0);  //起始点
CPoint m_ptEpoint = CPoint(0, 0);  //最终点
bool m_click;
float k = 0;


// C直线截取View

IMPLEMENT_DYNCREATE(C直线截取View, CView)

BEGIN_MESSAGE_MAP(C直线截取View, CView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &C直线截取View::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
//	ON_WM_PAINT()
END_MESSAGE_MAP()

// C直线截取View 构造/析构

C直线截取View::C直线截取View() noexcept
{
   
	// TODO: 在此处添加构造代码

}

C直线截取View::~C直线截取View()
{
   
}

BOOL C直线截取View::PreCreateWindow(CREATESTRUCT& cs)
{
   
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	<
// 线裁剪CSView.cpp : implementation of the CCSView class // #include "stdafx.h" #include "线裁剪CS.h" #include "线裁剪CSDoc.h" #include "线裁剪CSView.h" #define left 200 //默认图形窗口 #define right 400 #define bottom 100 #define top 300 #define l 1 //区域编码 #define r 2 #define b 4 #define t 8 #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CCSView IMPLEMENT_DYNCREATE(CCSView, CView) BEGIN_MESSAGE_MAP(CCSView, CView) //{{AFX_MSG_MAP(CCSView) ON_WM_LBUTTONDOWN() ON_WM_RBUTTONDOWN() //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CCSView construction/destruction CCSView::CCSView() { // TODO: add construction code here } CCSView::~CCSView() { } BOOL CCSView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CCSView drawing void CCSView::OnDraw(CDC* pDC) { CCSDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDC->TextOut(150,1," 单击左键定线起点,右击定线终点"); pDC->TextOut(150,20,"线的裁剪结果会自动显示"); // TODO: add draw code for native data here pDC->Rectangle(left,top,right,bottom); } ///////////////////////////////////////////////////////////////////////////// // CCSView printing BOOL CCSView::OnPreparePrinting(CPrintInfo* pInfo) { // default preparation return DoPreparePrinting(pInfo); } void CCSView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add extra initialization before printing } void CCSView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: add
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值