图形几何算法 -- 凸包算法

news2024/11/11 20:27:53

前言

        常用凸包算法包括Graham Scan 算法和Jarvis March (Gift Wrapping) 算法,在这里要简单介绍的是Graham Scan 算法。

1、概念

        凸包是一个点集所包围的最小的凸多边形。可以想象用一根绳子围绕着一群钉子,绳子所形成的轮廓便是这些钉子的凸包。在计算几何中,凸包得到了广泛的应用,涉及领域包括模式识别、图像处理和优化问题等。

2、算法原理

        凸包算法的目标是从给定的点集(在二维平面中)确定出一个最小的凸多边形(即凸包)。此多边形的所有顶点是在输入点集中。

算法的核心在于以下几个基本概念:

2.1 、极角:对于一个基准点(通常是集合中最底部或最左边的点),其余每个点与基准点的连线形成的角度。通过极角的比较,我们可以确定相对位置。

2.2、栈结构:使用栈来存储凸包上的点。栈的特性允许我们很容易地回退到前一个状态,并且在确定凸包的顶点时非常有效。

2.3、方向判断(Orientation):通过计算三点(一个基准点和两个参考点)形成的向量的叉积来判断它们的相对方向,包括:

  • 顺时针(Clockwise):两个参考点的连线向基准点转动的方式为顺时针。

  • 逆时针(Counterclockwise):两个参考点的连线向基准点转动的方式为逆时针。

  • 共线(Collinear):三点在同一条直线上。

3、算法步骤

以下是该算法的详细步骤:

3.1、选择基准点:遍历所有输入点,选择 Y 坐标最低的点作为基准点(如果有多个点具有相同的 Y 坐标,则选择 X 坐标最小的点),作为基准点(minPoint)。

3.2、极角排序:对于每个点P,计算它与基准点的极角并记录。可以使用 Math.Atan2() 函数来计算极角。排序的同时,如果有两个点的极角相同,则应该依据它们到基准点的距离进行排序,从近到远进行排列。

3.3、初始化栈:

  • 创建一个栈并将基准点压入栈中。

  • 将排好序的点依次压入栈中,初始先将基准点后面的两个点压入栈,以便形成开始的边。

3.4、构建凸包:排序后的点集,从第一个用于构建凸包的点开始。

  • 检查栈顶的两个点和当前点的方向。使用前面提到的在 Orientation() 中实现的稳定性判断。

  • 如果方向判断为“右转”,则弹出栈顶的点,直到遇到一个“左转”或“共线”的状态。

  • 将当前点压入栈中,继续根据下一个点执行该步骤。

3.5、输出结果:当所有点处理完毕后,栈中包含的点即为最终的凸包。

4、代码

class MyConvexHull  
{  
    // 定义一个点的类,包含 X 和 Y 坐标, 坐标类型为 double  
    public class Point2d  
    {  
        public double X { get; }  
        public double Y { get; }  

        public Point2d (double x, double y)  
        {  
            X = x;  
            Y = y;  
        }  
    }  

    // 计算两个点相对于基点的极角  
    private static double PolarAngle(Point2d p0, Point2d p1)  
    {  
        return Math.Atan2(p1.Y - p0.Y, p1.X - p0.X);  
    }  

    // 判断三个点的方向  
    private static int Orientation(Point2d p, Point2d q, Point2d  r)  
    {  
        double val = (q.Y - p.Y) * (r.X - q.X) - (q.X - p.X) * (r.Y - q.Y);  
        if (val == 0) return 0; // collinear  
        return (val > 0) ? 1 : 2; // clockwise or counterclockwise  
    }  

    // Graham Scan 主函数,返回凸包的顶点列表  
    public static List<Point2d> GetConvexHull(List<Point2d> points)  
    {  
        // 1. 找到最低的点  
        Point2d minPoint = points[0];  
        foreach (var point in points)  
        {  
            if (point.Y < minPoint.Y || (point.Y == minPoint.Y && point.X < minPoint.X))  
            {  
                minPoint = point;  
            }  
        }  
        // 2. 将点按相对于基准点的极角进行排序  
        points.Sort((p1, p2) =>  
        {  
            double angle1 = PolarAngle(minPoint, p1);  
            double angle2 = PolarAngle(minPoint, p2);  
            return angle1.CompareTo(angle2);  
        });  

        // 3. 初始化栈  
        Stack<Point2d> hull = new Stack<Point2d>();  
        hull.Push(minPoint);      // 压入基准点  
        hull.Push(points[0]);     // 压入第一个排序后的点  

        // 4. 遍历剩余点,构建凸包  
        for (int i = 1; i < points.Count; i++)  
        {  
            while (hull.Count >= 2)  
            {  
                Point2d top = hull.Pop(); // 弹出栈顶元素  
                Point2d nextToTop = hull.Peek(); // 获取当前栈顶的下一个元素  
                // 检查当前点是否为顺时针  
                if (Orientation(nextToTop, top, points[i]) == 2) // 右转  
                {  
                    hull.Push(top);    // 若是右转,维持栈顶元素  
                    break;  
                }  
            }  
            hull.Push(points[i]); // 压入当前点  
        }  

        // 结果为栈内点的列表  
        return new List<Point2d>(hull);  
    }  

