计算几何基础

24 篇文章 0 订阅
5 篇文章 0 订阅

最基本的概念就是叉积,其实说白了就是三角形的面积的2倍。但是叉积有正负,所以可以用来判定给定的三个点的顺序问题。

叉积的公式为:E X C = x1*y2 - x2*y1(在原点的情况)。模板为:

double multi(point p0,point p1,point p2)//计算叉积     
{   return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);    
}

(1) 若C×E<0,则E在C的顺时针方向;(2)若C×E>0,则E在C的逆时针方向;(3)若C×E=0,则E与C共线,但可能同向也可能反向。

上面的图形中要求三角形OCE的面积S,因为:2S=2*(矩形OABD的面积-S1-S2-S3),所以S=|x1y2-x2y1|/2

用这种方法可以求一般的三角形面积,模板为:

struct Point 
{   double x,y;
};
Point P[3];
double Area()
{   return fabs(P[0].x*P[1].y+P[1].x*P[2].y+P[2].x*P[0].y-P[1].x*P[0].y-P[2].x*P[1].y-P[0].x*P[2].y)/2;
}

这个就是上面叉积化简得到的,只是利用叉积的时候要加绝对值和/2。

同样我们可以用三角形面积求多边形面积,可以拆分成多个小三角形面积之和,如图所示:

四边形ABCD的面积可以分解为三角形PAB的面积+PBC+PCD+PDA(P为四边形内任意一点),由于都是顺时针方向,所以利用叉积求出三角形面积后取绝对值刚好是四边形面积。

但是P(x,y)为任意一点的话,这个时候求面积就有些复杂了,比方说A(x1,y1),B(x2,y2)。那么三角形PAB的面积=|(x1-x)*(y2-y)-(x2-x)*(y1-y)|;那么如果这个点为原点的话就很简单了,这个时候PAB的面积=|x1*y2-x2*y1|。问题是P点为原点求出来的面积是不是等于四边形的面积呢?

我们可以看到三角形OAB,OBC,OCD,三点的顺序都是顺时针的,三者的叉积值的符号都是相同的,加起来后的绝对值面积为OABCD的面积,当运行到D点时,三角形ODA三点的顺序是逆时针,刚好与前面的三个三角形的结果值相反,所以OABCD的面积-ODA的面积=ABCD的面积。所以直接以原点为顶点,运用叉积求出即为多边形的面积。

模板为:

const int MAX=1010;
typedef point polygon[MAX];
double polygon_area(polygon p,int n)    
{   double area=0.0;     
    for(int i=1;i<=n;i++)    
        area+=p[i-1].x*p[i%n].y-p[i%n].x*p[i-1].y;  //以原点为定点 
    return fabs(area)/2;   
} 

利用叉积求三个点的顺序NYOJ 68(三点顺序)

#include<iostream>
using namespace std;
struct Point
{   int x,y;
    friend istream& operator>>(istream &cin,Point &P)
    {   cin>>P.x>>P.y;
        return cin;
    } 
    bool operator==(const int &n) const
    {   return x==n&&y==n;
    }
};
Point P[10];
double multi()     
{   return (P[1].x-P[0].x)*(P[2].y-P[0].y)-(P[2].x-P[0].x)*(P[1].y-P[0].y);    
} 
int main()
{   while(cin>>P[0]>>P[1]>>P[2])
    {   if(P[0]==0&&P[1]==0&&P[2]==0) break;   
        if(multi()>0) cout<<0<<endl;
        else cout<<1<<endl;
    }
    return 0;
}

2、Pick定理:给定顶点坐标均是整点的简单多边形,那么其面积A和内部格点数目i,边上格点数目b的关系:A=i+b/2 - 1
求线段上的整点的个数:

给定点P(x0,y0)和Q(x1,y1),若某一个点A(x,y)在这条线段上,那么由定比分点公式有x=x0+λ(x1-x0),y=y0+λ(y1-y0)。由于是整点,所以λ一定为分数,且是(x1-x0)和(y1-y0)的公因数,所以这条线上整点的个数为(x1-x0)和(y1-y0)的最大公约数,sum=gcd(dx,dy)=gcd(x1-x0,y1-y0)。具体模板见代码,注意面积用__int64型:

#include<iostream>
#include<cstdlib> 
using namespace std;
#define __int64 long long
struct Point 
{   int x,y;
    friend istream& operator>>(istream& cin,Point &P)
    {   cin>>P.x>>P.y;
        return cin;
    }
    bool operator==(const int &n) const
    {   return x==n&&y==n;
    }
};
Point P[10];
int gcd(int n,int m)
{   return m==0?n:gcd(m,n%m);
}
__int64 Area(int n) //求多边形面积 
{   __int64 area=0;
    for(int i=1;i<=n;i++)
        area+=P[i-1].x*P[i%n].y-P[i%n].x*P[i-1].y;
    return abs(area);     
}
int Count(int n) //求在线段的点的个数和 
{   int sum=0;
    for(int i=1;i<=n;i++)
    {   int dx=abs(P[i%n].x-P[i-1].x);
        int dy=abs(P[i%n].y-P[i-1].y); 
        sum+=gcd(dx,dy);    
    }
    return sum;    
}
int main()
{   while(cin>>P[0]>>P[1]>>P[2])
    {   if(P[0]==0&&P[1]==0&&P[2]==0) break; 
        __int64 area=Area(3);
        int I=(area-Count(3))/2+1;
        cout<<I<<endl;
    }
    return 0;
}


 


 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值