计算几何模板

(1)点积求投影

分析计算几何模板_第1张图片

|BD| = BA * BC / |BC|

BD = |BD| * BC / |BC| = BA * BC * BC / (|BC| * |BC|)

D = B + BD

#include
#include
#include
using namespace std;

struct Point{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double k){return Point(k*x,k*y);}
    Point operator / (double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;};
    double abs(){return sqrt(norm());}
};
typedef Point Vector;
double dot(Vector a, Vector b)
{
    return a.x * b.x + a.y * b.y;
}

int n;

int main()
{
    Point p1, p2;
    scanf("%lf%lf%lf%lf", &p1.x, &p1.y, &p2.x, &p2.y);
    scanf("%d", &n);
    while(n--)
    {
        Point ans;
        scanf("%lf%lf", &ans.x, &ans.y);
        double k1 = dot(ans - p1, p2 - p1);
        double k2 = (p2 - p1).abs();
        k1 /= k2;
        ans = (p2 - p1) * (k1 / k2);
        printf("%.10f %.10f\n", ans.x + p1.x, ans.y + p1.y);
    }
    return 0;
}

(2)点积求映射

分析:用(1)中的方法求垂足后扩深两倍后即可。

#include
#include
#include
using namespace std;

struct Point{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double k){return Point(k*x,k*y);}
    Point operator / (double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;};
    double abs(){return sqrt(norm());}
};
typedef Point Vector;
double dot(Vector a, Vector b)
{
    return a.x * b.x + a.y * b.y;
}

int n;

int main()
{
    Point p1, p2;
    scanf("%lf%lf%lf%lf", &p1.x, &p1.y, &p2.x, &p2.y);
    scanf("%d", &n);
    while(n--)
    {
        Point p, ans;
        scanf("%lf%lf", &p.x, &p.y);
        double k1 = dot(p - p1, p2 - p1);
        double k2 = (p2 - p1).abs();
        k1 /= k2;
        ans = (p2 - p1) * (k1 / k2);
        ans = ans + p1; /// 垂足
        printf("%.10f %.10f\n", 2 * ans.x - p.x, 2 * ans.y - p.y);
    }
    return 0;
}

(3)平行垂直

点积为0垂直,叉积为0平行。

#include
#include
#include
using namespace std;
const double eps = 1e-8;

struct Point{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double k){return Point(k*x,k*y);}
    Point operator / (double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;};
    double abs(){return sqrt(norm());}
};
typedef Point Vector;
double dot(Vector a, Vector b)
{
    return a.x * b.x + a.y * b.y;
}
double cross(Vector a, Vector b)
{
    return a.x * b.y - a.y * b.x;
}
bool isParallel(Vector a, Vector b)
{
    return fabs(cross(a, b)) <= eps;
}
bool isOrthogonal(Vector a, Vector b)
{
    return fabs(dot(a, b)) <= eps;
}
Point p1, p2, p3, p4, ans;
int n;

int main()
{
    scanf("%d", &n);
    while(n--)
    {
        scanf("%lf%lf%lf%lf", &p1.x, &p1.y, &p2.x, &p2.y);
        scanf("%lf%lf%lf%lf", &p3.x, &p3.y, &p4.x, &p4.y);
        if(isParallel(p1 - p2, p3 - p4)) puts("2");
        else if(isOrthogonal(p1 - p2, p3 - p4)) puts("1");
        else puts("0");
    }
    return 0;
}

(3)两线段相交

#include
#include
#include
using namespace std;
const double eps = 1e-8;

