计算几何基础知识讲义.docx
- 文档编号:24282864
- 上传时间:2023-05-26
- 格式:DOCX
- 页数:30
- 大小:190.70KB
计算几何基础知识讲义.docx
《计算几何基础知识讲义.docx》由会员分享,可在线阅读,更多相关《计算几何基础知识讲义.docx(30页珍藏版)》请在冰豆网上搜索。
计算几何基础知识讲义
计算几何基础知识讲义
一.基础知识
1.两点间的距离公式:
已知:
平面上的两点的直角坐标分别为P1(x1,y1),P2(x2,y2),则P1和P2两点间的距离为
d=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
2.线段的中点坐标公式:
已知:
平面上的两点的直角坐标分别为P1(x1,y1),P2(x2,y2),则线段P1P2的中点坐标为
x=(x1+x2)/2 y=(y1+y2)/2
3.直线的斜率公式:
已知:
平面上的两点的直角坐标分别为P1(x1,y1),P2(x2,y2),则线段P1P2所在的直线的斜率为
k=(y2-y1)/(x2-x1)
4.直线的点斜式方程:
已知:
直线过点P0(x0,y0),斜率为k,则该直线所在的方程为
y=k(x-x0)+y0=kx+y0-kx0=kx+b(与y轴交点的纵坐标:
纵截距)
5、三角形面积
。
当然,还有其他的许多方法,包括大家熟知的
以及Hero公式。
Hero公式是令
,则
。
6、多边形面积计算
如果一个多边形的顶点是按逆时针(顺时针也可)顺序排列的,那么我们可以找到一种简洁的面积算法。
例如右图是一个四边形P1P2P3P4,设P5=P1,xi是各点在x轴上的射影。
我们称PiXiXi+1Pi+1是一个“有向梯形”,并定义其面积为:
“有向梯形”的面积是可正可负的,这就是称其“有向”的原因。
而整个四边形的面积则是:
这个面积就是正数了。
对于各种特殊的四边形,这个算法仍然成立。
这些例子如凹四边形(图2),被x轴切割的四边形(图3),注意图3中有向梯形P1X1X2P2实际上并不是严格的梯形,但这并不影响结果的正确性,这就是“有向梯形”带符号的好处。
这个面积算法对按逆时针排列顶点的四边形的计算结果为正,而对按顺时针排列顶点的四边形的计算结果为负。
此外,它也适用于任意多边形。
【结论】:
设多边形顶点按逆时针依次为(x0,y0),(x1,y1),(x2,y2),…,(xn,yn),其中(xn,yn)=(x0,y0)。
那么,多边形面积为:
时间和空间复杂度都是O(n)。
【练习】
1.已知:
矩形上三点的坐标p1(x1,y1),p2(x2,y2),p3(x3,y3)
(1)求矩形另外一点的坐标p4(x4,y4)。
(2)判断点p(x,y)是在矩形内、矩形外还是在矩形的边上。
多边形面积1918
Description
给出一个简单多边形(没有缺口),它的边要么是垂直的,要么是水平的。
要求计算多边形的面积。
多边形被放置在一个X-Y的卡笛尔平面上,它所有的边都平行于两条坐标轴之一。
然后按逆时针方向给出各顶点的坐标值。
所有的坐标值都是整数(因此多边形的面积也为整数)
Input
输入文件第一行给出多边形的顶点数n(n≤100)。
接下来的n行每行给出多边形一个顶点的坐标值X和Y(都为整数并且用空格隔开)。
顶点按逆时针方向逐个给出。
并且多边形的每一个顶点的坐标值-200≤x,y≤200。
多边形最后是靠从最后一个顶点到第一个顶点画一条边来封闭的。
Output
输出文件仅有一行,包含一个整数,表示多边形的面积。
SampleInput
10
00
40
41
31
33
23
22
12
13
03
SampleOutput
9
二.矢量叉积
1.【矢量的概念】:
如果一条线段的端点是有次序之分的,我们把这种线段成为有向线段。
如果有向线段p1p2的起点p1在坐标原点,我们可以把它称为矢量p2。
2.【矢量加减法】:
设二维矢量P=(x1,y1),Q=(x2,y2),则矢量加法定义为:
P+Q=(x1+x2,y1+y2),同样的,矢量减法定义为:
P-Q=(x1-x2,y1-y2)。
显然有性质P+Q=Q+P,P-Q=-(Q-P)。
矢量平移
3.【矢量叉积】
y
0
x
叉积只的是向量OA与向量OB所形成的三角形的面积
定义O点坐标为(0,0),A点坐标为(X1,Y1),B点坐标为(X2,Y2)
则有叉积公式S=(X1Y2-X2Y1)/2
当角AOB∈(0,π)差集为负,称OA在OB的逆时针方向
当角AOB∈(π,2π)叉积为正,称OA在OB的顺时针方向
当角AOB∈{0,π}叉积为0,称点A在直线OB上(判断点是否在直线上)
已知:
平面上的两点的直角坐标分别为p1(x1,y1),p2(x2,y2)则
(1)该两点相对坐标原点(0,0)的叉积为m=x1*y2-x2*y1
若m>0则相对坐标原点,点p1在点p2的顺时针方向
若m<0则相对坐标原点,点p1在点p2的逆时针方向
若m=0则原点和p1、p2在一条直线上
(2)该两点相对点p0(x0,y0)的叉积为m=(x1-x0)*(y2-y0)-(x2-x0)*(y1-y0)
若m>0则相对p0点,点p1在点p2的顺时针方向
若m<0则相对p0点,点p1在点p2的逆时针方向
若m=0则p0和p1、p2在一条直线上
4.折线段的拐向判断
确定两条连续的有向线段p0p1和p1p2在pl点是向左转还是向右转的方法可以直接由矢量叉积的性质推出。
对于有公共端点的线段p0p1和p1p2,通过计算(p2-p0)×(p1-p0)的符号便可以确定折线段的拐向:
(1)计算叉积m=(x1-x0)*(y2-y0)-(x2-x0)*(y1-y0)
(2)判断m
若m>0则p1点向左拐
若m<0则p1点向右拐
若m=0则点p0、p1、p2在一条直线上
5.判断两线段是否相交
两条线段AB、CD,相交的充要条件是:
A、B在直线CD的异侧且C、D在直线AB的异侧。
也就是说从AC到AD的方向与从BC到BD的方向不同,从CA到CB的方向也与从DA到DB的方向不同。
这可以通过矢量的叉积来判断:
(AC*AD)*(BC*BD)<0且(CA*CB)*(DA*DB)<0
structpos//点
{doublex,y;}//x座标与Y座标值
structline//线段
{pos:
a,b;}
posp1,p2;
linel1,l2;
doublemulti(posp1,p2,p0)//叉积
{return(p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}
boolacross(linel1,l2)//l1,l2是否有交点
{
/*
线段l1,l2的界限框同时在x,y方向上相交才可能有交点
以l1的a点为公共点p0,l2的a点为p1,l1的b点为p2作叉积与以l1的a点为公共点p0,l1的b点为p1,l2的b点为p2作叉积相乘.若大于0则l2跨立l1
以l2的a点为公共点p0,l1的a点为p1,l2的b点为p2作叉积与以l2的a点为公共点p0,l2的b点为p1,l1的b点为p2作叉积相乘.若大于0则l1跨立l2
*/
if((max(l1.a.x,l1.b.x)>=min(l2.a.x,l2.b.x)&&(min(l1.a.x,l1.b.x)<=max(l2.a.x,l2.b.x)&&(max(l1.a.y,l1.b.y)>=min(l2.a.y,l2.b.y)&&(min(l1.a.x,l1.b.y)<=max(l2.a.x,l2.b.y)&&
(multi(l2.a,l1.b,l1.a)*multi(l1.b,l2.b,l1.a)>0)&&(multi(l1.a,l2.b,l2.a)*multi(l2.b,l1.b,l2.a)>0))return1;
return0;
}
intmain()
{cin>>l1.a.x>>l1.a.y>>l1.b.x>>l1.b.y;//l1的两点座标
cin>>l2.a.x>>l2.a.y>>l2.b.x>>l2.b.y);/l1的两点座标
cout< return0; } 应用1: 1判断直线与线段是否相交 直线给出的是两个点坐标,把其中一个定义为原点,判断线段的两个端点是否在直线的同一方向(顺时针或逆时针),是则线段与直线不想交,否则相交 2判断线段与线段是否相交 按照判断直线与线段是否相交的方法,分别把线段1和线段2当成直线,如果线段2的两个段点在线段1所在直线的两侧,且线段1的两个端点在线段2所在直线的两侧,则两线段相交,否则不相交。 3判断点是否在凸多边形内 顺时针遍历凸多边形的边,如果对于每条边,所给的点都在其顺时针方向,则点在多边形内 应用2: 凸包 三.凸包算法 1.凸包的概念 一个点集Q=(p0,p1,p2...pn-1),它的凸包是一个最小的凸多边形P,且满足Q中的每个点或者在P的边界上,或者在P的内部。 在直观上,我们可以把Q中的每个点看作露在板外的铁钉.那么凸包就是包含所有铁钉的一个拉紧的橡皮绳所构成的形状. 如图: 2.寻找凸包算法 算法如下(极角序Graham-Scan算法): 1)求q中y坐标最小的点p0,若具有最小坐标的点有多个,则取最左边的点作为p0. 2)对q中剩余的点按逆时针相对p0的极角排序,若有数个保留其中距p0最远的点得到序列(p1,p2,...pn-1); 3)p0,p1,p2相继入栈 4)fori=3ton-1do while由次栈顶元素、栈顶元素和Pi所形成角不是向左转do栈顶元素出栈s; pi入栈 5)打印按逆时针排列的栈中的各顶点 1、找出点集Q中处于最低位置(Y坐标值最小)的一个点P0是凸包ch(Q)的一个顶点。 如果这样的顶点有多个,则选取最左边的点为P0。 2、各点依据逆时针方向上相对P0的极角的递增次序排列成Q。 极角的大小通过计算叉积(Pi-P0)*(Pj-P0)确定: 若叉积>0,则说明相对P0来说,Pj的极角大于Pi的极角,Pi先于Pj被扫描; 若叉积<0,则说明Pj的极角小于Pi的极角,Pj先于Pi被扫描; 若叉积=0,则说明两个极角相等。 在这种情况下,由于Pi和Pj中距离P0较近的点不可能是凸包的顶点,因此只需扫描其中一个与P0距离较远的点。 3、按照Q序列顺序确定凸包顶点。 堆栈S存储凸包顶点。 初始时P0和排序后的P1、P2相继入栈。 扫描过程中,Q集合中的其它点都被推入堆栈一次,而不是凸包ch(Q)顶点的点最终将弹出堆栈。 判别栈顶元素是否为凸包顶点的方法: 若栈顶元素向左转指向当前被扫描的点Pi,则为凸包顶点,即(Pi-Ptop-1)*(Ptop-Ptop-1)<0; 否则((Pi-Ptop-1)*(Ptop-Ptop-1)≥0)栈顶元素不属于凸包顶点,从堆栈S中移出。 在弹出了所有非左转的顶点后,我们就把Pi推入堆栈S,继续扫描序列中的下一个点Pi+1。 当算法结束时,堆栈S中仅包含ch(Q)的顶点,其顺序为各点在边界上出现的逆时针方向排列的顺序。 极角序Graham-Scan算法 constintMaxn=2000; structpoint { doublex,y; }; pointa[Maxn];//存储点坐标 intb[Maxn];//栈,存储点的顺序号 intn,tot; voidinit() { intmin=1; cin>>n; for(intk=0;k { cin>>a[k].x>>a[k].y; if((a[min].y>a[k].y)||(a[min].y=a[k].y&&a[min].x>a[k].x))min=k; } pointtemp; temp=a[0],a[0]=a[min],a[min]=temp; } intchaji(constvoid&p0,constvoid&p1,constvoid&p2) { point*a,*b,*c; a=(point)p0,b=(point)p1,c=(point)c; return(b->x-a->x)*(c->y-a->y)-(b->y-a->y)*(c->x-a->x); } intcompare(constvoid&a,constvoid&b) { return(chaji(&a[0],a,b)); } intgram() { inti; tot=2;b[0]=0;b[1]: =1; for(i=2;i { while((tot>1)&&! (chaji(a[b[tot-1]],a[b[tot]],a[i]))tot--; tot++;b[tot]=i; } } intmain() { init(); qsort(a+1,n-1,sizeof(point),compare);//按极角序对点排序 gram(); for(inti=0;i } 方法二: 水平序Graham-Scan算法 将所有的点按y坐标从小到大排序,y相同则按x从小到大排。 从最小一个y开始,按排好的序从小到大,用上面的栈的方法做凸包,一次以后,得到凸包的右链。 然后用相同的方法,按y从大到小顺序再做一次,得到凸包的左链。 两条链拼在一起就是凸包了。 与极角序相比时间复杂度虽然和上面相同,但这种算法更优。 其优势在于: 1、排序方法更简单;2、避免了一些特殊情况 【参考代码】 水平序Graham-Scan算法 constintMaxsize=201; structPoint { intx,y; }; inlinePointoperator-(constPoint&a,constPoint&b) { Pointc; c.x=a.x-b.x; c.y=a.y-b.y; returnc; } inlineintoperator*(constPoint&a,constPoint&b) { returna.x*b.y-a.y*b.x; } PointP[Maxsize];//存储点坐标 intStack[Maxsize];//栈,存储点的顺序号 inttop,N; inlineboolTurnRight(constPoint&a,constPoint&b,constPoint&c) { if((c-a)*(b-a)>=0)returntrue; returnfalse; } voidConvexHull() { boolUsed[Maxsize]; memset(Used,false,sizeof(Used)); intk,MaxTop; for(inti=1;i for(intj=1;j<=N-i;j++) if(P[j].y>P[j+1].y||P[j].y==P[j+1].y&&P[j].x>P[j+1].x)//按从下到上,从左到右顺序对点排序 swap(P[j],P[j+1]); //寻找右链,栈的第一个元素为最左下角点编号 Stack[1]=1; k=2; top=1; while(k<=N) { while(top>1&&TurnRight(P[Stack[top-1]],P[Stack[top]],P[k])) Used[Stack[top--]]=false; //与栈顶两个点形成右拐则出栈 Stack[++top]=k; //当前点入栈 Used[k]=true; k++; //从下往上扫描 } //寻找左链,栈的第一个元素为最右上角点编号 MaxTop=top; k=N-1; while(k>=1) { while(Used[k])k--; while(top>MaxTop&&TurnRight(P[Stack[top-1]],P[Stack[top]],P[k])) Used[Stack[top--]]=false; //与栈顶两个点形成右拐则出栈 Stack[++top]=k; //当前点入栈 Used[k]=true; k--; // 从上往下扫描 } } 【练习试题】 轰炸1034 Description “我该怎么办? ”飞行员klux向你求助。 事实上,klux面对的是一个很简单的问题,但是他实在太菜了。 klux要想轰炸某个区域内的一些地方,它们是位于平面上的一些点,但是(显然地)klux遇到了抵抗,所以klux只能飞一次,而且由于飞机比较破,一点起飞就只能沿直线飞行,无法转弯。 现在他想一次轰炸最多的地方。 Input 第一行n(1 以下n行每行有一对整数,表示一个点的坐标。 没有一个点会出现两次。 Output 一个整数,表示一条直线能覆盖的最多的点数。 SampleInput 5 11 22 33 910 1011 SampleOutput 3 #include #defineX(a,b)(a.x-b.x)//向量减 #defineY(a,b)(a.y-b.y) usingnamespacestd; intmx=2; structPoint {intx,y; }pp[800];//定义点 inlineboolcross(Pointa,Pointb,Pointc)//叉积判断 {if(X(b,a)*Y(c,a)-Y(b,a)*X(c,a)==0)returntrue; returnfalse; } intmain() { intn,i,j,t,e; scanf("%d",&n); for(i=0;i scanf("%d%d",&(pp[i].x),&(pp[i].y)); if(n<=2) {cout< for(i=0;i {for(j=0;j {e=2; for(t=i+1;t { if(cross(pp[i],pp[j],pp[t]))e++; if(n-t+e } if(e>mx)mx=e; } } cout< return0; } 机器蛇1922 【问题描述】: 在未来的某次战争中,我军计划了一次军事行动,目的是劫持敌人的航母。 由于这个计划高度保密,你只知道你所负责的一部分: 机器蛇的通信网络。 计划中要将数百条机器蛇投放到航母的各个角落里。 由于航母内部舱室、管线错综复杂,且大部分由金属构成,因此屏蔽效应十分强烈,况且还要考虑敌人的大强度电子干扰,如何保持机器蛇间的联系,成了一大难题。 每条机器蛇的战斗位置由作战计划部门制定,将会及时通知你。 每条机器蛇上都带有接收、发射系统,可以同时与多条机器蛇通讯。 由于整个系统承载的数据量庞大,需要一个固定的通讯网络。 情报部门提供了极其详尽的敌方航母图纸,使你对什么地方有屏蔽了如指掌。 请你设计一个程序,根据以上信息构造通讯网络,要求信息可以在任意两条机器蛇间传递,同时为了避免干扰,通讯网络的总长度要尽可能的短。 【文件输入】: 第一行是一个整数n(n≤200)表示参战的机器蛇总数。 以下n行,每行两个整数xi,yi,为第i支机器蛇的战斗位置。 接下来一行是一个整数m(m≤100)表示航母内部可能产生屏蔽的位置。 最后m行,每行四个整数ai,bi,ci,di,表示线段(ai,bi)-(ci,di)处可能有屏蔽,也就是说通讯网络不能跨越这条线段。 【文件输出】: 仅一个实数,表示建立的通讯网的最短长度,保留3位小数。 如果不能成功建立通讯网,请输出-1.000。 【样例输入】: 3 13 31 55 1 0033 【样例输出】: 8.944 【模拟试题】多边形面积1478 Description 在直角坐标系中,给出n个顶点的坐标,求这n个点所围成的图形的周长和面积。 注意: (1)如果所有点共线则周长按直线的长度计算,面积视为0; (2)如果部分点共线按共线后的多边形计算; (3)所给出的n个顶点如果能围成多边形均为突多边形。 Input 第一行输入多边形顶点个数n(3<=n<=10); 接下来n行每行输入一个顶点坐标x,y,x,y均为整数且坐标的绝对值均不超过10。 Output 两行,即多边形的周长和面积(均保留两位小数)。 SampleInput 4 00 10 01 11 SampleOutput 4.00 1.00 【2007年四川】最大土地面积2044 Description: 在某块平面土地上有n个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大 Input: 第1行一个正整数n,接下来n行,每行2个数x、y,表示该点的横坐标和纵坐标。 Output: 最大的多边形面积,答案精确到小数点后3位。 SampleInput 5 00 10 11 01 0.50.5 SampleOutput: 1.000 【数据范围】n<=2000,|x|,|y|<=100000 练习: 1.巳知: 平面上有n个点(n<=10000),用Graham算法找出彼此间最远的两个点. 多边形面积 【曙光试题】两个凸多边形交的面积1140 Description 在平面上有两给定的凸多边形
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算 几何 基础知识 讲义
![提示](https://static.bdocx.com/images/bang_tan.gif)