已知平面三点坐标求其中两条边之间的夹脚

回首这篇两年前写的博客,算是自己觉得比较有意思的一篇了,那时候刚拿毕业证也就一年左右吧,在一家小公司写代码,然后一同事也是前辈向我讨教这个问题,问我有没有招编程解决这个问题。抱着试试看的态度立马就研究了起来,从理论到实践,也是第二次感觉到数学和代码的结合真的很奇妙(第一感觉神奇的是在学校实验室捣鼓四轴飞行器的pid算法,通过用微分和积分的以及比例控制对飞机的过去、现在、以及未来的飞行姿态做最佳调控)。学的一点数学基础还好没有交还给老师,查资料然后理论+实践花了一小会功夫算是把代码写出来了。虽然只是简单的一道数学题转变为C代码实现。但工作两年多了,确很少有找到这种编程的乐趣和感觉!

向量:既有大小又有方向的量叫向量。
向量的模:向量的长度称为向量的模,用符号| |表示。
零向量:长度为0的向量</span>
单位向量:长度为1的向量平面中,设有向量a={x1, y1},向量b={x2, y2},则有
(1)       向量的加:a+b={x1+x2, y1+y2}
(2)       向量的减:a-b={x1-x2, y1-y2}
(3)       向量的点积(内积):a·b=|a|*|b|*cosθ=x1*x2 + y1*y2
(4)       向量的叉积(外积):a×b=x1*y2 - x2*y1 注:文中出现的*为数学乘法,×为叉积运算符。

 

三维中,设有向量a={x1, y1, z1},向量b={x2, y2, z2},

则a×b = {y1*z2-y2*z1, x2*z1-x1*z2, x1*y2-x2*y1}。注:点用()表示,如(x, y, z),而向量用{}表示,如{x, y, z}。

设有点A=(x1, y1),点B=(x2, y2),则由A到B可组成向量AB={x2-x1, y2-y1}(AB=-BA)。

 

平面中有两个向量a和b:
a∥b当且仅当a×b=0(0向量)
a⊥b当且仅当a·b=0
 
叉积的一个非常重要性质是,可以通过它的符号判断两矢量相互之间的顺逆时针关系:
若a×b > 0 , 则a在b的顺时针方向。
若a×b < 0, 则a在b的逆时针方向。
若a×b = 0,则a和b共线,方向相同或相反。


给出了坐标, 先求出两个向量的模,再求出两个向量的向量积
|a|=√[x1^2+y1^2]
|b|=√[x2^2+y2^2]
a*b=(x1,y1)(x2,y2)=x1x2+y1y2

cos=a*b/[|a|*|b|]=(x1x2+y1y2)/[√[x1^2+y1^2]*√[x2^2+y2^2]]


设a向量坐标为(x1,y1)b向量坐标为(x2,y2)则ab数量积a.b=x1x2+y1y2(注:a.b是数量积,a*b是向量积,是不一样的,不能弄混了.)</span>

 

数量积等于两向量对应坐标相乘后相加,当夹角大于90度时便为负值

 

 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#define PI 3.1415926

double Get_angle(double Ax, double Ay, double Bx, double By, double Cx, double Cy)
{
	
	double AB = 0;//向量AB的模 
	double BC = 0;
	double Sab = 0.0, Sbc = 0.0, Sabc = 0.0;
	
	double val = 180.0 / PI;
	double angle = 0.0;

	
	AB = sqrt( pow(Ax-Bx,2) + pow(Ay-By,2) ) ;
	BC = sqrt( pow(Bx-Cx,2) + pow(By-Cy,2) ) ;
	
	printf("AB = %f\n", AB);
	printf("BC = %f\n", BC);
	
	Sab = (Bx - Ax) * (Cx - Bx);//向量 
	Sbc = (By - Ay) * (Cy - By);
	

	
	Sabc = sqrt( pow(Sab, 2) + pow(Sbc, 2) ); 
	
	printf("Sab = %f\n", Sab);
	printf("Sbc = %f\n", Sbc);
	printf("Sabc = %f\n", Sabc);
	
	angle =  acos( (Sabc/(AB*BC)) ) * val;	
	
	printf("Sab + Sbc = %f\n", Sab + Sbc);
	if( (Sab + Sbc) < 0 )
	{
		angle = 180.0 - angle;	
	}
	
	return angle;		
}

int main(void)
{
	double  ret = 0;
	//A(0,3)  B(0,0)  C(5,0)  90 正确
	//A(0,3)  B(0,0)  C( 3.464102,2)  120 正确
	//A(0,3)  B(0,0)  C( 3.464102,-2)  60 正确
	 
	
    ret = Get_angle(0, 3, 0, 0,-3.464102, 2.0);

    printf("ret = %f\n", ret);
    
    system("pause");
    return 0;
}

 

效果截图!算是复习了高中时的数学了!

 

当然这里如果自己画图来理解验证的话就会更清晰了!

 