int sgn(double x){
    if(fabs(x) < eps) return 0;
    if(x > 0) return 1;
    else return -1;
}
struct Point{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double k){return Point(k*x,k*y);}
    Point operator / (double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;};
    double abs(){return sqrt(norm());}
};
typedef Point Vector;
double dot(Vector a, Vector b)
{
    return a.x * b.x + a.y * b.y;
}
double cross(Vector a, Vector b)
{
    return a.x * b.y - a.y * b.x;
}
Point p1, p2, p3, p4, ans;
int n;
/*
Point a=p1-p0;
Point b=p2-p0;
1.外积大小cross(a,b)为正时,可确定b在a的逆时针方向
	sin(Y)(Y在0-180)所以是正数
2. 外积大小cross(a,b)为负时,可确定b在a的顺时针方向
3.(1,2)不符合 表示p2在直线p0p1上(注意是直线),cos(Y)大于90或小于-90
	度时为负,因此a与b的内积dot(a,b)负时,可确定p2位于线段p0p1后方
	即p2->p0->p1
4.不是3时,有俩种p0->p1-p2或者p0->p2->p1如果b的大小大于a的大小,即为
	p0->p1->p2;
5.不符合4,可以确定p2位于线段p0p1上
*/
int ccw(Point p0,Point p1,Point p2)//判断三个点相对位置
{
	Point a=p1-p0;
	Point b=p2-p0;
	if(cross(a,b)>eps) return 1;//p0,p1,p2成逆时针方向
	if(cross(a,b)<-eps) return -1;//p0,p1,p2成顺时针方向
	if(dot(a,b)<-eps) return 2;//p2 p0 p1一次排列在同一直线上
	if(a.norm()
#include
#include
using namespace std;
const double eps = 1e-8;

int sgn(double x){
    if(fabs(x) < eps) return 0;
    if(x > 0) return 1;
    else return -1;
}
struct Point{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double k){return Point(k*x,k*y);}
    Point operator / (double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;};
    double abs(){return sqrt(norm());}
};
typedef Point Vector;
double dot(Vector a, Vector b)
{
    return a.x * b.x + a.y * b.y;
}
double cross(Vector a, Vector b)
{
    return a.x * b.y - a.y * b.x;
}
Point p1, p2, p3, p4, ans;
int n;
/*
Point a=p1-p0;
Point b=p2-p0;
1.外积大小cross(a,b)为正时,可确定b在a的逆时针方向
	sin(Y)(Y在0-180)所以是正数
2. 外积大小cross(a,b)为负时,可确定b在a的顺时针方向
3.(1,2)不符合 表示p2在直线p0p1上(注意是直线),cos(Y)大于90或小于-90
	度时为负,因此a与b的内积dot(a,b)负时,可确定p2位于线段p0p1后方
	即p2->p0->p1
4.不是3时,有俩种p0->p1-p2或者p0->p2->p1如果b的大小大于a的大小,即为
	p0->p1->p2;
5.不符合4,可以确定p2位于线段p0p1上
*/
int ccw(Point p0,Point p1,Point p2)//判断三个点相对位置
{
	Point a=p1-p0;
	Point b=p2-p0;
	if(cross(a,b)>eps) return 1;//p0,p1,p2成逆时针方向
	if(cross(a,b)<-eps) return -1;//p0,p1,p2成顺时针方向
	if(dot(a,b)<-eps) return 2;//p2 p0 p1一次排列在同一直线上
	if(a.norm()

(4)两线段交点

#include
#include
#include
using namespace std;
const double eps = 1e-8;

struct Point{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double k){return Point(k*x,k*y);}
    Point operator / (double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;};
    double abs(){return sqrt(norm());}
};
typedef Point Vector;
double dot(Vector a, Vector b)
{
    return a.x * b.x + a.y * b.y;
}
double cross(Vector a, Vector b)
{
    return a.x * b.y - a.y * b.x;
}


struct Segment{
    Point p1,p2;
};
Point getCrossPoint(Segment a,Segment b)
{
    Vector base=b.p2-b.p1;
    double d1=fabs(cross(a.p1-b.p1,base));
    double d2=fabs(cross(a.p2-b.p1,base));
    double t=d1 / (d1 + d2);
    Point ans=a.p1 + (a.p2 - a.p1) * t;
    return ans;
}
Point p1, p2, p3, p4, ans;
int n;

int main()
{
    scanf("%d", &n);
    while(n--)
    {
        scanf("%lf%lf%lf%lf", &p1.x, &p1.y, &p2.x, &p2.y);
        scanf("%lf%lf%lf%lf", &p3.x, &p3.y, &p4.x, &p4.y);
        Segment a, b;
        a.p1 = p1, a.p2 = p2, b.p1 = p3, b.p2 = p4;
        ans = getCrossPoint(a, b);
        printf("%.10f %.10f\n", ans.x, ans.y);
    }
    return 0;
}


(5)判断凸多边形

先判断第1和第2个边的位置如果是逆时针方向,则每次判断下个点的位置,是在顺时针方向还是在逆时针方向,在遍历过程中有一个向量向顺时针方向了,是凹多边形

#include
#include
#include
using namespace std;
const double eps = 1e-8;

struct Point{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double k){return Point(k*x,k*y);}
    Point operator / (double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;};
    double abs(){return sqrt(norm());}
};
typedef Point Vector;
double dot(Vector a, Vector b)
{
    return a.x * b.x + a.y * b.y;
}
double cross(Vector a, Vector b)
{
    return a.x * b.y - a.y * b.x;
}

const int COUNTER_CLOCKWISE = -1;
const int CLOCKWISE = 1;
const int ON_SEGMENT = 0;
const int ONLINE_BACK = 2;
const int ONLINE_FRONT = -2;
int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    if(cross(a,b)>eps) return COUNTER_CLOCKWISE;
    if(cross(a,b)<-eps) return CLOCKWISE;
    if(dot(a,b)<-eps) return ONLINE_BACK;
    if(a.norm()

(6)任意凸多边形面积

两个向量同一起点的叉乘积再乘1/2就是三角形的面积(哦哦哦,我知道,把多边形分成三角形就可以了)

#include
#include
#include
using namespace std;
const double eps = 1e-8;

struct Point{
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y){}
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double k){return Point(k*x,k*y);}
    Point operator / (double k){return Point(x/k,y/k);}
    double norm(){return x*x+y*y;};
    double abs(){return sqrt(norm());}
};
typedef Point Vector;
double dot(Vector a, Vector b)
{
    return a.x * b.x + a.y * b.y;
}
double cross(Vector a, Vector b)
{
    return a.x * b.y - a.y * b.x;
}


