当前位置: 首页 > news >正文

Greiner–Hormann裁剪算法深度探索:C++实现与应用案例

介绍

在计算几何中,裁剪是一个核心的主题。特别是,多边形裁剪已经被广泛地应用于计算机图形学,地理信息系统和许多其他领域。Greiner-Hormann裁剪算法是其中之一,提供了一个高效的方式来计算两个多边形的交集、并集等。在本文中,我们将深入探讨这一算法,并为您提供一个基于C++的实现。


算法概述

Greiner-Hormann算法基于边界交点的概念,即两个多边形的交点。算法的关键思想是找到这些交点,并根据需要合并多边形的顶点。

  1. 找到所有的交点:遍历多边形A和B的所有边,找到它们的交点。
  2. 排序交点:按照它们在多边形边上的位置对交点进行排序。
  3. 连接交点:使用链接交点来形成新的多边形。
  4. 得到结果多边形:得到交集、并集或差集,取决于所需的操作。

C++实现

为了简单起见,我们假设点是一个简单的结构,并有一个函数来计算两条线段的交点。

struct Point {double x, y;Point(double x = 0, double y = 0) : x(x), y(y) {}
};bool findIntersection(Point p1, Point q1, Point p2, Point q2, Point &intersec) {// ... (交点的计算代码)
}

为了表示多边形,我们使用点的列表:

using Polygon = std::vector<Point>;

现在,让我们开始寻找两个多边形之间的所有交点。

std::vector<Point> findIntersections(const Polygon &polyA, const Polygon &polyB) {std::vector<Point> intersections;for(size_t i = 0; i < polyA.size(); i++) {Point p1 = polyA[i];Point q1 = (i == polyA.size() - 1) ? polyA[0] : polyA[i + 1];for(size_t j = 0; j < polyB.size(); j++) {Point p2 = polyB[j];Point q2 = (j == polyB.size() - 1) ? polyB[0] : polyB[j + 1];Point intersec;if(findIntersection(p1, q1, p2, q2, intersec)) {intersections.push_back(intersec);}}}return intersections;
}

此代码片段首先初始化一个空的交点列表。然后,它遍历polyApolyB的每条边,使用findIntersection函数来确定它们是否有交点。如果找到交点,它会添加到交点列表中。

排序交点

为了确保算法的正确性,我们需要按照它们在多边形上的位置对交点进行排序。这确保了当我们形成新的多边形时,交点被正确地处理。

