Cohen Sutherland线段裁剪算法(C#实现)

来源:互联网 发布:好学而近乎知 编辑:程序博客网 时间:2024/05/17 13:41
Cohen Sutherland线段裁剪算法(C#实现)

一、问题说明:

平面上有一个矩形框和一条线段,将线段画到平面上,只显示线段在矩形框中的部分,即矩形框中的部分为可见的。已知矩形框的四个边框的坐标值Left,Right,Top,Buttom和线段的两个端点的坐标P1P2。通过算法实现该过程。

二、算法思想:

该算法将矩形边框分别延长(即沿着边框做直线)将平面分成九个部分,对九个部分分别编码,并将两个端点按所在的区域进行编码。线段与矩形有五种位置情况。

1、  判断端点是否在中间区域,都在就将线段画出来。

2、端点在四个边框的同一侧就不用画出

3、不在其中就求线段与边框的交点,将外边的部分去掉。对于剩余的部分当做新的线段的处理,从头开始再判断。循环两次就能判断剩余部分是保留还是舍去。

             

三、程序代码

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;namespace Cohen_Sutherland{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();        }        //设置矩形窗口的四条边        private int left = 100, right = 200, top = 100, buttom = 200;        //设置裁剪直线的端点        private Point P1 = new Point(100, 100), P2 = new Point(200, 200);        //设置编码 最后四位对应上 下 右 左        private int CodeLeft = 1;        private int CodeRight = 2;        private int CodeButtom = 4;        private int CodeTop = 8;        private void btnCut_Click(object sender, EventArgs e)        {            Graphics g = pictureBox1.CreateGraphics();            Pen p = new Pen(Color.Blue);            g.DrawLine(p, new Point(left, top), new Point(right, top));            g.DrawLine(p, new Point(left, top), new Point(left, buttom));            g.DrawLine(p, new Point(right, top), new Point(right, buttom));            g.DrawLine(p, new Point(right, buttom), new Point(left, buttom));            g.DrawLine(new Pen(Color.Gray), P1, P2);            CohenSutherland(P1.X, P1.Y, P2.X, P2.Y);        }        private void CohenSutherland(int P1x, int P1y, int P2x, int P2y)        {            int C1 = Code(P1x, P1y), C2 = Code(P2x, P2y);            int C;            int Px = 0, Py = 0;//记录交点            while (C1 != 0 || C2 != 0)//两个点(P1x,P1y),(P2x,P2y)不都在矩形框内;都在内部就画出线段            {                if ((C1 & C2) != 0)   //两个点在矩形框的同一外侧 → 不可见                {                    P1x = 0;                    P1y = 0;                    P2x = 0;                    P2y = 0;                    break;                }                C = C1;                if (C1 == 0)// 判断P1 P2谁在矩形框内(可能是P1,也可能是P2)                {                    C = C2;                }                if ((C & CodeLeft) != 0)//用与判断的点在左侧                 {                    Px = left;                    Py = P1y + (int)(Convert.ToDouble(P2y - P1y) / (P2x - P1x) * (left - P1x));                }                else if ((C & CodeRight) != 0)//用与判断的点在右侧                 {                    Px = right;                    Py = P1y + (int)(Convert.ToDouble(P2y - P1y) / (P2x - P1x) * (right - P1x));                }                else if ((C & CodeTop) != 0)//用与判断的点在上方                {                    Py = top;                    Px = P1x + (int)(Convert.ToDouble(P2x - P1x) / (P2y - P1y) * (top - P1y));                }                else if ((C & CodeButtom) != 0)//用与判断的点在下方                {                    Py = buttom;                    Px = P1x + (int)(Convert.ToDouble(P2x - P1x) / (P2y - P1y) * (buttom - P1y));                }                if (C == C1) //上面判断使用的是哪个端点就替换该端点为新值                {                    P1x = Px;                    P1y = Py;                    C1 = Code(P1x, P1y);                }                else                {                    P2x = Px;                    P2y = Py;                    C2 = Code(P2x, P2y);                }            }            Graphics g = pictureBox1.CreateGraphics();            Pen p = new Pen(Color.Red);            g.DrawLine(p, new Point(P1x, P1y), new Point(P2x, P2y));        }        private int Code(int x, int y) //端点编码函数 左右上下分别对应一位        {            int c = 0;            if (x < left)            {                c = c | CodeLeft;            }            if (x > right)            {                c = c | CodeRight;            }            if (y < top)            {                c = c | CodeTop;            }            if (y > buttom)            {                c = c | CodeButtom;            }            return c;        }        private void btnParameter_Click(object sender, EventArgs e)        {            left = Convert.ToInt32(txtLeft.Text);            right = Convert.ToInt32(txtRight.Text);            top = Convert.ToInt32(txtTop.Text);            buttom = Convert.ToInt32(txtButtom.Text);            P1.X = Convert.ToInt32(txtP1X.Text);            P1.Y = Convert.ToInt32(txtP1Y.Text);            P2.X = Convert.ToInt32(txtP2X.Text);            P2.Y = Convert.ToInt32(txtP2Y.Text);        }        private void btnClear_Click(object sender, EventArgs e)        {            pictureBox1.Refresh();        }        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)        {            toolStripStatusLabelAxis.Text = "X:" + e.X + " Y:" + e.Y;        }    }}

 

四、结果显示

显示线段与矩形框的五种位置关系,红线为裁剪所得,灰色为参考的整条线段

原创粉丝点击