平面计算几何模版集合

这几天学计算几何,感觉自己很适合做这种类型的题目。。毕竟数学还算学的不错。。尤其是几何。。

模版是照着白书上敲的,会用就好,原理也都很简单,能写成函数并且运用就是好的。

模版如下,方便以后自己用


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
const double PI = acos(-1.0);
const double MAXN = 1000000.0;
struct Point{
	double x,y;
	Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vec;
//向量+向量 = 向量,点+向量 = 点
Vec operator +(Vec A,Vec B){return Vec(A.x+B.x,A.y+B.y);}
//点-点 = 向量
Vec operator -(Point A,Point B){return Vec(A.x-B.x,A.y-B.y);}
//向量*数 = 向量
Vec operator *(Vec A,double p){return Vec(A.x*p,A.y*p);}
//向量/数 = 向量
Vec operator /(Vec A,double p){return Vec(A.x/p,A.y/p);}
bool operator <(const Point& a,const Point& b){
	return a.x<b.x || (a.x == b.x && a.y<b.y);
}
const double EPS = 1e-10;
int dcmp(double x){
	if(fabs(x)<EPS) return 0;else return x<0? -1: 1;
}
bool operator == (const Point& a,const Point &b){
	return dcmp(a.x-b.x)==0 &&dcmp(a.y-b.y) == 0;
}
double ang(Vec v){return atan2(v.y,v.x);}
/*========直线基本定义========*/
struct Line{
	Point P;
	Vec v;
	double ang;
	Line(){}
	Line(Point P,Vec v):P(P),v(v){ang  = atan2(v.y,v.x);}
	bool operator < (const Line& L) const {
		return ang < L.ang;
	}
	Point point(double a){
		return P+v*a;
	}
};
/*========圆的基本定义========*/
struct Circle{
	Point c;
	double r;
	Circle(Point c,double r):c(c),r(r){}
	Point point(double a){
		return Point(c.x+cos(a)*r,c.y + sin(a)*r);
	}
};
/*==========以上为基本定义============*/


double Dot(Vec A,Vec B){return A.x*B.x+A.y*B.y;}
double Length(Vec A){ return sqrt(Dot(A,A));}
double Angle(Vec A,Vec B){return acos(Dot(A,B)/Length(A)/Length(B));}
/*==========用点积算向量长度和两个向量夹角============*/


double Cross(Vec A,Vec B){return A.x*B.y - A.y*B.x;}
//ABC的三角形有向面积的两倍
double Area2(Point A,Point B,Point C){return Cross(B-A,C-A);}
//rad是弧度 逆时针旋转
Vec Rotate(Vec A,double rad){
	return Vec(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
//逆时针旋转90°的单位法向量
Vec Normal(Vec A){
	double L = Length(A);
	return Vec(-A.y/L,A.x/L);
}
/*=====以上为叉积的基本运算=====*/


//P+tv和Q+tw两条直线的交点,确保有唯一交点
Point GetlineIntersection(Line a,Line b){
	Point P = a.P,Q = b.P;
	Vec v = a.v,w = b.v;	
	Vec u = P-Q;
	double t = Cross(w,u)/Cross(v,w);
	return a.point(t);
}
//点到直线的距离
double DistanceToLine(Point P,Line a){
	Point A = a.P,B = a.P + a.v;
	Vec v1 = B-A,v2 = P-A;
	return fabs(Cross(v1,v2)/Length(v1));//不取绝对值那么得到的是有向距离
}
//点到线段的距离
double DistanceToSegment(Point P,Point A,Point B){
	if(A == B)return Length(P-A);
	Vec v1 = B - A, v2 = P - A, v3 = P - B;
	if(dcmp(Dot(v1,v2))<0)return Length(v2);
	else if(dcmp(Dot(v1,v3)>0)) return Length(v3);
	else return fabs(Cross(v1,v2))/Length(v1);
}
//点在直线上的投影
Point GetLineProjection(Point P,Line a){
	Point A = a.P,B = a.P + a.v;
	Vec v = B - A;
	return A + v*(Dot(v,P-A) / Dot(v,v));
}
//判断两条线段是否相交 此处必须为规范相交
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2){
	double c1 = Cross(a2-a1,b1-a1),c2 = Cross(a2-a1,b2-a1);
	double c3 = Cross(b2-b1,a1-b1),c4 = Cross(b2-b1,a2-b1);
	return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
}
//如果允许端点相交,则用以下代码,判断一个点是否在一条线段上
bool OnSegment(Point p,Point a1,Point a2){
	return dcmp(Cross(a1-p,a2-p)) == 0 && dcmp(Dot(a1-p,a2-p))<0;
}
/*=========以上为点和直线,直线和直线关系的内容========*/
//判断点和多边形位置关系
int isPointInPolygon(Point p, const vector<Point>& poly){
	int w = 0;
	int n = poly.size();
	for(int i=0;i<n;i++){
		if(OnSegment(p,poly[i],poly[(i+1)%n]))return -1;//在边界上
		int k = dcmp(Cross(poly[(i+1)%n]-poly[i],p-poly[i]));
		int d1 = dcmp(poly[i].y - p.y);
		int d2 = dcmp(poly[(i+1)%n].y - p.y);
		if(k > 0 && d1 <= 0 && d2 > 0)w++;
		if(k < 0 && d2 <= 0 && d1 > 0)w--;
	}
	if(w != 0)return 1;
	return 0;
}
//多边形有向面积
double PolygonArea(vector<Point> p){
	int n = p.size();
	double area = 0;
	for(int i=1;i<n-1;i++)
		area += Cross(p[i] - p[0],p[i+1]-p[0]);
	return area/2;
}
//多边形周长
double PolygonZhouc(vector<Point> p){
	int n = p.size();
	double ans = 0;
	for(int i=0;i<n-1;i++)
		ans+= Length(p[i+1]-p[i]);
	ans+=Length(p[0]-p[n-1]);
	return ans;
}
double isint(double x){
	return fabs(x - (int)(x+0.5))<EPS;
}
/*========多边形面积等内容=========*/

bool OnLeft(Line L,Point P){
	return Cross(L.v,P - L.P)>=0;          //如果线上的点不算就改成>
}
Point GetIntersection(Line a, Line b){
	Vec u = a.P - b.P;
	double t = Cross(b.v,u)/Cross(a.v,b.v);
	return a.P+a.v*t;
}
int HalfplaneIntersection(Line* L,int n,Point* poly){
	sort(L,L+n);
	int first,last;
	Point *p = new Point[n];
	Line *q = new Line[n];
	q[first = last = 0] = L[0];
	for(int i=1;i<n;i++){
		while(first<last && !OnLeft(L[i],p[last-1]))last--;
		while(first<last && !OnLeft(L[i],p[first]))first++;
		q[++last] = L[i];
		if(fabs(Cross(q[last].v,q[last-1].v))<EPS){
			last--;
			if(OnLeft(q[last],L[i].P))q[last] = L[i];
		}
		if(first<last) p[last-1] = GetIntersection(q[last-1],q[last]);
	}
	while(first<last && !OnLeft(q[first],p[last-1]))last -- ;
	if(last-first<=1)return 0;
	p[last] = GetIntersection(q[last],q[first]);
	int m = 0;
	for(int i=first;i<=last;i++)poly[m++] = p[i];
	return m;
}
/*=========半平面交所需函数及主过程=========*/

vector<Point> ConvexHull(vector<Point> p){
	sort(p.begin(),p.end());
	//删除重复点
	p.erase(unique(p.begin(),p.end()),p.end());
	int n = p.size();
	vector<Point> ch(n+1);
	int m = 0;
	for(int i=0;i<n;i++){
		while(m>1 && dcmp(Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])) <= 0) m--;         //若需要把边线上的点也算上,把等号去掉
		ch[m++] = p[i];
	}
	int k = m;
	for(int i = n-2;i>=0;i--){
		while(m > k && dcmp(Cross(ch[m-1] - ch[m-2] , p[i]-ch[m-2] )) <= 0)m--;
		ch[m++] = p[i];
	}
	if(n > 1)m--;
	ch.resize(m);
	return ch;
}
/*=============以上为凸包==========*/