    // 主程序  
    static void Main(string[] args)  
    {  
        // 示例点集  
        List<Point2d> points = new List<Point2d>  
        {  
            new Point2d(0, 3),  
            new Point2d(2, 2),  
            new Point2d(1, 1),  
            new Point2d(2, 1),  
            new Point2d(3, 0),  
            new Point2d(0, 0),  
            new Point2d(3, 3)  
        };  

        // 获取凸包  
        List<Point2d> convexHull = MyConvexHull::GetConvexHull(points);  

        // 输出凸包的顶点  
        Console.WriteLine("Convex Hull:");  
        foreach (var point in convexHull)  
        {  
            Console.WriteLine($"({Point2d.X}, {Point2d.Y})");  
        }  
    }  
}

5、代码步骤说明

5.1、定义 Point2d 类:

  • 该类用于表示二维空间中的点,包含 X 和 Y 坐标,以及一个构造函数用于初始化坐标。

5.2、极角计算:

  • PolarAngle(Point p0, Point p1):接受两个点,计算第二个点相对于第一个点形成的极角。使用 Math.Atan2() 函数来求取两点之间的角度,返回值为弧度。

5.3、方向判断:

  • Orientation(Point2d p, Point2d q, Point2d r):此函数通过计算三点的叉积来判断它们的相对方向。返回值表示这三点的关系,能够帮助我们判断当前点是向“左转”、“右转”还是“共线”。

5.4、获取凸包的主函数:

5.4.1、GetConvexHull(List<Point2d> points)该函数实现了 Graham Scan 算法的核心逻辑,输入一个点的列表并返回构成凸包的点。、

  • 步骤一:

    找到最底部点:遍历点集,找到 Y 坐标最低的点,将其作为基准点。

  • 步骤二:

    对所有点(包括基准点)按相对于基准点的极角进行排序。

  • 步骤三:

    初始化栈:创建栈并将基准点和第一个排序后的点推入栈中。

  • 步骤四:

    构建凸包:遍历剩余的点:

    1. 弹出栈顶元素,检查当前点与栈顶前两个点的方向。

    2. 如果是右转,保留后面的点,继续弹出直到遇到左转或栈中的点少于两个。

    3. 将当前点压入栈中。

5.4.2、返回值:栈中的点即为构成凸包的点。

5.5、主程序:

  • 创建一个示例点集。

  • 调用 GetConvexHull(points) 获取凸包,接着打印输出结果。

6、总结

        该代码通过 Graham Scan 算法实现了一个有效的二维空间的凸包计算。利用栈结构和极角排序,能够高效地构建并返回凸包顶点。通过对代码的逐步解析,我们可以清楚地理解每个步骤的目的和意义,能够较好扩展到其他相关的几何计算中。

  更多学习内容,可关注公众号:

 

以上内容为个人测试过程的记录,供大家参考。

内容如有错欢迎批评指正,谢谢!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2107990.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谈谈AI领域的认知误区、机会点与面临的挑战

谈谈AI领域的认知误区、机会点与面临的挑战 最近2年&#xff0c;AI 技术的火爆&#xff0c;到处都能看到大家在讨论AI 的发展与机会。这里我们讨论一下AI 认知的误区&#xff0c;机会点和面临的挑战。 by kimmking AI 认知的误区 这年头掀起了所有人讨论AI热潮的同时&#xf…

使用C语言实现字符推箱子游戏

使用C语言实现字符推箱子游戏 推箱子&#xff08;Sokoban&#xff09;是一款经典的益智游戏&#xff0c;玩家通过移动角色将箱子推到目标位置。本文将带你一步步用C语言实现一个简单的字符版本的推箱子游戏。 游戏规则 玩家只能推箱子&#xff0c;不能拉箱子。只能将箱子推到…

【内容审核】对审核结果进行封装

目录 1、分析返回结果示例 2、自定义封装类 在【内容审核】Java实现七牛云内容审核功能七牛 java 审核-CSDN博客 中实现了文本、图片和视频的审核功能&#xff0c;但是这些功能灵活性不够&#xff0c;既不能自己设置审核的强度&#xff0c;也不能内容违规的详细信息&#xff…

【教学类-52-08】20240905动物数独(6宫格)一页2张任务卡,一页一个动物贴图卡,有答案

背景需求&#xff1a; 前文提到6宫格数独的图片6*636图&#xff0c;如果将6张任务卡放在一个A4上&#xff0c;看上去6种动物很小&#xff0c;所以我换了一个word模板&#xff0c;变成了2张任务卡放在一个A4上。 【教学类-52-07】20240903动物数独&#xff08;6宫格&#xff0…

dp练习【4】

最长数对链 646. 最长数对链 给你一个由 n 个数对组成的数对数组 pairs &#xff0c;其中 pairs[i] [lefti, righti] 且 lefti < righti 。 现在&#xff0c;我们定义一种 跟随 关系&#xff0c;当且仅当 b < c 时&#xff0c;数对 p2 [c, d] 才可以跟在 p1 [a, b…

