清华计算几何-ConvexHull(凸包)-求极点InTriangle/ToLeft Test

ConvexHull(凸包)

凸包是什么

凸包是计算几何一个非常基础核心的概念。我理解的凸包就是给定一个点集合, 最外围的点的包围体就是凸包。如下所示:

极点(ExtremityPoint)

给定的点集合中, 如果一个点存在一条直线, 让其他所有点都在于该直线的同一侧, 则该点为极点。

非极点

和极点性质相反, 经过该点任一直线都无法做到让其他所有点位于同一侧

凸集合

给定一个点集合S = [P1, P2...Pn], 给每个点分配一个权重rx,  满足条件:

[1]rx >= 0 &&rx <= 1, 

[2]r1 + r2 +  ...... rn = 1.0

由 P = r1 * P1 + ..... + Pn * rn 计算公式,  得到新的点集合,成为S的凸组合.

我理解的是点S构成的凸包内部的点集合就是凸组合。

凸相关

给定一个点集合S, 加入一个点A后,凸组合没变化的,就称点A和点集合S是凸相关的。

换一个说法就是, 点A包含在集合S里的凸组合里。

比如给定点S = {1, 4}, 点2或者点3和集合S是凸相关。

凸无关

给定一个点集合S, 加入一个点A后,凸组合发生变化, 就称点A和点集合S是凸无关。

对于点集合S(1, 2, 3), 点4是凸无关.

给定点集合求极点

分解问题

极点满足: 不在点集合构成的所有三角形内部的点, 则为极点。反之为非极点。

伪代码实现

算法复杂度为O(n4)

算法实现

In-Trianle-Test

In-Trianle-Test: 判断一个点是否在一个三角形内.

如果点S在三角形三条边的同一侧, 则在三角形内. 分解为三次ToLeft测试,即点和三角形的三条边的测试.

ToLeft测试

ToLeft测试就是用于判断点是否在一条边的左侧.

叉积面积正负来判断左侧 or 右侧

(CCW 的时候ToLeft 世界左侧返回True, CW的时候ToLeft 世界左侧返回False)

代码实现

给定点集合

代码实现

