南昌大学实验报告
学生姓名: 陈洁
实验类型:□ 验证 □ 综合 □ 设计 □ 创新 实验日期: 08.12.1
一、实验项目名称:线段裁剪
号: 6103106040
学
专业班级: 计算机 062
实验成绩:
二、实验目的:理解和掌握 Cohen-SutherLand 裁剪的原理和算法。
三、实验基本原理:
对于每条线段 P1P2 分为三种情况处理分为三种情况处理:
(1)若 P1P2 完全在窗口内,则显示该线段 P1P2 简称“取”之;
(2)若 P1P2 明显在窗口外,则丢弃该线段,简称“弃”之;
(3)若线段不满足“取”或 “弃”的条件,则在交点处把线段分为两段。其中一段完全在窗口外,可
弃之。然后对另一段重复上述处理。
将区域码的各位从右到左编号,则坐标区域与各位的关系为:
上 下 右 左
X
X
任何位赋值为 1,代表端点落在相应的位置上,否则该位为 0。若端点在剪取矩形内,区域码为 0000。
如果端点落在矩形的左下角,则区域码为 0101。
一旦给定所有的线段端点的区域码,就可以快速判断哪条直线完全在剪取窗口内,哪条直线完全在
窗口外。所以得到一个规律:
X
X
– 若 P1P2 完全在窗口内 code1=0,且 code2=0,则“取”
– 若 P1P2 明显在窗口外 code1&code2≠0,则“弃”
– 在交点处把线段分为两段。其中一段完全在窗口外,可弃之。然后对另一段重复上述处理。
如何判定应该与窗口的哪条边求交呢?
编码中对应位为 1 的边。
计算线段 P1(x1,y1)P2(x2,y2)与窗口边界的交点。
具体算法见书上 p201。
1001
1000
1010
0001
0000
0010
0101
0100
0110
编码
P1
P3
P4
P2
线段裁剪
四、主要仪器设备及耗材:PC 微机;Windows 操作系统;Visual C++ 程序集成环境。
五、实验步骤:
1、理解和掌握 Cohen-SutherLand 裁剪的原理和算法;
2、根据算法编写(或修改)程序裁剪线段;
3、对程序进行编译,纠正程序中可能出现的语法错误;
4、测试程序运行效果:从键盘输入数据,在屏幕上输出,检查输出结果。
六、实验数据及处理结果
编写程序如下:
// 裁剪 Dlg.h:header file
//
#if !defined(AFX_DLG_H__BE852DB5_A0A9
_4DC6_A10F_6D35796C1BDE__INCLUDED
_)
#define
AFX_DLG_H__BE852DB5_A0A9_4DC6_A1
0F_6D35796C1BDE__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// CMyDlg dialog
class CMyDlg : public CDialog
{
// Construction
public:
CMyDlg(CWnd* pParent = NULL);
standard constructor
// Dialog Data
//{{AFX_DATA(CMyDlg)
enum { IDD = IDD_MY_DIALOG };
//
// NOTE: the ClassWizard will add data
function
void
//
members here
//}}AFX_DATA
// ClassWizard generated virtual
overrides
//{{AFX_VIRTUAL(CMyDlg)
protected:
virtual
DoDataExchange(CDataExchange* pDX);
DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
int code(int x,int y);
HICON m_hIcon;
CDC pic;//图片
int top,but;//
int lef,rig;//矩形
int lxb,lyb;
int lxe,lye;//直线坐标
BOOL ldb;//左键是否按下。
int step;//步骤
// Generated message map functions
//{{AFX_MSG(CMyDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID,
LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnButton4();
afx_msg void OnButton1();
afx_msg void OnButton2();
afx_msg void OnLButtonDown(UINT nFlags,
CPoint point);
afx_msg void OnLButtonUp(UINT nFlags,
CPoint point);
afx_msg void OnMouseMove(UINT nFlags,
CPoint point);
afx_msg void OnButton3();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional
declarations immediately before the previous
line.
#endif
// !defined(AFX_DLG_H__BE852DB5_A0A9_
4DC6_A10F_6D35796C1BDE__INCLUDED_
)
// 裁剪 Dlg.cpp : implementation file
//
#include "stdafx.h"
#include "裁剪.h"
#include "裁剪 Dlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual
overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
function
:
void
pDX);
virtual
DoDataExchange(CDataExchange*
// DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg()
CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void
CAboutDlg::DoDataExchange(CDataExchange
* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg,
CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// CMyDlg dialog
CMyDlg::CMyDlg(CWnd*
/*=NULL*/)
: CDialog(CMyDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMyDlg)
pParent
// NOTE:
the ClassWizard will
add
member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not
subsequent DestroyIcon in Win32
=
m_hIcon
AfxGetApp()->LoadIcon(IDR_MAINFRAME);
ldb = FALSE;
require a
step = 0;
top = 20,but = 100,lef = 20,rig = 100;
lxb = 0,lyb = 0;
lxe = 50,lye = 50;
}
void
CMyDlg::DoDataExchange(CDataExchange*
pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMyDlg)
// NOTE: the ClassWizard will add DDX
and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//{{AFX_MSG_MAP(CMyDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON4,
OnButton4)
ON_BN_CLICKED(IDC_BUTTON1,
OnButton1)
ON_BN_CLICKED(IDC_BUTTON2,
OnButton2)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_BN_CLICKED(IDC_BUTTON3,
OnButton3)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// CMyDlg message handlers
BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system
command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) ==
IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu*
pSysMenu
=
GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX)
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR)
;
;
pSysMenu->AppendMenu(MF_STRING,
IDM_ABOUTBOX, strAboutMenu);
}
//
Set
// Set small
}
// Set the icon for this dialog. The framework
does this automatically
// when the application's main window is not
a dialog
SetIcon(m_hIcon, TRUE);
big icon
SetIcon(m_hIcon, FALSE);
icon
// TODO: Add extra initialization here
CPaintDC dc(this);
pic.CreateCompatibleDC(&dc);
CBitmap * bp1,*obp1;
bp1 = new CBitmap;
bp1->LoadBitmap(IDB_B);
obp1 = pic.SelectObject(bp1);
obp1->DeleteObject();
return TRUE;
the focus to a control
}
void CMyDlg::OnSysCommand(UINT nID,
LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
// return TRUE unless you set
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
to draw the icon.
For MFC applications
this is automatically done for you by the
}
}
// If you add a minimize button to your dialog,
you will need the code below
//
using the document/view model,
//
framework.
void CMyDlg::OnPaint()
{
CPaintDC dc(this);
painting
if (IsIconic())
{
SendMessage(WM_ICONERASEBKGND,
(WPARAM) dc.GetSafeHdc(), 0);
// device
context
for
// Center icon in client rectangle
int
cxIcon
GetSystemMetrics(SM_CXICON);
int
cyIcon
GetSystemMetrics(SM_CYICON);
=
=
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
CDC mdc;
CBitmap bmp,*bp;
bmp.LoadBitmap(IDB_B);
mdc.CreateCompatibleDC(GetDC());
bp = mdc.SelectObject(&bmp);
pic.BitBlt(0,0,500,320,&mdc,0,0,SRCCOPY);
mdc.SelectObject(bp);
CDC * dc1;
CWnd * wd1;
wd1 = this->GetDlgItem(IDC_S);
dc1 = wd1->GetDC();
pic.MoveTo(lxb,lyb);
pic.LineTo(lxe,lye);
pic.MoveTo(lef,top);
pic.LineTo(rig,top);
pic.LineTo(rig,but);
pic.LineTo(lef,but);
pic.LineTo(lef,top);
dc1->BitBlt(1,1,496,309,&pic,0,0,SRCCOPY);
}
// The system calls this to obtain the cursor to
display while the user drags
//
the minimized window.
HCURSOR CMyDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CMyDlg::OnButton4()
{
// TODO: Add your control notification handler
code here
OnOK();
}
void CMyDlg::OnButton1()
{
// TODO: Add your control notification handler
code here
step = 1;
}
void CMyDlg::OnButton2()
{
// TODO: Add your control notification handler
code here
step = 2;
}
void CMyDlg::OnLButtonDown(UINT nFlags,
CPoint point)
{
// TODO: Add your message handler code here
and/or call default
if(step){
if(point.x>11&&point.x<508&&point.y>11&&
point.y<321){
ldb = TRUE;
switch(step){
case 1:
top = point.y-12;
lef = point.x-12;
break;
case 2:
lxb = point.x-12;
lyb = point.y-12;
break;
}
}
}
CDialog::OnLButtonDown(nFlags, point);
}
void CMyDlg::OnLButtonUp(UINT nFlags,
CPoint point)
{
// TODO: Add your message handler code here
and/or call default
if(ldb){
ldb = FALSE;
int ti;
switch(step){
case 1:
but = point.y-12;
rig = point.x-12;
if(butrig){ti = lef;lef = rig;rig = ti;}
break;
ti;}
case 2:
lxe = point.x-12;
lye = point.y-12;
break;
}
Invalidate(FALSE);
}
CDialog::OnLButtonUp(nFlags, point);
}
void CMyDlg::OnMouseMove(UINT nFlags,
CPoint point)
{
// TODO: Add your message handler code here
and/or call default
if(ldb){
switch(step){
case 1:
but = point.y-12;
rig = point.x-12;
break;
case 2:
lxe = point.x-12;
lye = point.y-12;
break;
}
Invalidate(FALSE);
}
CDialog::OnMouseMove(nFlags, point);
}
#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8
int CMyDlg::code(int x,int y){//编码函数
int c = 0;
if(x
rig)
c = c|RIGHT;
if(y>but)
c = c|BOTTOM;
else if(y七、思考讨论题或体会或对改进实验的建议
Cohen-Sutherland 线段裁剪算法小结:
本算法的优点在于简单,易于实现。他可以简单的描述为将直线在窗口左边的部分删去,
按左,右,下,上的顺序依次进行,处理之后,剩余部分就是可见的了。在这个算法中求
交点是很重要的,他决定了算法的速度。另外,本算法对于其他形状的窗口未必同样有效。
特点:用编码方法可快速判断线段的完全可见和显然不可见。
八、参考资料:计算机图形学(第 3 版)及其实验指导书