double getS(Point a,Point b,Point c) //返回三角形面积
{
    return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y)*(c.x - a.x))/2;
}
double getPS(Point p[],int n) //返回多边形面积。必须确保 n>=3,且多边形是凸多 边形
{
    double sumS=0;
    for(int i=1;i<=n-1;i++)
        sumS+=getS(p[1],p[i],p[i+1]);
    return sumS;
}

Point p[110];
int n;

int main()
{
    while(~scanf("%d", &n) && n)
    {
        for(int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
        double ans = getPS(p, n);
        printf("%.1f\n", ans);
    }
    return 0;
}

(7)线段之间的距离

模板解释博客

#include
#include
#include
#include
using namespace std;
typedef struct node
{
	double x, y;
}NODE;
double cross(NODE A, NODE B, NODE P)      //向量AB与向量AP的外积
{
	NODE AB = { B.x - A.x, B.y - A.y };
	NODE AP = { P.x - A.x, P.y - A.y };
	return AB.x*AP.y - AB.y*AP.x;
}
double dot(NODE A, NODE B, NODE P)         //向量AB与向量AP的外积
{
	NODE AB = { B.x - A.x, B.y - A.y };
	NODE AP = { P.x - A.x, P.y - A.y };
	return AB.x*AP.x + AB.y*AP.y;
}
double dis2(NODE a, NODE b)                //点a、b距离的平方
{
	return (a.x - b.x)*(a.x - b.x) + (a.y-b.y)*(a.y-b.y);
}
int dir(NODE A, NODE B, NODE P)            //点P与线段AB位置关系
{
	if (cross(A, B, P) < 0) return -1;     //逆时针
	else if (cross(A, B, P)>0) return 1;   //顺时针
	else if (dot(A, B, P) < 0) return -2;  //反延长线
	else if (dot(A, B, P) >= 0&&dis2(A,B)>=dis2(A,P))
	{
		if (dis2(A, B) < dis2(A, P)) return 2;  //延长线
		return 0;                          //在线上
	}
}
double disMin(NODE A, NODE B, NODE P)      //点P到线段AB的最短距离
{
	double r = ((P.x-A.x)*(B.x-A.x) + (P.y-A.y)*(B.y-A.y)) / dis2(A, B);
	if (r <= 0) return sqrt(dis2(A, P));
	else if (r >= 1) return sqrt(dis2(B, P));
	else
	{
		double AC = r*sqrt(dis2(A,B));
		return sqrt(dis2(A,P)-AC*AC);
	}
}
int main()
{
	NODE A1, A2, B1, B2;
	int n;
	scanf("%d", &n);
	while(n--)
    {
        cin >> A1.x >> A1.y;
        cin >> A2.x >> A2.y;
        cin >> B1.x >> B1.y;
        cin >> B2.x >> B2.y;
        if (dir(A1, A2, B1)*dir(A1, A2, B2) <= 0 && dir(B1, B2, A1)*dir(B1, B2, A2) <= 0)  //两线段相交, 距离为0
            printf("%.10f\n", 0);
        else printf("%.10f\n", min(min(min(disMin(A1, A2, B1), disMin(A1, A2, B2)), disMin(B1, B2, A1)),disMin(B1,B2,A2)));
                                                        //如不相交, 则最短距离为每个端点到另一条线段距离的最小值
    }
	return 0;
}

 

 

你可能感兴趣的:(计算几何)