计算机图形学常用算法实现10 多边形裁剪Sutherland-Hodgman算法

算法原理比较简单,用裁剪区域的四条边分别去分割多边形。
假设边p1,p2,用区域某条边进行裁剪。方向为p1->p2
1.p1在边外,p2在边外
无操作
2.p1外,p2内
保存交点p和p2
3.p1内,p2内
保存p2
4.p1内,p2外
保存交点
分割完之后更新多边形的点集
代码裁剪区域为(200,200)到(400,400)


       private void SutherlandHodgmanClip()
        {
            //分四条边裁剪
            clipEdge(1);
            clipEdge(2);
            clipEdge(3);
            clipEdge(4);
            g.Clear(Color.White);
            drawEdge();
            for (int i = 0; i < indexOfPolygon; i++)
                g.DrawLine(p, polygon[i], polygon[(i + 1) % indexOfPolygon]);
        }

求交点的函数

     private Point findIntersection(int edge,Point p1,Point p2)
       {
           Point pt = new Point();
           if (edge == 1)
           {
               pt.X = 200;
               pt.Y = (int)(p1.Y - (float)(p1.Y - p2.Y) * (p1.X - 200) / (p1.X - p2.X));
           }
           else if (edge == 3)
           {
               pt.X = 400;
               pt.Y = (int)(p1.Y - (float)(p1.Y - p2.Y) * (p1.X - 400) / (p1.X - p2.X));
           }
           else if (edge == 2)
           {
               pt.Y = 200;
               pt.X = (int)(p1.X - (float)(p1.X - p2.X) * (p1.Y - 200) / (p1.Y - p2.Y));
           }
           else if (edge == 4)
           {
               pt.Y = 400;
               pt.X = (int)(p1.X - (float)(p1.X - p2.X) * (p1.Y - 400) / (p1.Y - p2.Y));
           }
           return pt;
       }

判断点是不是在边外

    private bool inSide(int edge,Point pt)
     {
         //左垂直边
         if (edge == 1 && pt.X < 200|| edge == 3 && pt.X > 400|| edge == 2 && pt.Y < 200||edge == 4 &&pt.Y>400)
             return false;
         return true;
     }

裁剪区域的某条边进行裁剪

    private void clipEdge(int edge)
     {
         indexOfPolygonTemp = 0;
         bool isP1In, isP2In;
         for (int i = 0; i < indexOfPolygon; i++)
         {
             isP1In = inSide(edge,polygon[i]);
             isP2In = inSide(edge,polygon[(i+1)%indexOfPolygon]);
             if (isP1In && isP2In)
                 polygonTemp[indexOfPolygonTemp++] = polygon[(i + 1) % indexOfPolygon];
             else if (isP1In)
                 polygonTemp[indexOfPolygonTemp++] = findIntersection(edge, polygon[i], polygon[(i + 1) % indexOfPolygon]);
             else if (isP2In)
             {
                 polygonTemp[indexOfPolygonTemp++] = findIntersection(edge, polygon[i], polygon[(i + 1) % indexOfPolygon]);
                 polygonTemp[indexOfPolygonTemp++] = polygon[(i + 1) % indexOfPolygon];
             }
         }
         indexOfPolygon = indexOfPolygonTemp;
         for (int i = 0; i < indexOfPolygon; i++)
             polygon[i] = polygonTemp[i];
     }

计算机图形学常用算法实现10 多边形裁剪Sutherland-Hodgman算法_第1张图片

计算机图形学常用算法实现10 多边形裁剪Sutherland-Hodgman算法_第2张图片

