#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1e100
#define eps 1e-8
//用于浮点数正负判断,根据题目精度修改
const double pi = acos(-1.0);//圆周率
int sgn(double x){
if(fabs(x)<eps)return 0;
if(x<0)return -1;
return 1;
}//判断浮点数正负
double sqr(double x){return x*x;}//距离等运算涉及大量平方,简便
//使用Point时注意部分函数是返回新Point而非修改本身值
struct Point{
double x,y;
/*构造函数*/
Point(){}
Point(double xx,double yy){
x=xx;y=yy;
}
/*重载一些点的基础运算符*/
bool operator == (Point b)const{
return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
}
bool operator < (Point b)const{
return sgn(x-b.x)== 0?sgn(y-b.y)<0:x<b.x;
}
Point operator -(const Point &b)const{
return Point(x-b.x,y-b.y);
}
Point operator +(const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator *(const double &k)const{
return Point(x*k,y*k);
}
Point operator /(const double &k)const{
return Point(x/k,y/k);
}
//叉积
double operator ^(const Point &b)const{
return x*b.y - y*b.x;
}
//点积
double operator *(const Point &b)const{
return x*b.x + y*b.y;
}
/*当前点为p,求角apb大小*/
double rad(Point a,Point b){
Point p = *this;
return fabs(atan2( fabs((a-p)^(b-p)),(a-p)*(b-p) ));
}
/*逆时针旋转90度*/
Point rotleft(){
return Point(-y,x);
}
/*顺时针旋转90度*/
Point rotright(){
return Point(y,-x);
}
//两点距离
double dis(Point p){
return sqrt(sqr(x-p.x)+sqr(y-p.y));
}
double abs(){
return sqrt(abs2());
}
double abs2(){
return sqr(x)+sqr(y);
}
//改变向量长度
Point trunc(double r){
double l = abs();
if(!sgn(l))return *this;
r /= l;
return Point(x*r,y*r);
}
//单位化
Point unit() { return *this/abs(); }
//IO
void input(){
scanf("%lf%lf",&x,&y);
}
void output(){
printf("%.7f %.7f\n",x,y);
}
//绕着p点逆时针旋转angle
Point rotate(Point p,double angle){
Point v = (*this) - p;
double c = cos(angle), s = sin(angle);
return Point(p.x + v.x*c - v.y*s,p.y + v.x*s + v.y*c);
}
};
struct Line{
//两点确定直线
Point s,e;
Line(){}
Line(Point ss,Point ee){
s=ss;e=ee;
}
void input(){
s.input();
e.input();
}
//点在线段上
bool checkPS(Point p){
return sgn((p-s)^(e-s)) == 0 && sgn((p-s)*(p-e)) <= 0;
}
//直线平行
bool parallel(Line v){
return sgn((e-s)^(v.e-v.s)) == 0;
}
//点和直线关系
//1 在左侧
//2 在右侧
//3 在直线上
int relation(Point p){
int c = sgn((p-s)^(e-s));
if(c < 0)return 1;
else if(c > 0)return 2;
else return 3;
}
//线段相交
//2 规范相交
//1 非规范相交
//0 不相交
int checkSS(Line v){
int d1 = sgn((e-s)^(v.s-s));
int d2 = sgn((e-s)^(v.e-s));
int d3 = sgn((v.e-v.s)^(s-v.s));
int d4 = sgn((v.e-v.s)^(e-v.s));
if( (d1^d2)==-2 && (d3^d4)==-2 )return 2;
return (d1==0 && sgn((v.s-s)*(v.s-e))<=0) ||
(d2==0 && sgn((v.e-s)*(v.e-e))<=0) ||
(d3==0 && sgn((s-v.s)*(s-v.e))<=0) ||
(d4==0 && sgn((e-v.s)*(e-v.e))<=0);
}
//直线和线段相交
//2 规范相交
//1 非规范相交
//0 不相交
int checkLS(Line v){
int d1 = sgn((e-s)^(v.s-s));
int d2 = sgn((e-s)^(v.e-s));
if((d1^d2)==-2) return 2;
return (d1==0||d2==0);
}
//两直线关系
//0 平行
//1 重合
//2 相交
int checkLL(Line v){
if((*this).parallel(v))
return v.relation(s)==3;
return 2;
}
//直线交点
Point isLL(Line v){
double a1 = (v.e-v.s)^(s-v.s);
double a2 = (v.e-v.s)^(e-v.s);
return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
}
//点到直线的距离
double disPL(Point p){
return fabs((p-s)^(e-s))/(s.dis(e));
}
//点到线段的距离
double disPS(Point p){
if(sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
return min(p.dis(s),p.dis(e));
return disPS(p);
}
//两线段距离
double disSS(Line v){
return min(min(disPS(v.s),disPS(v.e)),min(v.disPS(s),v.disPS(e)));
}
//点在直线上投影
Point proj(Point p){
return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).abs2()) );
}
//向垂直有向直线的左侧移动x
Line push(double x){
Point tmp=e-s;
tmp=tmp.rotleft().trunc(x);
Point ss=s+tmp;
Point ee=e+tmp;
return {ss,ee};
}
};
struct circle{
Point p;//圆心
double r;//半径
circle(){}
circle(Point pp,double rr){
p = pp;
r = rr;
}
void input(){
p.input();
scanf("%lf",&r);
}
bool operator == (circle v){
return (p==v.p) && sgn(r-v.r)==0;
}
//面积
double area(){
return pi*r*r;
}
//周长
double cir(){
return 2*pi*r;
}
//点和圆的关系
//0 圆外
//1 圆上
//2 圆内
int relation(Point B){
double dst = B.dis(p);
if(sgn(dst-r) < 0)return 2;
else if(sgn(dst-r)==0)return 1;
return 0;
}
//两圆的关系
//5 相离
//4 外切
//3 相交
//2 内切
//1 内含
int checkCC(circle v){
double d = p.dis(v.p);
if(sgn(d-r-v.r) > 0)return 5;
if(sgn(d-r-v.r) == 0)return 4;
double l = fabs(r-v.r);
if(sgn(d-r-v.r)<0 && sgn(d-l)>0)return 3;
if(sgn(d-l)==0)return 2;
if(sgn(d-l)<0)return 1;
}
//求两个圆的交点,返回0表示没有交点,返回1是一个交点,2是两个交点
int isCC(circle v,Point &p1,Point &p2){
int rel = checkCC(v);
if(rel == 1 || rel == 5)return 0;
double d = p.dis(v.p);
double l = (d*d+r*r-v.r*v.r)/(2*d);
double h = sqrt(r*r-l*l);
Point tmp = p + (v.p-p).trunc(l);
p1 = tmp + ((v.p-p).rotleft().trunc(h));
p2 = tmp + ((v.p-p).rotright().trunc(h));
if(rel == 2 || rel == 4)
return 1;
return 2;
}
//求直线和圆的交点,返回交点个数
int isCL(Line v,Point &p1,Point &p2){
if(sgn(v.disPL(p)-r)>0)return 0;
Point A = v.proj(p);
double d = v.disPL(p);
d = sqrt(r*r-d*d);
if(sgn(d) == 0){
p1 = A;
p2 = A;
return 1;
}
p1 = A + (v.e-v.s).trunc(d);
p2 = A - (v.e-v.s).trunc(d);
return 2;
}
//点到圆切线
int tanCP(Point q,Line &u,Line &v){
int x = relation(q);
if(x == 2)return 0;
if(x == 1){
u = Line(q,q + (q-p).rotleft());
v = u;
return 1;
}
double d = p.dis(q);
double l = r*r/d;
double h = sqrt(r*r-l*l);
u = Line(q,p + ((q-p).trunc(l) + (q-p).rotleft().trunc(h)));
v = Line(q,p + ((q-p).trunc(l) + (q-p).rotright().trunc(h)));
return 2;
}
//两圆相交面积
double areaCC(circle v){
int rel = checkCC(v);
if(rel >= 4)return 0.0;
if(rel <= 2)return min(area(),v.area());
double d = p.dis(v.p);
double hf = (r+v.r+d)/2.0;
double ss = 2*sqrt(hf*(hf-r)*(hf-v.r)*(hf-d));
double a1 = acos((r*r+d*d-v.r*v.r)/(2.0*r*d));
a1 = a1*r*r;
double a2 = acos((v.r*v.r+d*d-r*r)/(2.0*v.r*d));
a2 = a2*v.r*v.r;
return a1+a2-ss;
}
//求圆和三角形pab的相交面积
double areaCT(Point a,Point b){
if(sgn((p-a)^(p-b)) == 0)return 0.0;
Point q[5];
int len = 0;
q[len++] = a;
Line l(a,b);
Point p1,p2;
if(isCL(l,q[1],q[2])==2){
if(sgn((a-q[1])*(b-q[1]))<0)q[len++] = q[1];
if(sgn((a-q[2])*(b-q[2]))<0)q[len++] = q[2];
}
q[len++] = b;
if(len == 4 && sgn((q[0]-q[1])*(q[2]-q[1]))>0)swap(q[1],q[2]);
double res = 0;
for(int i = 0;i < len-1;i++){
if(relation(q[i])==0||relation(q[i+1])==0){
double arg = p.rad(q[i],q[i+1]);
res += r*r*arg/2.0;
}
else{
res += fabs((q[i]-p)^(q[i+1]-p))/2.0;
}
}
return res;
}
};
//多边形面积,需保证A逆时针
double area(vector<Point> A) {
double ans = 0;
for (int i = 0; i < A.size(); i++) ans += (A[i]^A[(i + 1) % A.size()]);
return ans / 2;
}
int contain(vector<Point>A, Point q) { // 2 内部 1 边界 0 外部
int pd = 0; A.push_back(A[0]);
for (int i = 1; i < A.size(); i++) {
Point u = A[i - 1], v = A[i];
if (Line(u,v).checkPS(q)) return 1; if (sgn(u.y-v.y) > 0) swap(u, v);
if (sgn(u.y-q.y) >= 0 || sgn(v.y-q.y) < 0) continue;
if (sgn((u - v) ^(q - v)) < 0) pd ^= 1;
}
return pd << 1;
}
//凸包
vector<Point> ConvexHull(vector<Point>A, int flag = 1) { // flag=0 不严格 flag=1 严格
int n = A.size(); vector<Point>ans(n * 2);
sort(A.begin(), A.end()); int now = -1;
for (int i = 0; i < A.size(); i++) {
while (now > 0 && sgn((ans[now] - ans[now - 1])^(A[i] - ans[now - 1])) < flag) now--;
ans[++now] = A[i];
} int pre = now;
for (int i = n - 2; i >= 0; i--) {
while (now > pre && sgn((ans[now] - ans[now - 1])^(A[i] - ans[now - 1])) < flag) now--;
ans[++now] = A[i];
} ans.resize(now); return ans;
}
// 最近点对 , 先要按照 x 坐标排序
double closepoint(vector<Point>&A, int l, int r) {
if (r - l <= 5) {
double ans = 1e20;
for (int i = l; i <= r; i++) for (int j = i + 1; j <= r; j++) ans = min(ans, A[i].dis(A[j]));
return ans;
}
int mid = l + r >> 1; double ans = min(closepoint(A, l, mid), closepoint(A, mid + 1, r));
vector<Point>B; for (int i = l; i <= r; i++) if (abs(A[i].x - A[mid].x) <= ans) B.push_back(A[i]);
sort(B.begin(), B.end(), [&](Point k1, Point k2) {return k1.y < k2.y;});
for (int i = 0; i < B.size(); i++) for (int j = i + 1; j < B.size() && B[j].y - B[i].y < ans; j++) ans = min(ans, B[i].dis(B[j]));
return ans;
}
//凸包直径
double convexDiameter(vector<Point>A) {
int now = 0, n = A.size(); double ans = 0;
for (int i = 0; i < A.size(); i++) {
now = max(now, i);
while (1) {
double k1 = A[i].dis(A[now % n]), k2 = A[i].dis(A[(now + 1) % n]);
ans = max(ans, max(k1, k2)); if (k2 > k1) now++; else break;
}
}
return ans;
}
//多边形和圆交面积
double areaPC(vector<Point> p,circle c){
double ans = 0;
int n=p.size();
for(int i = 0;i < n;i++){
int j = (i+1)%n;
if(sgn( (p[j]-c.p)^(p[i]-c.p) ) >= 0)
ans += c.areaCT(p[i],p[j]);
else ans -= c.areaCT(p[i],p[j]);
}
return fabs(ans);
}
int main(){
}
计算几何模板(第一版)
最新推荐文章于 2024-07-22 09:38:37 发布