【问题描述】 至少有三条直线平面封闭图形称为多形。图1a 的多形有 6条,图1b 的多形有 8 条。多形既包含其线上的点,也包含线内的点。一个多形如果它的任意两个点的连线都不包含该多形以外的点,就称为凸多形,图1a 的多形是凸多形,而图1b 的多形不是凸多形。图1b 的两条虚线段虽然其端点属于多形,但它们都包含了多形以外的点。 一个平面点集S的凸包是指包含S的最小多形。该多形的顶点(即角)称为S的极点。图2是平面上的13个点,它的凸包是由实线连成的多形,极点用圆圈来标识。如果S的点都落在一条直线段上(即这些点是共线点 ),那么S的凸包就退化为包含S的最短直线。 寻找一个平面点集的凸包是计算几何的基本问题。计算几何还有其他问题(如包含一个指定点集的最小矩形),解这些问题需要计算凸包。此外,凸包在图象处理和统计学中也有应用。 假定在S的凸包内部取一个点X,然后从X向下画一条垂直线(如图3a所示)。后面的算法补充说明1介绍了如何选择点X。这条垂直线与X和S的第i个点的连线之间有一个逆时针夹角,称为极角,用ai表示图3a给出了极角a2。现在按照极角非递减次序来排列S的点,对于极角相同的点,按照它们与X的距离从小到大来排列。在图3 中,所有点按照上述次序被依次编号为1~ 13。 从X向下的垂线沿逆时针扫描,按照极角的次序会依次遇到 S的极点。如果 u、v和w是按照逆时针排列的三个连续的极点,那么从u到v与从w到两条连线之间的时针夹角大于180度。(图3b给出了点8、11、12之间的逆时针夹角。) 当按照极角次序排列的3个连续点之间的逆时针夹角小于或等于 180 度时,第二个点不是极点。当u、v、w间的逆时针夹角小于180度时,如果从u走到v再走到w,那么在v点将会向右转。当按逆时针方向在一个凸多形上行走时,所有的转弯都是向左转。根据这种观察,得出了以下的算法用以寻找 S的极点和凸包。   步骤1) [处理退化情况] 如果S的点少于3个,则返回S 如果 S 的所有点都在一条直线上,即共线,则计算并返回包含S所有点的最短直线的两个端点   步骤2) [按极角排序] 在S的凸包内找到一个点X 按照极角递增次序来排列 S 的点,对于极角相同的点,按照它们与X的距离从小到大来排列创建一个以S的点为元素,按照上述顺序排列的双向循环链表 令right指向后继,left指向前驱   步骤 3)  [删除非极点的点] 令p是y坐标最小的点(也可以是 x 坐标最大的) for(x=p,rx=x右的下一个点; p!=rx; ) {     rrx=rx右的点;     if(x, rx和rrx的逆时针夹角小于或等于180度)     {         从链表中删除rx;         rx=x;x=rx左的点;     }     else {x=rx; rx=rrx;} } 步骤1) 处理退化情况,即S的点数为1或2,或S的所有点是共线的。这一步用时O(n),其中n是S的点数。判断共线的方法是,任取两个点,出两点连线的方程式,然后检查余下的 m-2 个点是否在这条直线上。如果所有点是共线的,也可以确定最短直线的端点。  步骤2) 按照极角的次序排列 S的点,并把它们存人一个双向链表。之所以采用双向链表是因为步骤3)需要消除非极点的点,并在链表中反向移动,当然也可以采用单向链表。因为需要排序,可以采用 O(nlogn)时间内的算法完成排序,因此步骤2)的时间复杂度可以计为 O(nlogn)。 步骤3) 依次检查按逆时针次序排列的三个连续点,如果它们的逆时针夹角小于或等于180度,则中间的点x 不是极点,要从链表中删除之。如果夹角超过 180 度,则rx 可能是也可能不是极点,可将点x移到下一个点。当 for 循环终止时,在链表中每三个连续的点所形成的逆时针夹角都超过 180 度,因此链表的点都是极点。沿着链表的 next 指针域移动,就是按逆时针方向遍历凸包的界。从y坐标最小的点开始,是因为这个点肯定在凸包上。 现在分析步骤3)的时间复杂度。在 for 循环中,每次检查一个角之后,或者顶点 rx 被删除,x在链表中后移一个位置,或者x前移一个位置。由于被删除的顶点数为 O(n),x 最多向后移动O(n)个位置。因此第二种情形只会发生O(n)次,因而 for 循环将执行 O(n)次。因为检查一个夹角需要耗时Θ(1),所以步骤3)的复杂度为 O(n)。结果,为了找到n个点的凸包,需要耗时 O(nlogn)。   算法补充说明: 1)   令u、v、w是平面上的三个点。假设这三点不在同一直线上。编写一个方法,从这三个点所构成的三角形中取一个点。 2)
最新发布
03-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值