计算机图形学——多边形裁剪(待改良可运行)

本文介绍了一种处理多边形裁剪的算法,尤其针对凹多边形裁剪时可能出现的错误进行了改进。通过区分进入点和出点,并结合裁剪窗口遍历,有效解决了错误裁剪线的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用窗口的四条边的边界分别对所画多边形进行裁剪,每次裁剪后的结果都会生成一个新的多边形,再将这一多边形作为输入多边形再以裁剪窗口其他边界裁剪,最终达到裁剪多边形的目的。上述多边形裁剪对于凸多边形适用,但对于部分凹多边形会出现错误如下图,向外凹陷地位置裁剪结果包含了一条本不应该有的线,对于该问题由于时间问题,还没有完成,但已经形成一定可行的改进思路。

首先还是要先求出多边形与裁剪区域的交点,同时类似于梁友栋算法的入边出边,把交点分成进入点和出点,然后将交点和原来的顶点按照多边形的顺序存储到同一个数组里,同样将裁剪区域和产生的交点也按照顺序存储起来。从多边形的某一顶点出发,开始遍历,遇到第一个进入点,此时进入裁剪区域,记录这个点,继续遍历直到找到第一个从边界“出去”的点,这时候开始在裁剪窗口里进行遍历,找到一个进入点再转换为多边形序列继续遍历,不断重复,直到发现回到第一个进入边界的点,将这些点组成的多边形绘制出来,就完成了裁剪。这样可以有效地解决凹多边形出现错误的问题。具体代码还没有实现。

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值