首页 > 其他分享 >关于凸包位置关系的判断

关于凸包位置关系的判断

时间:2023-10-17 15:57:51浏览次数:33  
标签:pii 判断 int 位置 凸包 pomsch vecs vec

近日恰好和同学谈到多边形之间怎么判断相交关系,便写下这篇博文。

由于非凸多边形的不确定性,这里就只谈论凸多边形间位置关系判断的优化。对于分别有 \(n\) 和 \(m\) 条边的非凸多边形可以枚举两个多边形的边判断线段是否相交,时间复杂度为 \(O(mn)\)。

凸多边形(以下简称凸包)也可以通过枚举边判断相交关系来判断两凸包是否相交,但 \(O(mn)\) 的复杂度有时属实过大。下面对如何优化进行讨论。

image

对于上图两个凸包,我们将凸包B绕着凸包A移动,并绘制出凸包B最左下角点的轨迹:

image

image

image

image

不难发现,最后凸包B最左下角点的轨迹为两凸包边重新拼接后形成的大凸包,即闵可夫斯基和。对于为什么绘制两凸包的闵可夫斯基和,可以从图中看出,当凸包B最左下角点位于该大凸包内时,两个凸包相交。这里判断点在凸包内则可以用Pick定理解决,最终复杂度为 \(O((m + n)\log(m + n) + (m + n))\)(包括求闵可夫斯基和对边进行极角排序和Pick定理判断单点是否在凸包内),即 \(O((m + n)\log(m + n))\)。

#include<bits/stdc++.h>
#define pii pair<int, int>
#define double long double
#define eps 1e-9

using namespace std;

//使用结构体表示向量方便进行极角排序
struct vec
{
	pii v;
	double ang;

	vec(pii v)
	{
		this->v = v;
		ang = atan2(v.second, v.first);
	}

	bool operator < (vec& r)
	{
		return this->ang < r.ang;
	}
};

pii operator + (pii& l, pii& r)
{
	return make_pair(l.first + r.first, l.second + r.second);
}

pii operator - (pii& l, pii& r)
{
	return make_pair(l.first - r.first, l.second - r.second);
}

bool cmp(vec l, vec r)
{
	return l.ang < r.ang;
}

//向量叉乘
double cross(pii l, pii r)
{
	return l.first * r.second - l.second * r.first;
}

int posOfCh(vector<pii> pochA, int size1, vector<pii> pochB, int size2) //pochA, pochB分别按顺时针顺序存储两凸包上的点
{
	vector<vec> vecs;
	pii maxp = pochA[0], minp = pochB[0];
	for (int i = 0; i < size1; i++)
	{
		vecs.push_back(vec(pochA[(i + 1) % size1] - pochA[i])); //将凸包的边按向量的形式存入,凸包A按顺时针,凸包B按逆时针
		maxp = max(maxp, pochA[i]); //同时查找凸包A中的最右上角点
	}
	for (int i = size2; i > 0; i--)
	{
		vecs.push_back(vec(pochB[i - 1] - pochB[i % size2]));
		minp = min(minp, pochB[i - 1]); //同时查找凸包B中的最左下角点
	}
	sort(vecs.begin(), vecs.end()); //极角排序
	
	//找到从极角-π/2开始(包括-π/2)顺时针方向第一条向量
	int pos = upper_bound(vecs.begin(), vecs.end(), vec({ 0, -1 }), cmp) - vecs.begin() - 1;
	
	//计算闵可夫斯基和的凸包顶点
	vector<pii> pomsch;
	pomsch.push_back(maxp);
	for (int i = pos, j = 0; j < vecs.size(); i = (i + vecs.size() - 1) % vecs.size(), j++)
	{
		pii p = pomsch.back() + vecs[i].v;
		while (pomsch.size() > 1 && cross(vecs[i].v, pomsch.back() - pomsch[pomsch.size() - 2]) < eps) //去除三点共线的中间点
			pomsch.pop_back();

		pomsch.push_back(p);
	}
	pomsch.pop_back();

	//Pick定理判断凸包B最左下角点是否在闵可夫斯基和中
	int flag = 1;
	for (int i = 0; i < pomsch.size(); i++)
		if (cross(minp - pomsch[i], pomsch[(i + 1) % pomsch.size()] - pomsch[i]) < eps)
		{
			flag = 0;
			break;
		}

	return flag;
}

