C-10 凸包

凸包

数学定义

  • 平面的一个子集S被称为是凸的,当且仅当对于任意两点A,B属于S,线段PS都完全属于S
  • 过于基础就不详细介绍了
    在这里插入图片描述

凸包的计算

  • github上找到了别人的代码,用4种方式实现了凸包的计算,把他放在这里
  • 链接地址https://github.com/MiguelVieira/ConvexHull2D
  • 先放这个代码的用法吧
int main() {vector<point> v = getPoints();
//1vector<point> h = quickHull(v);cout << "quickHull point count: " << h.size() << endl;print(h);//2h = giftWrapping(v);cout << endl << "giftWrapping point count: " << h.size() << endl;print(h);//3h = monotoneChain(v);cout << endl << "monotoneChain point count: " << h.size() << endl;print(h);//4h = GrahamScan(v);cout << endl << "GrahamScan point count: " << h.size() << endl;print(h);
  • 这是具体的代码,直接写在一个头文件里,包含一下就能在程序里实现上面的诸多用法了
#include <algorithm>
#include <iostream>
#include <vector>
#include<random>using namespace std;
namespace ch{struct point {float x;float y;point(float xIn, float yIn) : x(xIn), y(yIn) { }};// The z-value of the cross product of segments // (a, b) and (a, c). Positive means c is ccw// from (a, b), negative cw. Zero means its collinear.float ccw(const point& a, const point& b, const point& c) {return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);}// Returns true if a is lexicographically before b.bool isLeftOf(const point& a, const point& b) {return (a.x < b.x || (a.x == b.x && a.y < b.y));}// Used to sort points in ccw order about a pivot.struct ccwSorter {const point& pivot;ccwSorter(const point& inPivot) : pivot(inPivot) { }bool operator()(const point& a, const point& b) {return ccw(pivot, a, b) < 0;}};// The length of segment (a, b).float len(const point& a, const point& b) {return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));}// The unsigned distance of p from segment (a, b).float dist(const point& a, const point& b, const point& p) {return fabs((b.x - a.x) * (a.y - p.y) - (b.y - a.y) * (a.x - p.x)) / len(a, b);}// Returns the index of the farthest point from segment (a, b).size_t getFarthest(const point& a, const point& b, const vector<point>& v) {size_t idxMax = 0;float distMax = dist(a, b, v[idxMax]);for (size_t i = 1; i < v.size(); ++i) {float distCurr = dist(a, b, v[i]);if (distCurr > distMax) {idxMax = i;distMax = distCurr;}}return idxMax;}// The gift-wrapping algorithm for convex hull.// https://en.wikipedia.org/wiki/Gift_wrapping_algorithmvector<point> giftWrapping(vector<point> v) {// Move the leftmost point to the beginning of our vector.// It will be the first point in our convext hull.swap(v[0], *min_element(v.begin(), v.end(), isLeftOf));vector<point> hull;// Repeatedly find the first ccw point from our last hull point// and put it at the front of our array. // Stop when we see our first point again.do {hull.push_back(v[0]);swap(v[0], *min_element(v.begin() + 1, v.end(), ccwSorter(v[0])));} while (v[0].x != hull[0].x && v[0].y != hull[0].y);return hull;}// The Graham scan algorithm for convex hull.// https://en.wikipedia.org/wiki/Graham_scanvector<point> GrahamScan(vector<point> v) {// Put our leftmost point at index 0swap(v[0], *min_element(v.begin(), v.end(), isLeftOf));// Sort the rest of the points in counter-clockwise order// from our leftmost point.sort(v.begin() + 1, v.end(), ccwSorter(v[0]));// Add our first three points to the hull.vector<point> hull;auto it = v.begin();hull.push_back(*it++);hull.push_back(*it++);hull.push_back(*it++);while (it != v.end()) {// Pop off any points that make a convex angle with *itwhile (ccw(*(hull.rbegin() + 1), *(hull.rbegin()), *it) >= 0) {hull.pop_back();}hull.push_back(*it++);}return hull;}// The monotone chain algorithm for convex hull.vector<point> monotoneChain(vector<point> v) {// Sort our points in lexicographic order.sort(v.begin(), v.end(), isLeftOf);// Find the lower half of the convex hull.vector<point> lower;for (auto it = v.begin(); it != v.end(); ++it) {// Pop off any points that make a convex angle with *itwhile (lower.size() >= 2 && ccw(*(lower.rbegin() + 1), *(lower.rbegin()), *it) >= 0) {lower.pop_back();}lower.push_back(*it);}// Find the upper half of the convex hull.vector<point> upper;for (auto it = v.rbegin(); it != v.rend(); ++it) {// Pop off any points that make a convex angle with *itwhile (upper.size() >= 2 && ccw(*(upper.rbegin() + 1), *(upper.rbegin()), *it) >= 0) {upper.pop_back();}upper.push_back(*it);}vector<point> hull;hull.insert(hull.end(), lower.begin(), lower.end());// Both hulls include both endpoints, so leave them out when we // append the upper hull.hull.insert(hull.end(), upper.begin() + 1, upper.end() - 1);return hull;}// Recursive call of the quickhull algorithm.void quickHull(const vector<point>& v, const point& a, const point& b,vector<point>& hull) {if (v.empty()) {return;}point f = v[getFarthest(a, b, v)];// Collect points to the left of segment (a, f)vector<point> left;for (auto p : v) {if (ccw(a, f, p) > 0) {left.push_back(p);}}quickHull(left, a, f, hull);// Add f to the hullhull.push_back(f);// Collect points to the left of segment (f, b)vector<point> right;for (auto p : v) {if (ccw(f, b, p) > 0) {right.push_back(p);}}quickHull(right, f, b, hull);}// QuickHull algorithm. // https://en.wikipedia.org/wiki/QuickHullvector<point> quickHull(const vector<point>& v) {vector<point> hull;// Start with the leftmost and rightmost points.point a = *min_element(v.begin(), v.end(), isLeftOf);point b = *max_element(v.begin(), v.end(), isLeftOf);// Split the points on either side of segment (a, b)vector<point> left, right;for (auto p : v) {ccw(a, b, p) > 0 ? left.push_back(p) : right.push_back(p);}// Be careful to add points to the hull// in the correct order. Add our leftmost point.hull.push_back(a);// Add hull points from the left (top)quickHull(left, a, b, hull);// Add our rightmost pointhull.push_back(b);// Add hull points from the right (bottom)quickHull(right, b, a, hull);return hull;}vector<point> getPoints() {vector<point> v;std::default_random_engine e(std::random_device{}());std::uniform_real_distribution<double> dist_x(0.05, 0.95);std::uniform_real_distribution<double> dist_y(0.05, 0.95);for (int i = 0; i < 30; ++i) {v.push_back(point(dist_x(e), dist_y(e)));}return v;}
}

可视化实现

这个exe小程序我放在主页了,大家可以免费下载,之后会创建一个仓库把代码公开出来,大家就可以在我的基础上实现更多的几何算法。
请添加图片描述

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

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

相关文章

redis运维:sentinel模式如何查看所有从节点

1. 连接到sentinel redis-cli -h sentinel_host -p sentinel_port如&#xff1a; redis-cli -h {域名} -p 200182. 发现Redis主服务器 连接到哨兵后&#xff0c;我们可以使用SENTINEL get-master-addr-by-name命令来获取当前的Redis主服务器的地址。 SENTINEL get-master-a…

Python骨架肌体运动学数学模型

&#x1f3af;要点 &#x1f3af;运动学矢量计算 | &#x1f3af;跳远的运动学计算 | &#x1f3af;关节肢体运动最小加加速度模型 | &#x1f3af;膝关节和踝关节角度二维运动学计算 | &#x1f3af;上下肢体关节连接运动链数学模型 | &#x1f3af;刚体连接点速度加速度计算…

[python]Markdown图片引用格式批处理桌面应用程序

需求 使用python编写一个exe&#xff0c;实现批量修改图片引用&#xff0c;将修改后的文件生成为 文件名_blog.md。有一个编辑框&#xff0c;允许接收拖动过来md文件&#xff0c;拖入文件时获取文件路径&#xff0c;有一个编辑框编辑修改后的文件的输出路径&#xff0c;用户拖入…

Springboot实战:AI大模型+亮数据代理助力短视频时代

目录 前言1.如何入门亮数据1.1、注册登录1.2、注册账号1.3、登录1.4、购买静态住宅代理1.5、展示购买的代理 2. 使用Springboot、AI大模型构建系统2.1 使用Springboot、AI大模型构建爬虫2.2、在Springboot项目添加工具 3、编写代码&#xff0c;爬取视频素材3.1、代码里使用代理…

Redis核心问题总结(一)

1、为什么要使用Redis做缓存 缓存的好处 使用缓存的目的就是提升读写性能。而实际业务场景下&#xff0c;更多的是为了提升读性能&#xff0c;带来更好的性 能&#xff0c;带来更高的并发量。Redis 的读写性能比 Mysql 好的多&#xff0c;我们就可以把 Mysql 中的热点数据缓 …

提升结构安全性:应变计在现代建筑中的应用

在现代建筑领域&#xff0c;随着工程技术的不断进步&#xff0c;对结构安全性的要求也日益提高。作为一种关键的工程仪器仪表&#xff0c;应变计在提升结构安全性方面发挥着不可替代的作用。本文将深入探讨应变计在现代建筑中的应用&#xff0c;以及它如何助力工程师们实时监测…

权力之望怎么注册账号创建角色 权利之网角色账号注册教程

权力之望是一款全新的大型MMORPG游戏&#xff0c;拥有9把独特武器和56种职业组合&#xff0c;并搭配了超炫酷的战斗画面&#xff0c;全程采用低俯视角游戏&#xff0c;让玩家能体验到更强的操作感和爽快感。这款游戏主打高养成自由度玩家可以自由更换武器进行战斗&#xff0c;还…

前端面试题30(闭包和作用域链的关系)

闭包和作用域链在JavaScript中是紧密相关的两个概念&#xff0c;理解它们之间的关系对于深入掌握JavaScript的执行机制至关重要。 作用域链 作用域链是一个链接列表&#xff0c;它包含了当前执行上下文的所有父级执行上下文的变量对象。每当函数被调用时&#xff0c;JavaScri…

零基础也能成为产品册设计高手

​在当今数字化时代&#xff0c;产品册设计已成为企业营销的重要手段之一。过去&#xff0c;人们认为只有专业人士才能设计出精美的产品册&#xff0c;然而&#xff0c;随着设计工具的普及和在线学习资源的丰富&#xff0c;零基础的你也能成为产品册设计高手。本文将带你走进这…

MindsDB:一个利用企业数据构建 AI 的平台

MindsDB作为一个开源项目&#xff0c;它旨在将机器学习模型无缝集成到现有的数据库系统中&#xff0c;为用户提供实时的数据预测能力。这个项目的创新之处在于&#xff0c;它能够以简单、直观的方式让开发者和非技术人员都能够利用AI进行数据分析和预测。 它是根据企业数据库定…

航空航天单位保密网文件导出管理难点在哪里?如何解决?

航空航天单位的重要性不言而喻&#xff0c;它们在国家安全、科技进步、经济发展以及国际合作等多个领域都扮演着至关重要的角色。为了保护工作内容中的重要数据&#xff0c;遵守保密规定&#xff0c;对涉密人员、保密要害部门单位、涉密载体、涉密信息传输和涉密活动进行严格管…

glide加载mp4 源码堆栈调用核心代码分析

load 数据走的httpurlfetcher 的loaddata 从MultiLoader 调用而来 load到inputstream流后的处理 核心 图片是glide 首先创建解释器的时候 加了videodecoder 然后这里会从流中加载对应帧的图片保存在手机cache目录中 将这个file 作为bitmap传递 然后加载 private static final…

2.5 C#视觉程序开发实例1----CamManager实现模拟相机采集图片

2.5 C#视觉程序开发实例1----CamManager实现模拟相机采集图片 1 目标效果视频 CamManager 2 CamManager读取本地文件时序 3 BD_Vision_Utility添加代码 3.0 导入链接库 BD_OperatorSets.dllSystem.Windows.Forms.dllOpencvSharp 3.1 导入VisionParam中创建的文件Util_FileO…

安防监控/视频汇聚平台EasyCVR设备录像回看请求播放时间和实际时间对不上,是什么原因?

安防监控EasyCVR视频汇聚平台可提供多协议&#xff08;RTSP/RTMP/国标GB28181/GAT1400/海康Ehome/大华/海康/宇视等SDK&#xff09;的设备接入、音视频采集、视频转码、处理、分发等服务&#xff0c;系统具备实时监控、云端录像、回看、告警、平台级联以及多视频流格式分发等视…

旅游计划定制小程序网页模板源码

手机在线旅游定制服务&#xff0c;定制旅游出行app小程序模板。包含&#xff1a;定制介绍、定制表单填写、我的订单等。 旅游计划定制小程序网页模板源码

swiftui中NavigationStack布局navigationBarTitleDisplayMode作用,以及内容顶部空白区域解决办法

写了一个小demo用于学习NavigationStack和toolbar/ToolbarItem知识&#xff0c;但是在写一个瀑布流布局的时候&#xff0c;设置了顶部的toolbar&#xff0c;然后内容区域的顶部出现了一大片空白区域&#xff0c;这样的效果并不是很美观很好看&#xff0c;所以就想着研究解决一下…

科普文:一文搞懂SpringBoot(狂神说Java)

1、Hello,World&#xff01; 1.1、SpringBoot简介 回顾什么是Spring Spring是一个开源框架&#xff0c;2003 年兴起的一个轻量级的Java 开发框架&#xff0c;作者&#xff1a;Rod Johnson 。 Spring是为了解决企业级应用开发的复杂性而创建的&#xff0c;简化开发。 Spring是…

clickhouse学习笔记(五)SQL操作

目录 一、增 二、删改 三、查询以及各种子句 1、with子句 a、表达式为常量 b、表达式为函数调用 c、表达式为子查询 2、from子句 3、array join子句 a、INNER ARRAY JOIN b、LEFT ARRAY JOIN c、数组的一些函数 groupArray groupUniqArray arrayFlatten splitBy…

2005-2023年各省居民人均消费支出、城镇居民人均消费支出、农村居民人均消费支出数据(无缺失)

2005-2023年各省居民人均消费支出、城镇居民人均消费支出、农村居民人均消费支出数据&#xff08;无缺失&#xff09; 1、时间&#xff1a;2005-2023年 2、来源&#xff1a;国家统计局、统计年鉴 3、范围&#xff1a;31省 4、指标&#xff1a;全体居民人均消费支出、城镇居…

Windows netstat命令详解,Windows查看网络连接

「作者简介」&#xff1a;冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础著作 《网络安全自学教程》&#xff0c;适合基础薄弱的同学系统化的学习网络安全&#xff0c;用最短的时间掌握最核心的技术。 netstat 常用来…