计算机图形学常用算法实现10 多边形裁剪Sutherland-Hodgman算法-程序员宅基地

技术标签: 图形学基础知识  多边形裁剪  计算机图形学  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];
     }

在这里插入图片描述

在这里插入图片描述

完整可执行代码如下:(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();
            }
        }
    }
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43813453/article/details/84647026

智能推荐

最近发现一个新的国产开发平台,给大家分享下-程序员宅基地

管理信息系统(MIS系统Management Information System)应该是我们这些开发者从业经历中必定经历过的开发项目,我们曾经为其昼夜奋战,与客户据理力争,改来改去。当这一切结束的时候你会发现一个和一开始设计有着千差万别的系统呈现在你眼前,你在开发的时候,客户的思路也在不断的变化,而这一过程增加了无形的成本,项目做完不仅不赚钱还有可能赔钱,你是多希望在一开始确定了需求后就直接交付...

异常值-程序员宅基地

假设一个公司的薪资水平中位数是 $35,000,排名第 25% 和 75% 的薪资分别是 $21,000 和 $ 53,000。如果某人的薪水是 $1,那么它可以被看成是异常值(Outlier)吗?A. 可以B. 不可以C. 需要更多的信息才能判断D. 以上说法都不对答案:C解析:异常值(Outlier)指样本中的个别值,其数值明显偏离它(或他们)所属样本的其余观测值,也称异常数据,..._异常值

bsoj 1482 【NOI2004】郁闷的出纳员(splay入门)_noi2004 郁闷的出纳员 splay-程序员宅基地

【NOI2004】郁闷的出纳员 Time Limit:10000MS Memory Limit:65536KTotal Submit:466 Accepted:178 Case Time Limit:2000MSDescription  OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一_noi2004 郁闷的出纳员 splay

CSR8670蓝牙模块,立体声高品质音频方案-程序员宅基地

FSC-BT802是一款非常小尺寸(9.7mm11.5mm1.8mm)的蓝牙5.0音频模块,模块内置CSR8670蓝牙模块芯片,支持模拟差分音频输出和MIC输入及I2S/PCM,光纤(SPDIF in/out),并支持APTX-X、APTX-X LL、APTX-X HD、CVC、、TWS等功能。FSC-BT802具有BQB、CE、FCC、TELEC、IC、RoHS认证,支持A2DP、AVRCP、HFP、HSP、SPP、GATT、PBAP配置文件,不含PCB天线,需要加外置天线。*蓝牙5.0/4.0/3._csr8670

ReactNative与Android的交互-程序员宅基地

1 RN调用Native方法1、创建交互类Module,继承ReactContextBaseJavaModule;2、创建package,实现ReactPackage的方法,添加步骤1创建的交互类Module到package内;3、添加创建的自定义package到ReactNativeHost中的getPackages方法中,向ReactNative注册原生模块;1.1 导出Nativ..._activity 给rn发通知

pycharm 弹出的Safe Delete安全 删除功能是什么?-程序员宅基地

这是pychamr右击删除一个类之后,会弹出一个Safe Delete安全删除的弹框:我们先来说下者三个选项的意思:①:Safe delete(with usage search):启用安全删除功能 (使用搜索)②:Search in comments and strings:在注释和字符串中搜索③:Search for text occurrences:搜索文本事件第一种...

随便推点

ocx插件: AniGIF.ocx安装-程序员宅基地

(ocx 是 ocx 控件的扩展名,与 .exe、.dll 同属于PE文件)①安装文件,其实也就是把他复制粘贴到我们的系统文件中。②对于是32bit的系统。请把 .ocx文件 移到 c:\Windows\system32 里面③对于是 64bit的Win7/win8 系统, 要把 .ocx文件移到 c:\Windows\SysWOW64④打开“运行”。输入注册命令。⑤对于32位的系统。在运行中直接输入“regsvr32 c:\Windows\system32\文件名.ocx⑥对于64_anigif.ocx

VUE vue-cli 步骤及配置文件解释_vue脚手架创建的项目打包配置文件在哪_小丑也有可爱的一面的博客-程序员宅基地

1:vue-cli 是vue的脚手架工具 并初始一个脚手架自带网站模板2:什么是脚手架? 文字解释:脚手架就有点类是建筑的一个承重墙以及框架下列分别用图说明package-lock.json是一个缓存文件,缓存的是依赖文件来源,在第二次生成的时候就会使用缓存加载速度更快注意:src文件夹中还有特别说明3:项目的其他配置 1:让项目运行时候就自动打开浏览器 package.json 在..._vue脚手架创建的项目打包配置文件在哪

Linux 开放端口号 CentOS中测试-程序员宅基地

查看 firewalld 状态systemctl status firewalld开放端口3306:// --permanent 永久生效,没有此参数重启后失效firewall-cmd --zone=public --add-port=3306/tcp --permanent firewall-cmd --zone=public --add-port=2000-2100/tcp --permanent 重新加载:firewall-cmd --reload查看端

cs_cs1238驱动-程序员宅基地

public ArrayList> combinationSum(int[] candidates, int target) { ArrayList> result = new ArrayList>(); if(candidates == null || candidates.length == 0) return result; Arrays.sort(candidates);_cs1238驱动

k8s安装会遇到的小问题_cidr 10.244.0.0/16 has incorrect ip version: expec_zeorg的博客-程序员宅基地

如果遇到[kubelet-check] Initial timeout of 40s passed.问题,查看日志有可能是k8s 新版本不支持docker的原因(此现象是docker启动了k8s容器但是会自动杀死容器)解决办法查看k8s版本(安装指定版本k8s)查看docker版本(安装指定版本docker)还有一种就是由于大意IP地址设置错误kubeadm init --kubernetes-version=v1.19.4 --pod-network-cidr=10.244.0.0/16 -_cidr 10.244.0.0/16 has incorrect ip version: expect isipv6=true

深入了解JVM——虚拟机字节码执行引擎-程序员宅基地

本文为 《深入理解Java虚拟机》第八章内容的学习笔记,部分内容经过二次加工。若对相关知识感兴趣,推荐购书深入阅读。若认为文章涉嫌侵权,请联系作者及时删除。 本作品采用 知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议 (CC BY-NC-SA 3.0 CN) 进行许可 。非商业性质转载请注明作者和出处,禁止商业性质转载。 开源创造世界概述执行引擎...

推荐文章

热门文章

相关标签