OpenCASCADE 平面求交

eryar@163.com

OpenCASCADE提供了类IntAna_QuadQuadGeo用来计算两个二次曲面quadric(球面、圆柱面、圆锥面及平面,平面是二次曲面的特例)之间的交线。他们之间可能的结果有:

l 一个点

l 一条或两条直线

l 一个点和一条直线

l 圆

l 椭圆

l 抛物线

l 双曲线

将源码结合《高等数学》、《解析几何》等书,可以来学习如何将理论付诸实践。本文主要介绍这个类中两个平面求交的源码实现。从源码中也可以看出OpenCASCADE官方开发人员的编码习惯。

将源码列出如下:

void IntAna_QuadQuadGeo::Perform (const gp_Pln& P1,
const gp_Pln& P2,
const Standard_Real TolAng,
const Standard_Real Tol)
{
Standard_Real A1, B1, C1, D1, A2, B2, C2, D2, dist1, dist2, aMVD;
//
done=Standard_False;
param2bis=.;
//
P1.Coefficients(A1,B1,C1,D1);
P2.Coefficients(A2,B2,C2,D2);
//
gp_Vec aVN1(A1,B1,C1);
gp_Vec aVN2(A2,B2,C2);
gp_Vec vd(aVN1.Crossed(aVN2));
//
const gp_Pnt& aLocP1=P1.Location();
const gp_Pnt& aLocP2=P2.Location();
//
dist1=A2*aLocP1.X() + B2*aLocP1.Y() + C2*aLocP1.Z() + D2;
dist2=A1*aLocP2.X() + B1*aLocP2.Y() + C1*aLocP2.Z() + D1;
//
aMVD=vd.Magnitude();
if(aMVD <=TolAng) {
// normalles are collinear - planes are same or parallel
typeres = (Abs(dist1) <= Tol && Abs(dist2) <= Tol) ? IntAna_Same
: IntAna_Empty;
}
else {
Standard_Real denom, denom2, ddenom, par1, par2;
Standard_Real X1, Y1, Z1, X2, Y2, Z2, aEps;
//
aEps=.e-;
denom=A1*A2 + B1*B2 + C1*C2;
denom2 = denom*denom;
ddenom = . - denom2; denom = ( Abs(ddenom) <= aEps ) ? aEps : ddenom; par1 = dist1/denom;
par2 = -dist2/denom; gp_Vec inter1(aVN1.Crossed(vd));
gp_Vec inter2(aVN2.Crossed(vd)); X1=aLocP1.X() + par1*inter1.X();
Y1=aLocP1.Y() + par1*inter1.Y();
Z1=aLocP1.Z() + par1*inter1.Z();
X2=aLocP2.X() + par2*inter2.X();
Y2=aLocP2.Y() + par2*inter2.Y();
Z2=aLocP2.Z() + par2*inter2.Z(); pt1=gp_Pnt((X1+X2)*0.5, (Y1+Y2)*0.5, (Z1+Z2)*0.5);
dir1 = gp_Dir(vd);
typeres = IntAna_Line;
nbint = ;
//
//-------------------------------------------------------
// When the value of the angle between the planes is small
// the origin of intersection line is computed with error
// [ ~0.0001 ] that can not br considered as small one
// e.g.
// for {A~=2.e-6, dist1=4.2e-5, dist2==1.e-4} =>
// {denom=3.4e-12, par1=12550297.6, par2=32605552.9, etc}
// So,
// the origin should be refined if it is possible
//
Standard_Real aTreshAng, aTreshDist;
//
aTreshAng=.e-; // 1.e-4 deg
aTreshDist=.e-;
//
if (aMVD < aTreshAng) {
Standard_Real aDist1, aDist2;
//
aDist1=A1*pt1.X() + B1*pt1.Y() + C1*pt1.Z() + D1;
aDist2=A2*pt1.X() + B2*pt1.Y() + C2*pt1.Z() + D2;
//
if (fabs(aDist1)>aTreshDist || fabs(aDist2)>aTreshDist) {
Standard_Boolean bIsDone, bIsParallel;
IntAna_IntConicQuad aICQ;
//
// 1.
gp_Dir aDN1(aVN1);
gp_Lin aL1(pt1, aDN1);
//
aICQ.Perform(aL1, P1, TolAng, Tol);
bIsDone=aICQ.IsDone();
if (!bIsDone) {
return;
}
//
const gp_Pnt& aPnt1=aICQ.Point();
//----------------------------------
// 2.
gp_Dir aDL2(dir1.Crossed(aDN1));
gp_Lin aL2(aPnt1, aDL2);
//
aICQ.Perform(aL2, P2, TolAng, Tol);
bIsDone=aICQ.IsDone();
if (!bIsDone) {
return;
}
//
bIsParallel=aICQ.IsParallel();
if (bIsParallel) {
return;
}
//
const gp_Pnt& aPnt2=aICQ.Point();
//
pt1=aPnt2;
}
}
}
done=Standard_True;
}

要理解这个源码,需要知道平面的一般方程:Ax+By+Cz+D=0,两个平面之间的夹角等概念。通过源码,可以看出计算两个平面之间的交线的步骤如下:

l 获取两个平面的一般方程的系数:A、B、C、D,其中平面的法向量(A,B,C)为单位向量;

l 将两个平面的法向量叉乘得到的向量vd为平面交线的方向;

l 分别计算一个平面上的点到另外一个平面的距离:dist1和dist2;