void sortIntersections(Polygon &poly, std::vector<Point> &intersections) {std::sort(intersections.begin(), intersections.end(), [&poly](const Point &a, const Point &b) -> bool {// 为每个交点找到其在多边形上的位置size_t posA = std::distance(poly.begin(), std::find(poly.begin(), poly.end(), a));size_t posB = std::distance(poly.begin(), std::find(poly.begin(), poly.end(), b));return posA < posB;});
}

此函数接受多边形和其交点列表作为参数,然后按照交点在多边形上的位置进行排序。

连接交点以形成新的多边形

一旦我们有了排序后的交点,我们就可以开始构造新的多边形。

Polygon constructNewPolygon(const Polygon &polyA, const Polygon &polyB, const std::vector<Point> &intersections) {Polygon result;// 使用一个标记数组来跟踪哪些交点已经被处理std::vector<bool> visited(intersections.size(), false);// 开始于多边形A的第一个点result.push_back(polyA[0]);for (size_t i = 1; i <= polyA.size(); i++) {Point current = (i == polyA.size()) ? polyA[0] : polyA[i];// 查找是否有交点auto it = std::find(intersections.begin(), intersections.end(), current);if (it != intersections.end() && !visited[std::distance(intersections.begin(), it)]) {// 标记交点为已访问visited[std::distance(intersections.begin(), it)] = true;// 将交点添加到结果多边形中result.push_back(*it);// 转到另一个多边形并遍历其边,直到遇到另一个交点const Polygon &otherPoly = (polyA == polyB) ? polyB : polyA;size_t j = std::distance(otherPoly.begin(), std::find(otherPoly.begin(), otherPoly.end(), *it));do {j = (j + 1) % otherPoly.size();result.push_back(otherPoly[j]);} while (std::find(intersections.begin(), intersections.end(), otherPoly[j]) == intersections.end());} else {result.push_back(current);}}return result;
}

这个函数首先初始化了一个空的多边形和一个标记数组,用于跟踪哪些交点已经被处理。然后,它遍历polyA的每个顶点,并检查它是否是一个交点。如果是,并且还没有被访问过,它将开始遍历polyB,直到找到另一个交点为止。

结论和进一步的应用

从上面的C++实现中,我们可以看到Greiner-Hormann裁剪算法是如何工作的。这种算法的优点是它对于复杂的多边形也能高效工作,而且它的理论基础使得它可以很容易地适应各种应用场景。

例如,此算法不仅限于2D平面上的裁剪。通过在三维空间中考虑多边形,或者在N维空间中进行一些扩展,我们可以将此方法用于更高维度的空间。

此外,这种算法在图形渲染、地理信息系统、碰撞检测等领域都有应用。其准确性和效率使它成为处理这些问题的理想选择。

总结

Greiner-Hormann裁剪算法为我们提供了一个强大的工具,可以用来解决多边形裁剪中的各种问题。不仅如此,由于其底层原理和结构的普遍性,它可以被扩展到多种不同的应用中。上面提供的C++实现只是开始,您可以根据需要对其进行扩展或修改,使其适应您的特定需求。

感谢您的耐心阅读!希望这篇文章为您提供了有价值的信息和启示。

相关文章:

Greiner–Hormann裁剪算法深度探索:C++实现与应用案例

介绍 在计算几何中&#xff0c;裁剪是一个核心的主题。特别是&#xff0c;多边形裁剪已经被广泛地应用于计算机图形学&#xff0c;地理信息系统和许多其他领域。Greiner-Hormann裁剪算法是其中之一&#xff0c;提供了一个高效的方式来计算两个多边形的交集、并集等。在本文中&…...

Automatically Correcting Large Language Models

本文是大模型相关领域的系列文章&#xff0c;针对《Automatically Correcting Large Language Models: Surveying the landscape of diverse self-correction strategies》的翻译。 自动更正大型语言模型&#xff1a;综述各种自我更正策略的前景 摘要1 引言2 自动反馈校正LLM的…...

【学习FreeRTOS】第8章——FreeRTOS列表和列表项

1.列表和列表项的简介 列表是 FreeRTOS 中的一个数据结构&#xff0c;概念上和链表有点类似&#xff0c;列表被用来跟踪 FreeRTOS中的任务。列表项就是存放在列表中的项目。 列表相当于链表&#xff0c;列表项相当于节点&#xff0c;FreeRTOS 中的列表是一个双向环形链表列表的…...

分布式图数据库 NebulaGraph v3.6.0 正式发布,强化全文索引能力

本次 v3.6.0 版本&#xff0c;主要强化全文索引能力&#xff0c;以及优化部分场景下的 MATCH 性能。 强化 强化增强全文索引功能&#xff0c;具体 pr 参见&#xff1a;#5567、#5575、#5577、#5580、#5584、#5587 优化 支持使用 MATCH 子句检索 VID 或属性索引时使用变量&am…...

在 ubuntu 18.04 上使用源码升级 OpenSSH_7.6p1到 OpenSSH_9.3p1

1、检查系统已安装的当前 SSH 版本 使用命令 ssh -V 查看当前 ssh 版本&#xff0c;输出如下&#xff1a; OpenSSH_7.6p1 Ubuntu-4ubuntu0.7, OpenSSL 1.0.2n 7 Dec 20172、安装依赖&#xff0c;依次执行以下命令 sudo apt update sudo apt install build-essential zlib1g…...

python中可以处理word文档的模块:docx模块

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 话不多说&#xff0c;直接开搞&#xff0c;如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 一.docx模块 Python可以利用python-docx模块处理word文档&#xff0c;处理方式是面向对象的。 也就是说python-docx模块…...

TikTok或将于8月底关闭半闭环、速卖通或将推出“半托管”模式

《出海周报》是运营坛为外贸企业主和外贸人独家打造的重要资讯栏目&#xff0c;聚焦企业出海、海外市场动态、海外监管政策等方面&#xff0c;以简捷的方式&#xff0c;提升读者获取资讯的效率。 接下来运营坛为大家带来第15期出海周报&#xff0c;快来看看这周国内外市场发生了…...

《凤凰架构》第二章——访问远程服务

前言 这章挺难的&#xff0c;感觉离我比较远&#xff0c;不太好懂&#xff0c;简单记录吧。 这章主要讲访问远程服务&#xff0c;主要对比了RPC和REST的区别&#xff0c;可以结合知乎上的文章《既然有 HTTP 请求&#xff0c;为什么还要用 RPC 调用&#xff1f;》 这篇文章进行…...

【Diffusion】李宏毅2023机器学习Diffusion笔记

文章目录 1 想法概述2 实际过程阶段1 Add Noise阶段2 Denoise 3 数学原理4 为什么推理时要额外加入noise5 一些不知道对不对的Summary 1 想法概述 从一张充满噪声的图中不断denoise&#xff0c;最终得到一张clear的图片。为了确定当前图片中噪声占比的大小&#xff0c;同时输入…...

CloudEvents—云原生事件规范

我们的系统中或多或少都会用到如下两类业务技术&#xff1a; 异步任务&#xff0c;用于降低接口时延或削峰&#xff0c;提升用户体验&#xff0c;降低系统并发压力&#xff1b;通知类RPC&#xff0c;用于微服务间状态变更&#xff0c;用户行为的联动等场景&#xff1b; 以上两种…...

神经网络基础-神经网络补充概念-51-局部最优问题

概念 局部最优问题是在优化问题中常见的一个挑战&#xff0c;特别是在高维、非凸、非线性问题中。局部最优问题指的是算法在优化过程中陷入了一个局部最小值点&#xff0c;而不是全局最小值点。这会导致优化算法在某个局部区域停止&#xff0c;而无法找到更好的解。 解决方案…...

深度学习中,什么是batch-size?如何设置?

什么是batch-size? batch-size 是深度学习模型在训练过程中一次性输入给模型的样本数量。它在训练过程中具有重要的意义&#xff0c;影响着训练速度、内存使用以及模型的稳定性等方面。 以下是 batch-size 大小的一些影响和意义&#xff1a; 训练速度&#xff1a;较大的 bat…...

[保研/考研机试] KY26 10进制 VS 2进制 清华大学复试上机题 C++实现

题目链接&#xff1a; 10进制 VS 2进制http://www.nowcoder.com/share/jump/437195121691738172415 描述 对于一个十进制数A&#xff0c;将A转换为二进制数&#xff0c;然后按位逆序排列&#xff0c;再转换为十进制数B&#xff0c;我们称B为A的二进制逆序数。 例如对于十进制…...

JSP-学习笔记

文章目录 1.JSP介绍2 JSP快速入门3 JSP 脚本3.1 JSP脚本案例3.2 JSP缺点 4 EL表达式4.1 快速入门案例 5. JSTL标签6. MVC模式和三层架构6.1 MVC6.2 三层架构 7. 案例-基于MVC和三层架构实现商品表的增删改查 1.JSP介绍 概念 JSP&#xff08;JavaServer Pages&#xff09;是一种…...

Golang协程,通道详解

进程、线程以及并行、并发 关于进程和线程 进程&#xff08;Process&#xff09;就是程序在操作系统中的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff0c;进程是一个动态概念&#xff0c;是程序在执行过程中分配和管理资源的基本单位&#xff0c;每一…...

unity 之 Vector 数据类型

文章目录 Vector 1Vector 2Vector 3Vector 4 Vector 1 在Unity中&#xff0c;Vector1 并不是一个常见的向量类型。 如果您需要表示标量&#xff08;单个值&#xff09;或者只需要一维的数据&#xff0c;通常会直接使用浮点数&#xff08;float&#xff09;或整数&#xff08;in…...

私密数据采集:隧道爬虫IP技术的保密性能力探究

作为一名专业的爬虫程序员&#xff0c;今天要和大家分享一个关键的技术&#xff0c;它能够为私密数据采集提供保密性能力——隧道爬虫IP技术。如果你在进行敏感数据采集任务时需要保护数据的私密性&#xff0c;那么这项技术将是你的守护神。 在进行私密数据采集任务时&#xff…...

使用git rebase 之后的如何恢复到原始状态

我们常常喜欢使用git rebase去切换分支提交代码,操作流程就是: 先切换分支:比如当前是master 我们修改了一堆代码产生一个commit id :5555555567777 那么我们常常比较懒就直接切换了:git checkout dev 然后呢?使用命令git rebase 5555555567777,想把这笔修改提交到d…...

matlab相机标定知识整理

matlab相机标定知识整理 单目相机标定 单目相机标定 内参矩阵&#xff1a;cameraParams.Intrinsics.K 或者 cameraParams.K旋转矩阵&#xff1a;cameraParams.RotationMatrices 有待确定 cameraParams.RotationVectors平移矩阵&#xff1a;cameraParams.TranslationVectors径向…...

win11安装ubuntu 子系统安装过程及注意事项

第一步 &#xff1a;安装系统必须组件 由于子系统是系统自带组件&#xff0c;需要安装软件支持 第二步&#xff1a;应用商店安装 ubuntu 编辑 编辑 这个时候打开会报错 第三步&#xff0c;运行linux子系统 选择Windows PowerShell 以管理员身份运行&#xff09; 输入&#…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)

前言&#xff1a; 在Java编程中&#xff0c;类的生命周期是指类从被加载到内存中开始&#xff0c;到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期&#xff0c;让读者对此有深刻印象。 目录 ​…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...