double earthdis(Point a,Point b){
	double x1=PI*a.x/180.0;
	double y1=PI*a.y/180.0;
	double x2=PI*b.x/180.0;
	double y2=PI*b.y/180.0;
	return acos(cos(x1-x2)*cos(y1)*cos(y2)+sin(y1)*sin(y2));
}
/*=======给出经纬度,算出球体上两点之间的角度=====*/


//判断圆和直线交点,方程法
int getLineCircleIntersection(Line L, Circle C, double& t1,double& t2,vector<Point>& sol){
	double a = L.v.x, b = L.P.x-C.c.x, c = L.v.y, d = L.P.y - C.c.y;
	double e = a*a+c*c,f = 2*(a*b+c*d),g = b*b-C.r*C.r;
	double delta = f*f - 4*e*g;             //判别式
	if(dcmp(delta) < 0)return 0;              //相离
	if(dcmp(delta) == 0){                   //相切
		t1 = t2 = -f/(2*e);sol.push_back(L.point(t1));
		return 1;
	}
	//相交
	t1 = (-f - sqrt(delta)) / (2*e); sol.push_back(L.point(t1));
	t2 = (-f + sqrt(delta)) / (2*e); sol.push_back(L.point(t2));
	return 2;
}
//圆和直线交点,几何法
int getLineCircleIntersection(Line L, Circle C,vector<Point>& sol){
	double d = DistanceToLine(C.c, L);
	if(dcmp(d - C.r)>0)return 0;	//相离
	Point ans = GetlineIntersection(L, Line(C.c,Normal(L.v)));
	if(dcmp(d - C.r) == 0){			//相切
		sol.push_back(ans);
		return 1;
	}
	//相交
	double len = sqrt(C.r*C.r-d*d);
	Vec v = L.v / Length(L.v);
	sol.push_back(ans + v * len),sol.push_back(ans - v * len);
	return 2;
}
//判断两圆相交
int getCircleCircleIntersection(Circle C1, Circle C2, vector<Point>& sol){
	double d = Length(C1.c-C2.c);
	if( dcmp(C1.r - C2.r)>0)
		swap(C1,C2);
	if(dcmp(d)==0){
		if(dcmp(C1.r-C2.r)==0)return -1;//重合
		return 0;
	}
	if(dcmp(C1.r + C2.r -d) < 0) return 0;//外离
	if(dcmp(fabs(C1.r-C2.r)-d)>0)return 0;//内含
	if(dcmp(C1.r + C2.r - d) == 0 || dcmp(fabs(C1.r - C2.r)-d) == 0){
		Vec p = C1.c-C2.c;
		sol.push_back(C2.c + p / Length(p) * C2.r);
		return 1;
	}//外切或内切
	double a = ang(C2.c - C1.c);
	double da = acos((C1.r * C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));
	Point p1 = C1.point(a-da),p2 = C1.point(a+da);
	sol.push_back(p1);
	sol.push_back(p2);
	return 2;//相交
}
//过点p到圆C的切线
int getTangents(Point p,Circle C,vector<Line>& L){
	Vec u = C.c - p , temp;
	double dist = Length(u);
	if(dist < C.r) return 0;
	else if(dcmp(dist - C.r) == 0){
		temp = Normal(u);
		L.push_back(Line(p,temp));
		return 1;
	}else {
		double ang = asin(C.r/dist);
		temp = Rotate(u,-ang),L.push_back(Line(p,temp));
		temp = Rotate(u,+ang),L.push_back(Line(p,temp));
		return 2;
	}
}
//两圆公切线,返回切线条数,-1表示无穷多条
//sol里存的是切线,p为a上切点,p+v为b上切点
int getTangents(Circle A,Circle B,vector<Line>& sol){
	int cnt = 0;
	Point a,b;
	if(dcmp(A.r - B.r) < 0)swap(A,B);
	double d2 = (A.c.x - B.c.x) * (A.c.x - B.c.x) + (A.c.y - B.c.y) * (A.c.y -B.c.y);
	double rdiff = A.r - B.r;
	double rsum = A.r + B.r;
	if(dcmp(d2 - rdiff * rdiff) < 0) return 0;//内含

	double base = atan2(B.c.y - A.c.y, B.c.x - A.c.x);
	if(dcmp(d2)==0 && A.r == B.r)return -1;//重合,切线无限多
	if(dcmp(d2-rdiff * rdiff)==0){//内切,一条切线
		a = A.point(base),b = B.point(base);
		sol.push_back(Line(a,b-a));
		return 1;
	}
	//有外切线
	double ang = acos((A.r-B.r) / sqrt(d2));
	a = A.point(base+ang),b = B.point(base+ang),sol.push_back(Line(a,b-a)),cnt++;
	a = A.point(base-ang),b = B.point(base-ang),sol.push_back(Line(a,b-a)),cnt++;
	if(dcmp(d2 - rsum * rsum)==0){
		a = A.point(base),b = B.point(PI + base),cnt++;
	}else if(dcmp(d2 - rsum * rsum)>0){
		double ang2 = acos((A.r + B.r) / sqrt(d2));
		a = A.point(base+ang),b = B.point(PI+base+ang),sol.push_back(Line(a,b-a)),cnt++;
		a = A.point(base-ang),b = B.point(PI+base-ang),sol.push_back(Line(a,b-a)),cnt++;
	}
	return cnt;

}
/*==========以上为圆的常用函数及计算==========*/


int main()
{

	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值