l 如果向量vd的大小小于指定的精度TolAng,则认为两个平面平行没有交线;如果两个距离dist1和dist2小于指定的精度Tol,则认为两个平面是相同的(重合);

l 计算两个平面的夹角denom;

l 根据两个平面的夹角计算交线上的点;

l 后面是处理两个平面夹角很小的情况;

l 最后得到交线上的点pt1和方向dir1

其实上面求交线上点的代码不好理解,可以换成三个平面求交点的处理更好理解,如将交线的方向作为法向得到的一个平面与那两个平面一起计算交点,这个交点就一定在交线上,相关代码如下:

gp_Pln P3(vd.X(), vd.Y(), vd.Z(), 0.0);

IntAna_Int3Pln aTool(P1, P2, P3);
if (aTool.IsDone())
{
pt1 = aTool.Value();
}

因为三个平面求交点是用高斯消元法解三元一次方程组,性能没有上面的代码好。生活中到处都是选择题,如何抉择是个问题啊。

OpenCASCADE 平面求交的更多相关文章

  1. OpenCASCADE直线与平面求交

    OpenCASCADE直线与平面求交 在<解析几何>相关的书中都给出了直线和平面的一般方程和参数方程.其中直线的一般方程有点向式形式的. 由于过空间一点可作且只能作一条直线平行于已知直线, ...

  2. OpenCASCADE圆与平面求交

    OpenCASCADE圆与平面求交 eryar@163.com 在 解析几何求交之圆与二次曲面中分析了OpenCASCADE提供的类IntAna_IntConicQuad可以用来计算圆与二次曲面之间的 ...

  3. 一步一步实现基于GPU的pathtracer(二):求交算法

    不管是哪种全局光照算法,最根本的都要落实到光线与物体的求交.主要分为光线与参数曲面和非参数曲面的求交,典型的参数曲面有球.盒.圆柱等基本体及基本体的组合体,以及一些更为复杂的参数曲面.非参数曲面就是所 ...

  4. OpenCASCADE 平面与球面求交

    OpenCASCADE 平面与球面求交 eryar@163.com OpenCASCADE提供了类IntAna_QuadQuadGeo用来计算两个二次曲面quadric(球面.圆柱面.圆锥面及平面,平 ...

  5. 光线求交-面、三角形、球 (Ray intersection)

    光线求交 光线定义:position \(a(t)\) = \(o\) + \(t\vec{d}\); 球定义: center p, radius r; 平面定义:normal \(\vec{n}\) ...

  6. ray与triangle/quad求交二三事

    引擎中,ray与quad求交,算法未细看,但有求解二次方程,不解.ray与triangle求交,使用的是97年经典算法,仔细看过论文,多谢小武同学指点,用到了克拉默法则求解线性方程组.想模仿该方法,做 ...

  7. [NetTopologySuite](2)任意多边形求交

    任意多边形求交: private void btnPolygon_Click(object sender, EventArgs e) { , , , , , , , , , , , , , }; , ...

  8. HDU - 3982:Harry Potter and J.K.Rowling(半平面交+圆与多边形求交)(WA ing)

    pro:给定一枚蛋糕,蛋糕上某个位置有个草莓,寿星在上面切了N刀,最后寿星会吃含有草莓的那一块蛋糕,问他的蛋糕占总蛋糕的面积比. sol:显然需要半平面交求含有蛋糕的那一块,然后有圆弧,不太方便求交. ...

  9. hdu 5111 树上求交

    hdu 5111 树上求交(树链剖分 + 主席树) 题意: 给出两棵树,大小分别为\(n1\),\(n2\), 树上的结点权值为\(weight_i\) 同一棵树上的结点权值各不相同,不同树上的结点权 ...

随机推荐

  1. 9.ActiveMQ理论

    一.首先说下什么是消息队列? 1.消息队列是在消息的传输过程中保存消息的容器. 二.为什么要用到消息队列? 主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的inse ...

  2. el-dialog(点击左上角的关闭x)执行弹窗关闭之前的回调

    绑定的事件: :before-close="handleDialogClose" html: <!-- 新增.编辑弹窗 --> <el-dialog :close ...

  3. 清空资源管理器访问过FTP的账号、密码

    修改注册表,删除HKEY_CURRENT_USER\SOFTWARE\Microsoft\FTP\Accounts下相对应的项即可,即为xxx.xxx.xxx.xxx项. 如下图所示:

  4. PHP 添加 跨域头

    我将下面的代码,放在Codeigniter 项目中的index.php 中的 header('Access-Control-Allow-Origin: *'); header('Access-Cont ...

  5. code+第四次网络赛div2

    T1 组合数问题: 用k个不完全相同的组合数表示一个数n. 用k-1个1和一个n-k+1表示即可. #include<cstdio> using namespace std; int x, ...

  6. LR调试脚本的时候报错Error -27796:(已解决)

    LR调试bbs脚本的时候报错: 1.Error -27796: Failed to connect to server "192.168.211.128:80": [10060] ...

  7. leetcode-210-课程表②

    题目描述: 第一次提交: class Solution: def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -& ...

  8. gevent实现并发

    #_author:来童星#date:2019/12/12import geventimport timedef func1(): print('\033[31;1mfun1 starting...\0 ...

  9. 剑指Offer-16:合并两个有序链表

    题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 例如A链表为1-3-5-7,B链表为2-4-6-8.所以合并后的新链表C为1-2-3-4-5- ...

  10. luoguP2398 GCD SUM [gcd]

    题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 给出n求sum. gcd(x,y)表示x,y的最大公约数. 输入输出格式 输入格式: n 输出格式: sum ...