导航:首页 > 编程语言 > 线段求交算法程序

线段求交算法程序

发布时间:2023-05-27 17:02:07

① 空间线段对求交算法

下面先介绍一种空间线段对求交算法:

图埋碰罩6.5 界线相交特性

三维地质建模方法及程序实现

空间两条线段的求交运算是三维地质建模中使用频率最高、算法最简单,同时也是最容易出现计算误差,并导致后续建模失败的数值运算之一。导致计算失败的主要原因是计算精度与浮点数问题。例如,有3条线段,两两之间的交点距离非常近但不重合,如果保持3个交点弯闹不变就会降低后续建模中曲面网格的质量;如果降低精度要求,将3个交点合并成一点,就会影响与其他线段的相交关系。另外,浮点数问题在线段平吵亮行判断、三点共线判断、四点共面判断都会遇到。在处理这类问题时,可以采用一个原则,即先精后粗,也就是说在线段对求交时尽量精确,等所有线段对求交结束后可以对距离很近的点进行合并处理。

② 谈谈"求线段交点"的几种算法

求线段交点 是一种非常基础的几何计算 在很多游戏中都会被使用到

下面我就现学现卖的把最近才学会的一些 求线段交点 的算法说一说 希望对大家有所帮助

本文讲的内容都很初级 主要是面向和我一样的初学者 所以请各位算法帝们轻拍啊 嘎嘎

引用已知线段 (a b) 和线段 (c d) 其中a b c d为端点 求线段交点p (平行或共线视作不相交)

算法一 求两条线段所在直线的交点 再判断交点是否在两条线段上

求直线交点时 我们可通过直线的一般方程 ax+by+c= 求得(方程中的abc为系数 不是前面提到的端点 另外也可用点斜式方程和斜截式方程 此处暂且不论)

然后根据交点的与线段端点的位置关系来判断交点是否在线段上 公式如下图

【责编:at 】

算法二 判断每一条线段的两个端点是否都在另一条线段的两侧 是则求出两条线段所在直线的交点 否则不相交

第一步判断两个点是否在某条线段的两侧 通常可采用投影法

求出线段的法线向量 然后把点投影到法线上 最后根据投影的位置来判断点和线段的关系 见下图

点a和点b在线段cd法线上的投影如图所示 这时候我们还要做一次线段cd在自己法线上的投影(选择点c或点d中的一个即可)

主要用来做参考

图中点a投影和点b投影在点c投影的两侧 说明线段ab的端点在线段cd的两侧

同理 再判断一次cd是否在线段ab两侧即可

