计算几何模板——点类以及线段类
程序员文章站
2022-04-02 18:58:03
...
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;
const int MAXN = 500+10;
const int INF=1e9+7;
const double eps=1e-8;
const double pi=acos(-1.0);
//计算几何误差修正
//输入为一个double类型的数,返回-1表示负数,1表示正数,0表示x为0
int cmp(double x){
if(fabs(x)<eps)
return 0;
if(x>0) return 1;
return -1;
}
//计算几何点类
inline double sqr(double x){
return x*x;
}
struct point{
double x,y;
double xx;
point(){}
point(double a,double b):x(a),y(b){}
void input(){
scanf("%lf%lf",&x,&y);
}
//加法
friend point operator + (const point &a,const point &b){
return point(a.x+b.x,a.y+b.y);
}
//减法
friend point operator - (const point &a,const point &b){
return point(a.x-b.x,a.y-b.y);
}
//判断相等
friend bool operator == (const point &a,const point &b){
return cmp(a.x-b.x)==0&&cmp(a.y-b.y)==0;
}
//倍增
friend point operator * (const point &a,const double &b){
return point(a.x*b,a.y*b);
}
//倍增
friend point operator * (const double &b,const point &a){
return point(a.x*b,a.y*b);
}
//除法
friend point operator / (const point &a,const double b){
return point(a.x/b,a.y/b);
}
//模长
double norm(){
return sqrt(sqrt(x)+sqr(y));
}
};
//叉积,a×b>0代表a在b的顺时针方向,<0代表a在b的逆时针方向,等于0代表a和b向量共线,但不确定方向是否相同
double det(const point &a,const point &b){
return a.x*b.y-a.y*b.x;
}
//点积
double dot(const point &a,const point &b){
return a.x*b.x+a.y*b.y;
}
//距离
double dist(const point &a,const point &b){
return (a-b).norm();
}
//op向量绕原点逆时针旋转A(弧度)
point rotate_point(const point &p,double A){
double tx=p.x,ty=p.y;
return point(tx*cos(A)-ty*sin(A),tx*sin(A)+ty*cos(A));
}
//计算几何线段类
struct line{
point a,b;
line(){}
line(point x,point y):a(x),b(y){}
void input(){
a.input();
b.input();
}
};
//用两个点a,b生成的一个线段或者直线
line point_make_line(point a,point b){
return line(a,b);
}
//求点p到线段st的距离
double dis_point_segment(point p,point s,point t){
if(cmp(dot(p-s,t-s))<0) return (p-s).norm();
if(cmp(dot(p-s,s-t))<0) return (p-t).norm();
return fabs(det(s-p,t-p)/dist(s,t));
}
//求点p到线段st的垂足,保存在cp中
void PointProjLine(point p,point s,point t,point &cp){
double r=dot((t-s),(p-s))/dot(t-s,t-s);
cp=s+(t-s)*r;
}
//判断p点是否在线段st上
bool PointOnSegment(point p,point s,point t){
return cmp(det(p-s,t-s))==0&&cmp(dot(p-s,p-t))<=0;
}
//判断a和b是否平行
bool parallel(line a,line b){
return !cmp(det(a.a-a.b,b.a-b.b));
}
//判断a和b是否共线
bool contribution(line a,line b){
if(!parallel(a, b))
return false;
if(!cmp(det(a.b-a.a,b.a-a.b)))
return true;
return false;
}
//判断a和b是否相交,若相交则返回true且交点保存在res中
bool line_make_point(line a,line b,point &res){
if(parallel(a, b))
return false;
double s1=det(a.a-b.a,b.b-b.a);
double s2=det(a.b-b.a,b.b-b.a);
res=(s1*a.b-s2*a.a)/(s1-s2);
return true;
}
//判断线段是否相交
bool segment_make_point(line a,line b,point &res){
if(!line_make_point(a,b,res))
return false;
if(PointOnSegment(res, a.a, a.b)&&PointOnSegment(res, b.a, b.b))
return true;
return false;
}
//判断线段和直线是否相交,a是直线,b是线段
bool line_across_segment(line a,line b){
if(cmp(det(a.b-a.a,b.a-a.a)*det(a.b-a.a,b.b-a.a))==1){
return false;
}
return true;
}
//将直线a沿法向量方向平移距离len得到的直线
line move_d(line a,const double &len){
point d=a.b-a.a;
d=d/d.norm();
d=rotate_point(d, pi/2);
return line(a.a+d*len,a.b+d*len);
}
推荐阅读