#include <iostream>
#include <vector>using namespace std;struct Point
{float x;float y;
};float Area2(const Point& inPointA, const Point& inPointB, const Point& inPointC)
{float value =inPointA.x * inPointB.y - inPointA.y * inPointB.x+ inPointB.x * inPointC.y - inPointB.y * inPointC.x+ inPointC.x * inPointA.y - inPointC.y * inPointA.x;return value;
}bool IsLeftTest(const Point& inPointA, const Point& inPointB, const Point& inPointC)
{return Area2(inPointA, inPointB, inPointC) > 0;
}bool IsInTrianle(const Point& inPoint, const Point& triangleA, const Point& triangleB, const Point& triangleC)
{bool bLeftA = IsLeftTest(triangleA, triangleB, inPoint);bool bLeftB = IsLeftTest(triangleB, triangleC, inPoint);bool bLeftC = IsLeftTest(triangleC, triangleA, inPoint);return (bLeftA == bLeftB) && (bLeftB == bLeftC);
}void GetConvexPointSet(const vector<Point>& inPoints, vector<Point>& outPoints)
{int pointNum = inPoints.size();vector<bool> extrmeFlags;extrmeFlags.resize(pointNum);for (int index = 0; index < pointNum; index++){extrmeFlags[index] = true;}// O(n4)for (int idxA = 0; idxA < pointNum; idxA++){for (int idxB = idxA + 1; idxB < pointNum; idxB++){for (int idxC = idxB + 1; idxC < pointNum; idxC++){for (int s = 0; s < pointNum; s++){if (s == idxA || s == idxB || s == idxC || !extrmeFlags[s])continue;if (IsInTrianle(inPoints[s], inPoints[idxA], inPoints[idxB], inPoints[idxC])){extrmeFlags[s] = false;}}}}}for (int index = 0; index < pointNum; index++){if (extrmeFlags[index]){outPoints.push_back(inPoints[index]);}}}int main()
{std::cout << "Hello World!\n";// point set contructvector<Point> inPoints ={{0, 0},{-1, -1},{5, 2},{4, 5},{3, 3},{-1, 3},{2, 2},{-3, 2},};vector<Point> outPoints;GetConvexPointSet(inPoints, outPoints);for (int index = 0; index < outPoints.size(); index++){printf("(%f, %f)\n", outPoints[index].x, outPoints[index].y);}}
运行结果

很显然漏掉了 (-1, -1, -1, -1)

原因是(-1, -1), (0, 0) (2, 2), (3, 3)四点共线导致ToLeft测试失效,误认为也在三角形内部。所以得改进检测算法。

改进In-Trianle-Test

在进行In-Trianle-Test的时候先判断是否四点共线, 然后在进行ToLeftTest

bool IsInTrianle(const Point& inPoint, const Point& triangleA, const Point& triangleB, const Point& triangleC)
{float a_area2 = Area2(triangleA, triangleB, inPoint);float b_area2 = Area2(triangleB, triangleC, inPoint);float c_area2 = Area2(triangleC, triangleA, inPoint);if (a_area2 == 0 && b_area2 == 0 && c_area2 == 0)return false;bool bLeftA = a_area2 > 0;bool bLeftB = b_area2 > 0;bool bLeftC = c_area2 > 0;// 取决于CCW/CWreturn (bLeftA == bLeftB) && (bLeftB == bLeftC);
}
运行结果

参考资料

[1]清华计算几何 P1-P12

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

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

相关文章

如何理解electron 的预加载脚本

在 Electron 应用中,预加载脚本(Preload Script)是一个非常重要的概念,它允许你在渲染进程(web 页面)和主进程之间创建一个安全的桥梁。预加载脚本运行在 Node.js 环境中,但位于渲染进程的一个单独的上下文中,这意味着它可以访问 Node.js 的 API,但无法直接访问 DOM。…

JavaScript进阶(7) ----构造函数和原型对象

目录 构造函数 prototype 定义&#xff1a; 使用场景&#xff1a; constructor 使用场景&#xff1a; 原型proto 原型链 定义 特点 instanceof 运算符 原型继承的基本概念 在JavaScript中&#xff0c;构造函数和原型是面向对象编程的核心概念&#xff0c;它们共同构…

海康工业相机驱动

1.新建基于对话框的MFC程序&#xff0c;界面布局如下 2.修改控件ID&#xff0c;为控件绑定变量 3.创建全局变量&#xff0c;构造函数中初始化变量&#xff0c;初始化对话框界面&#xff0c;补齐各控件按钮响应函数 全文程序如下&#xff1a; // MFC_GrabimageDlg.h : 头文件 /…

【动态规划Ⅰ】斐波那契、爬楼梯、杨辉三角

动态规划—斐波那契系列 什么是动态规划斐波那契数组相关题目509. 斐波那契数 Easy1137. 第 N 个泰波那契数 Easy 杨辉三角118. 杨辉三角 Easy 爬楼梯相关题目70. 爬楼梯 Easy746. 使用最小花费爬楼梯 Easy 什么是动态规划 动态规划是一种通过将原问题分解为相对简单的子问题来…

linux下解压命令

在Linux下&#xff0c;解压缩文件通常涉及多种命令&#xff0c;具体取决于文件的压缩格式。以下是一些常用的解压缩命令&#xff1a; tar.gz / .tgz 如果文件扩展名为 .tar.gz 或 .tgz&#xff0c;你可以使用 tar 命令来解压缩&#xff1a; tar -xzf filename.tar.gz这里的 -x …

近期几首小诗汇总-生活~卷

生活 为生活飘零&#xff0c;风雨都不阻 路见盲人艰&#xff0c;为她心点灯 贺中科大家长论坛成立十五周年 科学家园有喜贺 园外丑汉翘望中 曾一学子入我科 正育科二盼长大 憧憬也能入此家 与科学家论短长 园外翘首听高论 发现有隙入此坛 竟然也能注册成 入园浏览惶然立 此贴…

系统架构的基础:定义、原则与发展历程

目录 1. 系统架构的定义 2. 系统架构的基本组成部分 2.1 架构层次 2.2 架构视图 2.3 架构原则 3. 系统架构的发展历程 3.1 初期阶段:单体架构(Monolithic Architecture) 3.2 面向对象和组件化阶段 3.3 客户端-服务器架构(Client-Server Architecture) 3.4 三层架…

在 Linux 上使用 lspci 命令查看 PCI 总线硬件设备信息

lspci 命令用于显示 Linux 系统上的设备和驱动程序 当在个人电脑或服务器上运行 Linux 时&#xff0c;有时需要识别该系统中的硬件。lspci 命令用于显示连接到 PCI 总线的所有设备&#xff0c;从而满足上述需求。该命令由 pciutils 包提供&#xff0c;可用于各种基于 Linux 和…

JAVA中的回溯算法解空间树,八皇后问题以及骑士游历问题超详解

1.回溯算法的概念 回溯算法顾名思义就是有回溯的算法 回溯算法实际上一个类似枚举的搜索尝试过程&#xff0c;主要是在搜索尝试过程中寻找问题的解&#xff0c;当发现已不满足求解条件时&#xff0c;就“回溯”返回&#xff0c;尝试别的路径。回溯法是一种选优搜索法&#xff…

E12.【C语言】练习:求两个数的最大公约数

1.枚举 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int main() {int a 0;int b 0;int tmp 0;scanf("%d %d", &a, &b);if (a < b){for (int i1; i < a; i){if (0a% i && 0b%i)tmp i;}}if (a>b){for (int i 1; i <…

[线性RNN系列] Mamba: S4史诗级升级

前言 iclr24终于可以在openreview上看预印本了 这篇&#xff08;可能是颠覆之作&#xff09;文风一眼c re组出品&#xff1b;效果实在太惊艳了&#xff0c;实验相当完善&#xff0c;忍不住写一篇解读分享分享。 TL;DR &#xff08;overview&#xff09; Structured State-Sp…

Nginx 日志统计分析命令

统计访问量最多的IP地址&#xff1a; awk {print $1} /path/to/nginx/access.log | sort | uniq -c | sort -nr | head -n 10统计不同状态码的出现次数&#xff1a; awk {print $9} /path/to/nginx/access.log | sort | uniq -c | sort -nr统计访问量最多的URL&#xff1a; awk…

SQL Server端口配置指南

SQL Server是微软推出的关系型数据库管理系统&#xff0c;它支持多种操作系统平台。默认情况下&#xff0c;SQL Server使用TCP/IP协议的1433端口进行通信。然而&#xff0c;出于安全或其他考虑&#xff0c;我们可能需要更改SQL Server实例的默认端口。本文将指导你如何更改SQL …

利率债与信用债的区别及其与债券型基金的关系

利率债与信用债的定义及其区别 定义 利率债&#xff1a; 定义&#xff1a;利率债是指由主权或类主权主体&#xff08;如中华人民共和国财政部、国家开发银行等&#xff09;发行的债券。这些债券通常被认为没有信用风险&#xff0c;因为它们由国家信用背书。特点&#xff1a;由…

【Python】 深入了解 Python 字典的 | 更新操作

我白天是个 搞笑废物 表演不在乎 夜晚变成 忧伤怪物 撕扯着孤独 我曾经是个 感性动物 小心地感触 现在变成 无关人物 &#x1f3b5; 张碧晨/王赫野《何物》 Python 3.9 引入了一种新的字典更新操作&#xff0c;即使用 | 运算符合并字典。这种方式不仅简洁…

xshell公钥免密登录

设备&#xff1a;一台linux系统机器&#xff0c;一台windows系统机器 软件&#xff1a;xshell 要求&#xff1a;公钥免密登录 一、生成公钥、私钥 1、打开shell &#xff1b; 点击工具 &#xff1b; 新建用户生成密钥向导 2、生成密钥参数 密钥类型&#xff1a;RS…

element ui ts table重置排序

#日常# 今天带的实习生&#xff0c;在遇到开发过程中&#xff0c;遇到了element ui table 每次查询的时候都需要重置排序方式&#xff0c;而且多个排序是由前端排序。 <el-table :data"tableData" ref"restTable"> </<el-table> <script…

bi项目笔记

1.bi是什么 bi项目就是商业智能系统&#xff0c;也就是数据可视画、报表可视化系统&#xff0c;如下图的就是bi项目了 2.技术栈

Linux rsync文件同步工具

scp的不足 1. 性能问题 单线程传输 SCP只使用单线程进行传输&#xff0c;这意味着在传输大文件或大量小文件时&#xff0c;其传输速度和效率可能不如其他多线程工具。 无法压缩数据传输 SCP不支持内置的压缩机制&#xff0c;这在传输大文件时会导致带宽使用效率较低。 2.…

我花了5年时间训练自己这种能力,希望你也能成功

人生最重要的能力是日拱一卒&#xff0c;即每天做一点点对自己有利的事并持续足够长的时间。作者之前急于求成&#xff0c;减肥失败。同事通过每月改进一件小事成功减肥且知识储备丰富。作者受启发后&#xff0c;通过走楼梯、换代糖等小改变&#xff0c;用 4 年减了 40 斤&…