求法线 求投影 什么的听起来很复杂的样子 实际上对于我来说也确实挺复杂 在几个月前我也不会(念书那会儿的几何知识都忘光了 ( ) 不过好在学习和实现起来还不算复杂 皆有公式可循

求线段ab的法线

JavaScript Code复制内容到剪贴板var nx=b y a y ny=a x b x var normalLine = { x nx y ny } 注意 其中 normalLine x和normalLine y的几何意义表示法线的方向 而不是坐标

求点c在法线上的投影位置

JavaScript Code复制内容到剪贴板var dist= normalLine x*c x + normalLine y*c y

注意 这里的 投影位置 是一个标量 表示的是到法线原点的距离 而不是投影点的坐标

通常知道这个渣耐郑距离就足够了

当我们把图中 点a投影(distA) 点b投影(distB) 点c投影(distC) 都求出来之后 就可以很容易的根据各自的大小判断出相对位置

distA==distB==distC 时 两条线段共线distA==distB!=distC 时 两条线段平行distA 和 distB 在distC 同侧时 两条线段不相交

distA 和 distB 在distC 异侧时 两条线段是否相交需要再判断点c点d与线段ab的关系

前面的那些步骤 只是实现了 判断线段是否相交 当结果为true时 我们还需要进一步求交点

求交点的过程后面再说 先看一下该算法的完整实现

JavaScript Code复制内容到剪贴板function segmentsIntr(a b c d){

//线段ab的法线N var nx = (b y a y) ny = (a x b x)

//线段cd的法线N var nx = (d y c y) ny = (c x d x)

亩蚂//两条法线做叉乘 如果结果为 说明线段ab和线段cd平行或共线 不相如颂交var denominator = nx *ny ny *nx if (denominator== ) { return false }

//在法线N 上的投影var distC_N =nx * c x + ny * c y var distA_N =nx * a x + ny * a y distC_N var distB_N =nx * b x + ny * b y distC_N

// 点a投影和点b投影在点c投影同侧 (对点在线段上的情况 本例当作不相交处理) if ( distA_N *distB_N >= ) { return false }

// //判断点c点d 和线段ab的关系 原理同上// //在法线N 上的投影var distA_N =nx * a x + ny * a y var distC_N =nx * c x + ny * c y distA_N var distD_N =nx * d x + ny * d y distA_N if ( distC_N *distD_N >= ) { return false }

//计算交点坐标var fraction= distA_N / denominator var dx= fraction * ny dy= fraction * nx return { x a x + dx y a y + dy } }

最后 求交点坐标的部分 所用的方法看起来有点奇怪 有种摸不著头脑的感觉

其实它和算法一 里面的算法是类似的 只是里面的很多计算项已经被提前计算好了

换句话说 算法二里求交点坐标的部分 其实也是用的直线的线性方程组来做的

现在来简单粗略 很不科学的对比一下算法一和算法二 最好情况下 两种算法的复杂度相同 最坏情况 算法一和算法二的计算量差不多 但是算法二提供了 更多的 提前结束条件 所以平均情况下 应该算法二更优

实际测试下来 实际情况也确实如此

【责编:at 】

算法三 判断每一条线段的两个端点是否都在另一条线段的两侧 是则求出两条线段所在直线的交点 否则不相交

(咦? 怎么感觉和算法二一样啊? 不要怀疑 确实一样 …… 囧)

所谓算法三 其实只是对算法二的一个改良 改良的地方主要就是 不通过法线投影来判断点和线段的位置关系 而是通过点和线段构成的三角形面积来判断

先来复习下三角形面积公式 已知三角形三点a(x y) b(x y) c(x y) 三角形面积为

JavaScript Code复制内容到剪贴板var triArea=( (a x c x) * (b y c y) (a y c y) * (b x c x) ) /

因为 两向量叉乘==两向量构成的平行四边形(以两向量为邻边)的面积 所以上面的公式也不难理解

而且由于向量是有方向的 所以面积也是有方向的 通常我们以逆时针为正 顺时针为负数

改良算法关键点就是 如果 线段ab和点c构成的三角形面积 与 线段ab和点d构成的三角形面积 构成的三角形面积的正负符号相异 那么点c和点d位于线段ab两侧 如下图所示

【责编:at 】 lishixin/Article/program/Java/Javascript/201311/25424

③ 求助,两条三维直线求交点的算法,最好有C++

这里假设是点向式,给定直线上一点(x1,y1,z1)和向量(m1,n1,p1)确定一条直线
对于两条直线,就是求方程组:
[m1m2|x1-x2]
[n1n2|y1-y2]
[p1p2|z1-z2]
的解。
如果有解(t1,t2),那么(x1+m1*t1,y1+n1*t1,z1+p1*t1)就是一个交点
求解线性方程组有很多方法,这里因为只有三个方程,可以直接明行蠢用克莱默法则解
#include<iostream>
std::pair<double,double>dd(doublea,doubleb,
doublec,doubled,doublem,doublen);
voidmain(){
doublem1,n1,p1,x1,y1,z1;
doublem2,n2,p2,x2,y2,z2;
std::cin激陪>>m1>>n1>>p1>>x1>>y1>>z1;
std::cin>>m2>>n2>>p2>>x2>>y2>>z2;
std::pair<double,double>answer;
constdoubleepsilon=1E-2;
//求解直线(x-x1)/m1=(y-y1)/n1=(z-z1)/p1和(x-x2)/m2=(y-y2)/n2=(z-z2)/p2的交点
if(fabs(m2*n2-n1*m2)<epsilon&&fabs(m1*p2-p1*m2)<epsilon){
if(fabs(m1*(y1-y2)-n1*(x1-x2))<epsilon&&fabs(m1*(z1-z2)-p1*(x1-x2))<epsilon)
std::cout<<"直线平行完全重合"<<std::endl;
else
std::cout<<"直线平行不相交"<<std::endl;
}
elseif(fabs(m1*n2-n1*m2)>epsilon){
answer=dd(m1,n1,m2,n2,x1-x2,y1-y2);
if(p1*answer.first+p2*answer.second-(z1-z2)<epsilon){
std::cout<<answer.first<<" "<<answer.second<<std::endl;
std::cout<<"找到!x="<<x1+m1*answer.first<<"y="<<y1+n1*answer.second<<std::endl;
}
elsestd::cout<<"无解"<<std::endl;
}
elseif(fabs(m1*p2-p1*m2)>epsilon){
answer=dd(m1,p1,m2,p2,x1-x2,z1-z2);
if(fabs(n1*answer.first+n2*answer.second-(z1-z2))<epsilon){
std::cout<<"找到!x="<<x1+m1*answer.first<<"y="<<y1+n1*answer.second<<std::endl;
}
elsestd::cout<<"无解"<<std::endl;
}
elsestd::cout<<"出错"<<std::endl;
}
std::pair<double,double>dd(doublea,doubleb,
doublec,doubled,doublem,doublen){
returnstd::pair<带陵double,double>((m*d-c*n)/(a*d-c*b),(a*n-b*m)/(a*d-c*b));
}

④ 界线的求交算法

当需要进行求交运算的界腔拆线较少,且每条界线上的线段也不多时,逐一对分别来自两条界线上的线段进行求交运算是可行的。但是,当界线很多时,这种求交方法将花费大量计算时间,效率十分低下。为此,本书将介绍一种算法:先利用网格定位,尽可能排除不可能相交的线段对,然后逐一对可能相交的线段对进行求交运算。该方法的具体步骤如下:

(1)确定界线矩形包围盒。将所有界线上的所有结点按坐标进行排耐山序,找到最小与最大的三维坐标(xmin,ymin,zmin)与(xmax,ymax,zmax),作为矩形包围盒的角点坐标。

(2)矩形包围盒的网格划分。以一定的间距,将包围盒划分成规则六面体格网,3个方向的间距可以不同,也可以相同。

(3)界线的网格定位,即确定每条界线上的每条线段与哪些网格单元相交,并将与某个网格单元相交的线段记录在该单元的相交线段集上。线段与网格单元的相交判断可以根据线段的端点坐标直接定位。

(4)组建可能相交的线段对。在每个格网单元中,将来自不同界线的线段进行组对,并删除重复昌圆中出现的线段对。

(5)线段对求交运算。

(6)结点的统一编排。将原有界线上的结点、界线的交点按坐标进行统一排序,按一定的阈值合并距离很近的结点,然后重新设置界线与新结点集中结点的关系。

(7)简单弧的划分。将每条界线划分成若干简单弧,保证每条简单弧是唯一的,并且确保简单弧上除端点以外的内部点不被其他简单弧共享。简单弧划分方法见第7章线框架生成方法。

⑤ C语言编写函数实现求两个线段的交点(定义一个函数而不是直接写求解的程序)

欲求二函数交点,必手悔须有二函数的代数表达局弊式,毕腊正或者必须有两条线段的端点坐标,否则,不可能得到线段的交点。

⑥ 求任意两线段交点

1.先建个坐标系,再在坐标上找两条线段经过的共同点就可以了。
2.至于如何找共同点,先要确定两条线段所在直线的函数,然后求交点,求不出交点简高就没有线段交点。
3.求出了线段交点还要看改点的自变量此拦和因变量在不在定义域和拦扒尺值域范围内。若在,就有交点;若有一条件不满足,就没有交点。

⑦ 用c语言 求点到线段垂线的交点,怎么求

设线段两点是 (x1,y1)(x2,y2),另外一个点是(x3,y3),那尘尺哪么他的方向向量就是 (a,b)=(x2-x1,y2-y1),那么他的垂线段的方向向量就是 (-b,a); 那么垂线的方程困消l就是就是 (x-x3)/(-b)=(y-y3)/a,l上的点就是x=t*(-b)+x3,y=a*t+y3,把(x,y)代入线段方程就可以求出t;
#include<stdio.h>派码

struct point
{
double x,y;
point(double _x,double _y):
x(_x),y(_y){}
};
struct Line
{
double x,y;
point a;
Line(double _x,double _y,point _a):
x(_x),y(_y),a(_a){}

};

int main()
{
double x,y;
printf("输入线段两点\n");
scanf("%lf%lf",&x,&y);point a=point(x,y);
scanf("%lf%lf",&x,&y);point b=point(x,y);
printf("输入线段外一点\n");
scanf("%lf%lf",&x,&y);point c=point(x,y);

Line l=Line(a.x-b.x,a.y-b.y,a);
Line l1=Line(b.y-a.y,a.x-b.x,c);

//ansx=(b.y-a.y)*t+c.x;ansy=(a.x-b.x)*t+c.y

//(ansx-a.x)/(a.x-b.x)=(ansy-a.y)/(a.y-b.y)

double t=((c.y-a.y)*(a.x-b.x)-(c.x-a.x)*(a.y-b.y))/((a.y-b.y)*(b.y-a.y)-(a.x-b.x)*(a.x-b.x));
if(t>1||t<0) puts("不存在");
else
{
double ansx=(b.y-a.y)*t+c.x;
double ansy=(a.x-b.x)*t+c.y;

printf("%lf %lf\n",ansx,ansy);
}
}

阅读全文

与线段求交算法程序相关的资料

热点内容
iphone来电壁纸 浏览:40
删除文件夹找不到指定路径怎么办 浏览:487
原力大数据招聘 浏览:479
数据线圆头什么意思 浏览:768
协和app怎么取号 浏览:664
c坐标转换代码 浏览:707
唐筛数据为什么能看出男女 浏览:44
快手java 浏览:835
qq分享的文件在哪里 浏览:226
爱念电影 浏览:656
97不用下载播放器的 浏览:649
在线观看0855影视 浏览:489
女主叫向晚棠的小说 浏览:841
uglifyjs使用 浏览:328
西班牙最大寸度电影 浏览:641
孤寂之狼txt无删笔趣阁 浏览:895
微程序微指令微操作机器指令 浏览:370
百合小说下载 浏览:477
iphone7怎么新建文件夹 浏览:339
如何用复印机打印u盘文件 浏览:377

友情链接