标签:pii,判断,int,位置,凸包,pomsch,vecs,vec
From: https://www.cnblogs.com/ItsAiHAn/p/17769891.html

相关文章

  • [学习笔记] 浏览器F12检查中应该如何判断margin的上下左右?
    如下图所示,margin上下左右四个方向分别是1px,2px,3px,4px。 而在浏览器F12检查时,margin显示如下图所示:即浏览器检查时显示的margin值,是按照上、右、下、左的顺序来的。该规律在padding也同样适用。 ......
  • windows根据条件判断,重启网卡
    @echooffTITLE网络检测time/T>ping.txtpingwww.baidu.com-n1>>ping.txtfindstr/n"主机"ping.txtif%errorlevel%==0(rem网卡重启netshinterfacesetinterface"以太网"disablednetshinterfacesetinterface"以太网"en......
  • Shell(七):退出、测试、判断及操作符
    1、退出状态在Linux系统中,每当命令执行完成后,系统都会返回一个退出状态。该退出状态用一整数值表示,用于判断命令运行正确与否。若退出状态值为0,表示命令运行成功;而退出状态值不为0时,则表示命令运行失败。最后一次执行命令的退出状态值保存在内置变量"$?"中。POSIX规定......
  • Qt -- 判断信号是否绑定成功
    1.判断信号是否正确连接通过判断connect的返回值是否为true。bool_ok=connect(this,SIGNAL(signal1()),this,SLOT(slot1()));//打印trueqDebug()<<_ok;2.判断信号是否被连接了receivers返回的是该信号的连接数,如果大于0则为信号有连接。原型:[protected]i......
  • BOSHIDA DC电源模块关于电容器的电解液位置
    BOSHIDADC电源模块关于电容器的电解液位置DC电源模块中的电容器扮演着一个非常重要的角色,它们能够对电路提供稳定的电源电压,同时也可以作为电路中的滤波器,去除电路中的噪声和纹波。在DC电源模块中使用的电容器通常是电解型电容器,而这些电解型电容器中的电解液位置是一个非常关键......
  • 判断二分图的方法
    题目描述:龙龙得知2020年中国将有2000万至4000万男人娶不到老婆后。他打算好好调查一下是不是人们的感情出现问题。他对n个人进行调查,得到m条信息,每条信息表示为某两人曾经是情侣。由于他不知道这些人的性别,请你帮他判断一下,有没有同性是情侣的情况?对于100%的数据,n的范围[2,100000......
  • 配置GT9157触摸屏,获取触摸位置
    触摸IC为GT91571.配置触摸屏引脚VDDSCLSDARSTINTGND电源I2C时钟I2C数据屏幕复位屏幕触摸信号地staticvoidI2C_GPIO_Config(void){GPIO_InitTypeDefGPIO_InitStructure;/*I2CPeriphclockenable*/RCC_APB1PeriphClockCmd(GTP_I2C_CLK,ENA......
  • js判断手机访问并跳转移动端网址
    1<scripttype="text/javascript">2functionuaredirect(murl){3try{4if(document.getElementById("bdmark")!=null){5return;6}7......
  • VTK 判断一个 点 是否在一个模型 stl 内部 vtk 点是否在内部 表面 寻找最近点
    判断一个点,判断是否在风格stl模型内部,或表面:目录1.方案一:使用vtkCellLocator  FindClosestPoint找到模型上距离给定点最近的一点,计算两点的距离,小于某一阈值则认为此点在模型上;2.方案二使用vtkKdTreePointLocator3.方案三使用vtkSelectEnclosedPoints1.方案一:使用vtk......
  • perl判断字符串包含
    perl判断字符串包含perl中没有判断字符串包含的函数,可以用正则表达式来实现这个功能,下面代码判断$str1是否包含$str2。if($str1=~/$str2/){...}if ($str1 !~/str2/) {    #匹配了不包含的}else {    #匹配了包含的}......