003: Visual Studio 配置 VTK 开发环境的方法与比较

目录 简介&#xff1a; 1 配置属性方法&#xff1a; 2 创建配置文件 3 在新项目中导入props文件 总结&#xff1a; 简介&#xff1a; 编译好VTK后&#xff0c;在安装目录里面有通常有包含bin,lib和include等文件夹&#xff0c;要在自己的项目里面使用VTK&#xff0c;主要…

如何用c++判断一个类型是vector

如何用c判断一个类型是vector 我们使用模板元编程来搞定 这里我们可以定义一个模板结构体 is_std_vector&#xff0c;并对其进行特化&#xff0c;以便专门处理 std::vector 类型。 . 下面是详细的实现和使用示例。 实现 is_std_vector 类型, 继承自false_type 首先&#xff…

Unexpected token d in JSON at position 5, check bodyParser config错误解决

错误原因&#xff1a;json格式不对 { desc"设备1", iotProjectId11 } 解决&#xff1a;通过json在线校验格式校验json格式&#xff0c;找出错误原因&#xff0c;修改 在线JSON校验格式化工具&#xff08;Be JSON&#xff09; 修改&#xff1a; {"desc": &…

基于SpringBoot的校园博客系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架 工具&#xff1a;IDEA/Eclipse、Navicat、Maven、Tomcat 系统展示 首页 博主管理…

使用 MongoDB 构建 AI:Patronus 如何自动进行大语言模型评估来增强对生成式 AI 的信心

大语言模型可能不可靠&#xff0c;这几乎算不上头条新闻。对于某些用例&#xff0c;这可能会带来不便。而对于其他行业&#xff0c;尤其是受监管行业&#xff0c;后果则要严重得多。于是&#xff0c;业内首个大语言模型自动评估平台 Patronus AI 应运而生。 Patronus AI 由 Met…

为啥给的贷款额度差距那么大?机构到底是怎么决定给你多少额度?

今日&#xff0c;我们深入探讨一个颇为引人入胜的话题——为何在不同银行或信贷机构申请贷款时&#xff0c;所能获得的额度竟能如此大相径庭&#xff1f;同时&#xff0c;揭秘这些金融机构背后是如何精密计算并决定每位申请者的“额度”的。以下内容干货满满&#xff0c;建议收…

10 先序遍历创建二叉树

这个代码是使用手动输入的方式创建二叉树 比较直观 #include "stdio.h" #include "stdlib.h"typedef int ElemType; typedef struct node {ElemType data;struct node *lchild;struct node *rchild; } Node;Node *create_node(int value) {Node *node (N…

2024国赛数学建模B题思路模型

完整的思路模型请查看文末名片

2024 年高教社杯全国大学生数学建模竞赛题目【A/B/C/D/E题】完整思路

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ A题是数模类赛事很常见的物理类赛题&#xff0c;需要学习不少相关知识。此题涉及对一个动态系统的建模&#xff0c;模拟…

弹框用户勾选过得置灰 或者不显示

弹框用户勾选过得置灰 或者不显示 添加 :disabled“row.disabled” <el-table-column label"名称" width"300"><template #default"{ row }"><el-radio:disabled"row.disabled":label"row.coursesName"v-mo…

中秋节如何利用Python发送彩信

中秋节&#xff0c;作为中国传统节日之一&#xff0c;不仅是家人团聚的时刻&#xff0c;也是商家提高销售业绩的黄金时期。在这个充满温情与消费氛围的节日里&#xff0c;合理利用短信平台进行精准营销&#xff0c;可以显著提高企业的销售业绩。 支持免费对接试用乐讯通PaaS平台…

【全网最全】2024年数学建模国赛B题保奖思路+成品论文+matlab/python代码等(后续会更新

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击末文的卡片&#xff0c;那是获取资料的入口&#xff01; 一、问题重述 本题聚焦于某电子产品制造企业在生产过程中的决策问题。企业在生产中需采购 和使用两种关键零配件&#xff0c;并在装配过程中面临如何优化质…

让Mac更Mac|明基MA系列显示器上市

凭借出色的性能和设计&#xff0c;MacBook成为了很多人的心头好。可13~16英寸的屏幕&#xff0c;时常让人感到视野受限&#xff0c;就像无边创意中的一道隐形壁垒。想要外接显示大屏&#xff0c;但除了Studio Display等苹果显示器之外&#xff0c;其他品牌的外接显示屏&#xf…

优化器与现有网络模型的修改

一、优化器 optimizer optim.SGD(model.parameters(), lr0.01&#xff08;学习速率&#xff09;, momentum0.9) optimizer optim.Adam([var1, var2], lr0.0001) 一般&#xff0c;学习率的设置&#xff0c;先从大的设置&#xff0c;逐渐变小。 神经网络可以参见上篇文章&am…

【数据库】MySQL-基础篇-函数

专栏文章索引&#xff1a;数据库 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、简介 二、字符串函数 三、数值函数 四、日期函数 五、流程函数 一、简介 函数 是指一段可以直接被另一段程序调用的程序或代码。 也就意味着&#xff0c;这一段程序或代码在 M…