完整可执行代码如下:(vs2015 winform)

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace cgdemo5
    {
        public partial class Form1 : Form
        {
            private Point[] polygon;
            private Point[] polygonTemp;
            private bool isClick=false;
            private int indexOfPolygon = 0;
            private int indexOfPolygonTemp = 0;
            private bool isFinished = false;
            Graphics g;
            Pen p = new Pen(Color.Red);
            public Form1()
            {
                polygon = new Point[10010];
                polygonTemp = new Point[10010];
                InitializeComponent();
                g = this.CreateGraphics();
            }
            private void drawEdge()
            {
                g.DrawLine(p,200,200,200,400);
                g.DrawLine(p,200,400,400,400);
                g.DrawLine(p, 400, 400, 400, 200);
                g.DrawLine(p,400,200,200,200);
            }
            private bool inSide(int edge,Point pt)
            {
                //左垂直边
                if (edge == 1 && pt.X < 200|| edge == 3 && pt.X > 400|| edge == 2 && pt.Y < 200||edge == 4 &&pt.Y>400)
                    return false;
                return true;
            }
            private void SutherlandHodgmanClip()
            {
                //分四条边裁剪
                clipEdge(1);
                clipEdge(2);
                clipEdge(3);
                clipEdge(4);
                g.Clear(Color.White);
                drawEdge();
                for (int i = 0; i < indexOfPolygon; i++)
                    g.DrawLine(p, polygon[i], polygon[(i + 1) % indexOfPolygon]);
            }
            private Point findIntersection(int edge,Point p1,Point p2)
            {
                Point pt = new Point();
                if (edge == 1)
                {
                    pt.X = 200;
                    pt.Y = (int)(p1.Y - (float)(p1.Y - p2.Y) * (p1.X - 200) / (p1.X - p2.X));
                }
                else if (edge == 3)
                {
                    pt.X = 400;
                    pt.Y = (int)(p1.Y - (float)(p1.Y - p2.Y) * (p1.X - 400) / (p1.X - p2.X));
                }
                else if (edge == 2)
                {
                    pt.Y = 200;
                    pt.X = (int)(p1.X - (float)(p1.X - p2.X) * (p1.Y - 200) / (p1.Y - p2.Y));
                }
                else if (edge == 4)
                {
                    pt.Y = 400;
                    pt.X = (int)(p1.X - (float)(p1.X - p2.X) * (p1.Y - 400) / (p1.Y - p2.Y));
                }
                return pt;
            }
            private void clipEdge(int edge)
            {
                indexOfPolygonTemp = 0;
                bool isP1In, isP2In;
                for (int i = 0; i < indexOfPolygon; i++)
                {
                    isP1In = inSide(edge,polygon[i]);
                    isP2In = inSide(edge,polygon[(i+1)%indexOfPolygon]);
                    if (isP1In && isP2In)
                        polygonTemp[indexOfPolygonTemp++] = polygon[(i + 1) % indexOfPolygon];
                    else if (isP1In)
                        polygonTemp[indexOfPolygonTemp++] = findIntersection(edge, polygon[i], polygon[(i + 1) % indexOfPolygon]);
                    else if (isP2In)
                    {
                        polygonTemp[indexOfPolygonTemp++] = findIntersection(edge, polygon[i], polygon[(i + 1) % indexOfPolygon]);
                        polygonTemp[indexOfPolygonTemp++] = polygon[(i + 1) % indexOfPolygon];
                    }
                }
                indexOfPolygon = indexOfPolygonTemp;
                for (int i = 0; i < indexOfPolygon; i++)
                    polygon[i] = polygonTemp[i];
            }
            private double distance(Point p1,Point p2)
            {
                return Math.Sqrt((p1.X-p2.X)*(p1.X-p2.X)+(p1.Y-p2.Y)*(p1.Y-p2.Y));
            }
    
            private void Form1_MouseClick(object sender, MouseEventArgs e)
            {
                drawEdge();
                   RectangleF rec = new RectangleF(e.Location.X - 1, e.Location.Y - 1, 3, 3);
                g.DrawEllipse(p, rec);
                if (isClick == false)
                {
                    Point pp = new Point();
                    pp.X = e.Location.X;
                    pp.Y = e.Location.Y;
                    polygon[indexOfPolygon++] = pp;
                    isClick = true;
                }
                else
                {
                    Point pp = new Point();
                    pp.X = e.Location.X;
                    pp.Y = e.Location.Y;
                    if (distance(pp, polygon[0]) < 8)
                    {
                        for (int i = 0; i < indexOfPolygon; i++)
                            g.DrawLine(p,polygon[i],polygon[(i+1)%indexOfPolygon]);
                        isFinished = true;
                    }
                    polygon[indexOfPolygon++] = pp;
                }
            }
    
            private void Form1_KeyUp(object sender, KeyEventArgs e)
            {
                if (isFinished)
                    SutherlandHodgmanClip();
            }
        }
    }

你可能感兴趣的:(图形学基础知识)