用窗口的四条边的边界分别对所画多边形进行裁剪,每次裁剪后的结果都会生成一个新的多边形,再将这一多边形作为输入多边形再以裁剪窗口其他边界裁剪,最终达到裁剪多边形的目的。上述多边形裁剪对于凸多边形适用,但对于部分凹多边形会出现错误如下图,向外凹陷地位置裁剪结果包含了一条本不应该有的线,对于该问题由于时间问题,还没有完成,但已经形成一定可行的改进思路。
首先还是要先求出多边形与裁剪区域的交点,同时类似于梁友栋算法的入边出边,把交点分成进入点和出点,然后将交点和原来的顶点按照多边形的顺序存储到同一个数组里,同样将裁剪区域和产生的交点也按照顺序存储起来。从多边形的某一顶点出发,开始遍历,遇到第一个进入点,此时进入裁剪区域,记录这个点,继续遍历直到找到第一个从边界“出去”的点,这时候开始在裁剪窗口里进行遍历,找到一个进入点再转换为多边形序列继续遍历,不断重复,直到发现回到第一个进入边界的点,将这些点组成的多边形绘制出来,就完成了裁剪。这样可以有效地解决凹多边形出现错误的问题。具体代码还没有实现。
private void 裁剪(Point[] ArrPoint, Point[] rect)
{
Point[] ArrPoint2 = new Point[100];//每判断一条边就会改变多边形顶点顺序,存入此数组
Graphics g = pictureBox1.CreateGraphics();
Pen p2 = new Pen(Color.Red, 2);
int i = 0;
int xmin = rect[0].X;
int xmax = rect[1].X;
int ymin = rect[0].Y;
int ymax = rect[2].Y;
int j = 0;
//rect[0]和rect[1]相连的边
for (i = 0; i < num1; i++)
{
//均在可见一侧
if (ArrPoint[i].Y >= ymin && ArrPoint[(i + 1) % num1].Y >= ymin)
{
ArrPoint2[j] = ArrPoint[(i + 1) % num1];
j = j + 1;
}
//均在不可见一侧
if (ArrPoint[i].Y < ymin && ArrPoint[(i + 1) % num1].Y < ymin)
{
//啥也不做
}
//起点在可见一侧,终点在不可见一侧
if (ArrPoint[i].Y >= ymin && ArrPoint[(i + 1) % num1].Y < ymin)
{
ArrPoint2[j] = 交点(ArrPoint[i], ArrPoint[(i + 1) % num1],
rect[0], rect[1]);//存储交点
j = j + 1;
}
//起点不可见,终点可见
if (ArrPoint[i].Y < ymin && ArrPoint[(i + 1) % num1].Y >= ymin)
{
ArrPoint2[j] = 交点(ArrPoint[i], ArrPoint[(i + 1) % num1], rect[0],
rect[1]);//存储交点
j = j + 1;
ArrPoint2[j] = ArrPoint[(i + 1) % num1];
j = j + 1;
}
}
num1 = j;
j = 0;
//rect[0]和rect[2]相连的边
for (i = 0; i < num1; i++)
{
//均在可见一侧
if (ArrPoint2[i].X >= xmin && ArrPoint2[(i + 1) % num1].X >= xmin)
{
ArrPoint[j] = ArrPoint2[(i + 1) % num1];
j = j + 1;
}
//均在不可见一侧
if (ArrPoint2[i].X < xmin && ArrPoint2[(i + 1) % num1].X < xmin)
{
//啥也不做
}
//起点在可见一侧,终点在不可见一侧
if (ArrPoint2[i].X >= xmin && ArrPoint2[(i + 1) % num1].X < xmin)
{
ArrPoint[j] = 交点(ArrPoint2[i], ArrPoint2[(i + 1) % num1],
rect[0], rect[2]);//存储交点
j = j + 1;
}
//起点不可见,终点可见
if (ArrPoint2[i].X < xmin && ArrPoint2[(i + 1) % num1].X >= xmin)
{
ArrPoint[j] = 交点(ArrPoint2[i], ArrPoint2[(i + 1) % num1],
rect[0], rect[2]);//存储交点
j = j + 1;
ArrPoint[j] = ArrPoint2[(i + 1) % num1];
j = j + 1;
}
}
num1 = j;
j = 0;
//rect[2]和rect[3]相连的边
for (i = 0; i < num1; i++)
{
//均在可见一侧
if (ArrPoint[i].Y <= ymax && ArrPoint[(i + 1) % num1].Y <= ymax)
{
ArrPoint2[j] = ArrPoint[(i + 1) % num1];
j = j + 1;
}
//均在不可见一侧
if (ArrPoint[i].Y > ymax && ArrPoint[(i + 1) % num1].Y > ymax)
{
//啥也不做
}
//起点在可见一侧,终点在不可见一侧
if (ArrPoint[i].Y <= ymax && ArrPoint[(i + 1) % num1].Y > ymax)
{
ArrPoint2[j] = 交点(ArrPoint[i], ArrPoint[(i + 1) % num1],
rect[2], rect[3]);//存储交点
j = j + 1;
}
//起点不可见,终点可见
if (ArrPoint[i].Y > ymax && ArrPoint[(i + 1) % num1].Y <= ymax)
{
ArrPoint2[j] = 交点(ArrPoint[i], ArrPoint[(i + 1) % num1],
rect[2], rect[3]);//存储交点
j = j + 1;
ArrPoint2[j] = ArrPoint[(i + 1) % num1];
j = j + 1;
}
}
num1 = j;
j = 0;
//rect[1]和rect[3]相连的边
for (i = 0; i < num1; i++)
{
//均在可见一侧
if (ArrPoint2[i].X <= xmax && ArrPoint2[(i + 1) % num1].X <= xmax)
{
ArrPoint[j] = ArrPoint2[(i + 1) % num1];
j = j + 1;
}
//均在不可见一侧
if (ArrPoint2[i].X > xmax && ArrPoint2[(i + 1) % num1].X > xmax)
{
//啥也不做
}
//起点在可见一侧,终点在不可见一侧
if (ArrPoint2[i].X <= xmax && ArrPoint2[(i + 1) % num1].X > xmax)
{
ArrPoint[j] = 交点(ArrPoint2[i], ArrPoint2[(i + 1) % num1],
rect[1], rect[3]);//存储交点
j = j + 1;
}
//起点不可见,终点可见
if (ArrPoint2[i].X > xmax && ArrPoint2[(i + 1) % num1].X <= xmax)
{
ArrPoint[j] = 交点(ArrPoint2[i], ArrPoint2[(i + 1) % num1],
rect[1], rect[3]);//存储交点
j = j + 1;
ArrPoint[j] = ArrPoint2[(i + 1) % num1];
j = j + 1;
}
}
num1 = j;
for (i = 0; i < num1; i++)
{
g.DrawLine(p2, ArrPoint[i], ArrPoint[(i + 1) % num1]);
}
}
private Point 交点(Point firstpoint, Point secondpoint, Point s1, Point s2)
{
Point jiaodian = new Point(0, 0);
double k;
if (s1.X == s2.X)
{
if (firstpoint.X == secondpoint.X)
{
//啥也不做
}
else
{
k = ((double)(firstpoint.Y) - secondpoint.Y) / (firstpoint.X - secondpoint.X);
double y = k * (s1.X - firstpoint.X) + firstpoint.Y;
jiaodian.X = s1.X;
jiaodian.Y = (int)(y);
}
}
if (s1.Y == s2.Y)
{
if (firstpoint.Y == secondpoint.Y)
{
//啥也不做
}
else
{
k = ((double)(firstpoint.X) - secondpoint.X) / (firstpoint.Y -
secondpoint.Y);
double x = k * (s1.Y - firstpoint.Y) + firstpoint.X;
jiaodian.X = (int)(x);
jiaodian.Y = s1.Y;
}
}
return jiaodian;
}
书写比较复杂,还请见谅
以上就是我在学习多边形裁剪算法过程中所写的程序,如果有什么可以改进的地方欢迎来探讨;如果有错误也麻烦指正。
下面是我整合学习图形学的程序包
https://download.youkuaiyun.com/download/gygygyyyyyy/12550827