using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace LineCut_Cohen
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//定义钻石参数
int x0 = 100;
int y0 = 100;
int n = 13;
int r = 50;
int[] x;
int[] y;
//
//计算钻石顶点 by tiantian
//
public void ZuanShi()
{
float t = (float)3.14159 * 2 / n;
x = new int[n];
y = new int[n];
for (int i = 0; i < n; i++)
{
x[i] = (int)(r * Math.Cos(i * t) + x0);
y[i] = (int)(r * Math.Sin(i * t) + y0);
}
}
//
//计算点(x,y)的编码
//
void CompOutCode(int x, int y, Rectangle rect, OutCode outCode)
{
outCode.all = 0;
outCode.top = outCode.bottom = 0;
if (y < rect.Top) //rect类的top相当于我们惯常用的坐标系的bottom by:tiantian
{
outCode.bottom = 1;
outCode.all += 1;
}
else if (y > rect.Bottom)//rect类的bottom相当于我们惯常用的坐标系的top by:tiantian
{
outCode.top = 1;
outCode.all += 1;
}
outCode.right = outCode.left = 0;
if (x > rect.Right)
{
outCode.right = 1;
outCode.all += 1;
}
else if (x < rect.Left)
{
outCode.left = 1;
outCode.all += 1;
}
}
//
//线段裁剪,p0(x0,y0),p1(x1,y1)为待裁剪线断,rect为裁剪窗口
//
bool ChoenSutherlandLineClip(ref int x0, ref int y0, ref int x1, ref int y1, Rectangle rect) //这里必须是引用传递!by:tiantian
{
Boolean accept, done;
OutCode outCode0 = new OutCode();
OutCode outCode1 = new OutCode();
OutCode outCodeOut = new OutCode();
int x = 0;
int y = 0;
accept = false;
done = false;
CompOutCode(x0, y0, rect, outCode0);
CompOutCode(x1, y1, rect, outCode1);
do
{
int code0 = outCode0.Code();
int code1 = outCode1.Code();
if ((outCode0.all == 0) && (outCode1.all == 0)) //完全可见
{
accept = true;
done = true;
}
else if ((code0 & code1) != 0) //显然不可见 by tt
done = true;
else //进行求交测试
{
if (outCode0.all != 0) //判断哪一点位于窗口之外
outCodeOut = outCode0;
else outCodeOut = outCode1;
if (outCodeOut.left == 1)//线段与窗口的左边相交
{
x = rect.Left;
y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
}
else if (outCodeOut.right == 1)//线段与窗口的右边相交
{
x = rect.Right;
y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
}
else if (outCodeOut.top == 1)//线段与窗口的上边相交
{
y = rect.Bottom;
x = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
}
else if (outCodeOut.bottom == 1)//线段与窗口的下边相交
{
y = rect.Top;
x = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
}
//以交点为界,将线段位于窗口边所在的直线的外侧的部分丢弃。
//对剩余的继续裁剪
if (outCodeOut.all == outCode0.all)
{
x0 = x;
y0 = y;
CompOutCode(x0, y0, rect, outCode0);
}
else
{
x1 = x;
y1 = y;
CompOutCode(x1, y1, rect, outCode1);
}
}
} while (!done);
return accept;
}
//
//画图函数
//
private void Form1_Paint_1(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen myPen = new Pen(Color.Blue, 1f);
g.Clear(Color.Black);
ZuanShi();
for (int i = 0; i <= n - 2; i++)
for (int j = i + 1; j <= n - 1; j++)
g.DrawLine(myPen, x[i], y[i], x[j], y[j]);
}
//
//裁剪按钮
//
private void button1_Click(object sender, EventArgs e)
{
//定义矩形
Point p = new Point(50, 50);
Size size = new Size(50, 50);
Rectangle rect = new Rectangle(p, size);
Graphics g = this.CreateGraphics();
Pen myPen = new Pen(Color.Yellow, 1f);
g.Clear(Color.Black);
ZuanShi();
int xi, xj, yi, yj;//用来存储顶点值的变量 by tiantian
for (int i = 0; i <= n - 2; i++)
for (int j = i + 1; j <= n - 1; j++)
{
xi = x[i]; xj = x[j];//裁剪函数为引用传递,会改变顶点的值,先把这些值存储起来 by:tiantian
yi = y[i]; yj = y[j];
if (ChoenSutherlandLineClip(ref x[i], ref y[i], ref x[j], ref y[j], rect))
{
g.DrawLine(myPen, x[i], y[i], x[j], y[j]);
x[i] = xi; x[j] = xj;//恢复顶点值
y[i] = yi; y[j] = yj;
}
}
}
private void button2_Click(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
Pen myPen = new Pen(Color.Blue, 1f);
g.Clear(Color.Black);
ZuanShi();
for (int i = 0; i <= n - 2; i++)
for (int j = i + 1; j <= n - 1; j++)
g.DrawLine(myPen, x[i], y[i], x[j], y[j]);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace LineCut_Cohen
{
class OutCode
{//顶点编码值类 by tiantian
public OutCode()
{ }
public int all;
public int left, right, top, bottom;
//
//计算编码值 by tiantian
//
public int Code()
{ return top * 2 * 2 * 2 + bottom * 2 * 2 + left * 2 + right; }
}
}
展开阅读全文