计算几何初步

来源:互联网 发布:矩阵和伴随矩阵的秩 编辑:程序博客网 时间:2024/05/19 12:27

表示点,线,面的方法

使用传统解析几何的方法会导致特殊情况过多,使得我们的计算偏差较大。

2. 使用矢量法来表示点

矢量法的基本运算
设向量a< x1,y1>, b< x2,y2>
a+b=< x1+y1,x2+y2>
ab = |a||b|cos< a,b> = x1*x2+y1*y2 矢量法的点积表示的是一个向量在另外一个向量上的投影的长度。
|a| = sqrt(aa) 即向量的膜长就是自己和自己点积德平方根
unit(a) = 1/|a|a即矢量除自己的膜长可以得到同个方向上的单位向量。
p*q = |p||q|sin< p,q> 即表示p,q的有向面积
两个矢量围成的三角形的面积,即两个向量点积德绝对值的一半

求解一个多边形的面积

我们通常的思路是将一个多边形划分成三角形来求解。在计算几何当中,我们采用特殊的一个点--原点来累加多边形的面积。能够较为方便的求解这个问题

表示线和面的方法

常用的常数和函数

因为在计算几何当中,我们常常需要使用到浮点数,所以,不能以整型的方法来定义浮点数
double EPS = 10e-8;
double INF = 1<<20
double PI = acos(-1)…
判断是否为0或者比较大小的时候,不能够简单的使用两个浮点数相减的结果,然后和0比较,而是要和我们所定义的近似0相比较。

线之间一些常见问题的求解

(1)两点之间的距离:使用两点之间所连膜长
(2)点和线之间的距离:求四边形面积,再除以两向量之差的膜长。
(3)线旋转后所得到的线:
两个点均在同一个圆上,采用参数方程表示再化简,可得
c< x,y> = < x1+x2*cos(alpha)-y*sin(alpha),y1+y2*cos(alpha)+x2*sin(alpha)>
(4)判断给定的点在直线的那一侧
使用叉积 (p-a)*(b-a)=0 则三点共线
小于0则在直线的右侧
大于0则会在直线的左侧
(5)过某个点做垂线

线段相交

(1)两条线段所延展的两条直线相交
由高中的几何知识可以知道,两条直线只有可能存在两种关系,相交,重合和平行。所以,判断是否两条直线的位置关系,只要使用叉乘,并判断一条直线上的某一点是否位于另外一条直线上。
(2)从直线相交延展到线段相交,就会有下面的几种情况:
1.平行,重合
2.某一个端点位于另外的一条直线上。
3.标准相交
那么,我们怎么判断标准相交呢?
两条线段的两个端点都位于对方的两侧。
判断方法:仍然施用叉积的方法。

点和多边形的关系

1.转角法
沿着四边形转动一圈来判断是否在四边形的内部。
2. 射线法
从给定的点发出射线判断和多边形的交点。
特殊情况:点就在这个多边形的边界上,可以通过特判加以解决。

一道例题[poj1066]

刷题的时候就想着等以后做计算几何的时候再来写这道题,结果就拖了整整4个月,拖延症晚期伤不起啊。
其实还是很简单的,就是从宝藏的所在地到边界最多需要穿过多少道墙。我们看到,墙把边界都已经离散化了。所以我们只需要对每个区间和宝藏所在地的连线求与墙的交点的个数(规范相交),就可以得到结果,代码如下。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define MAXN 35#define INF 100#define ZERO 10e-6struct CPoint{    double x,y;    CPoint(){}    CPoint(double a,double b){        x = a;        y = b;    }    friend double operator^(CPoint a,CPoint b){        return a.x*b.y-b.x*a.y;    }    friend CPoint operator-(CPoint a,CPoint b){        return CPoint(a.x-b.x,b.y-a.y);     }};struct CLine{    CPoint st,en;    CLine(){}}LineTable[MAXN],seg;int n;bool intersected(CLine a, CLine b){//judge if two lines is intersected    double d1 = (a.en-a.st)^(b.st-a.st);    double d2 = (a.en-a.st)^(b.en-a.st);    double d3 = (b.en-b.st)^(a.en-b.st);    double d4 = (b.en-b.st)^(a.st-b.st);    if(((d1>ZERO&&d2<ZERO)||(d1<ZERO&&d2>ZERO)) && ((d3>ZERO&&d4<ZERO)||(d3<ZERO&&d4>ZERO)))        return true;    return false;}int Test(){    int i;    int cnt = 0;    for(i=0;i<n;i++){        if(intersected(LineTable[i],seg))            cnt++;    }    return cnt;}int main(){    freopen("input","r",stdin);    int i;    int ans = INF;    scanf("%d",&n);    for(i=0;i<n;i++){        scanf("%lf%lf",&LineTable[i].st.x,&LineTable[i].st.y);        scanf("%lf%lf",&LineTable[i].en.x,&LineTable[i].en.y);    }    scanf("%lf%lf",&seg.st.x,&seg.st.y);    for(i=0;i<n;i++){        seg.en = LineTable[i].st;        ans = min(ans,Test());        seg.en = LineTable[i].en;        ans = min(ans,Test());    }    seg.en = CPoint(0.0,0.0);    ans = min(ans,Test());    seg.en = CPoint(0.0,100.0);    ans = min(ans,Test());    seg.en = CPoint(100.0,0);    ans = min(ans,Test());    seg.en = CPoint(100.0,100.0);    ans = min(ans,Test());    printf("Number of doors = %d\n",ans+1);    //we must have a door on the edge    return 0;}
0 0
原创粉丝点击