布尔数据 点的相交
布尔数据 点的相交
1 Introduction
OpenCASCADE中将相交干涉分成两种类型,一种类型是边界表示数据中的点线面Vertex, Edge, Face包含几何和容差,在3D空间中距离在容差范围之内的BRep相交。包含几何数据的点线面就有6种类型的BRep相交(BRep interferences):
- Vertex/Vertex
- Vertex/Edge
- Vertex/Face
- Edge/Edge
- Edge/Face
- Face/Face
第二种类型是一个模型完全在一个Solid之内,这种相交称为非BRep的相交(Non-BRep interferences),有四种可能:
- Vertex/Solid
- Edge/Solid
- Face/Solid
- Solid/Solid
上面两种类型的相交总共为10种,在类BOPDS_DS中通过静态函数NbInterfTypes()返回。代码如下:
//=======================================================================
//function : NbInterfTypes
//purpose : Returns the number of types of the interferences
//=======================================================================
inline Standard_Integer BOPDS_DS::NbInterfTypes()
{
return 10;
}
在BOPDS_Tools中又重新对相交的类型进行编码。本文通过在DRAW中使用Tcl来对源码进行DEBUG,主要来探究一下对点Vertex的相交处理。
2 Vertex/Vertex interference
上图所示为文档中对点/点相交的描述,当两个点之间的距离在容差范围之内时,判定为相交。相交的结果会得到新的点Vertex,其坐标为考虑两个点的容差的一个球的中心,容差为球的半径。在DRAW中输入命令:
vertex v1 1 2 3
vertex v2 1 2 3
bop v1 v2
其中两点求交代码如下:
//=======================================================================
// function: ComputeVV
// purpose:
//=======================================================================
Standard_Integer BOPTools_AlgoTools::ComputeVV(const TopoDS_Vertex& aV1,
const TopoDS_Vertex& aV2,
const Standard_Real aFuzz)
{
Standard_Real aTolV1, aTolV2, aTolSum, aTolSum2, aD2;
gp_Pnt aP1, aP2;
Standard_Real aFuzz1 = (aFuzz > Precision::Confusion() ? aFuzz : Precision::Confusion());
//
aTolV1=BRep_Tool::Tolerance(aV1);
aTolV2=BRep_Tool::Tolerance(aV2);
aTolSum=aTolV1+aTolV2+aFuzz1;
aTolSum2=aTolSum*aTolSum;
//
aP1=BRep_Tool::Pnt(aV1);
aP2=BRep_Tool::Pnt(aV2);
//
aD2=aP1.SquareDistance(aP2);
if (aD2>aTolSum2) {
return 1;
}
return 0;
}
从代码中可以看出OCC中布尔模糊容差Fuzzy Tolerance的最高精度为Precision::Confusion()。根据相交结果生成新的点代码如下:
//=======================================================================
// function: MakeVertex
// purpose : Makes the vertex in the middle of given vertices with
// the tolerance covering all tolerance spheres of vertices.
//=======================================================================
void BOPTools_AlgoTools::MakeVertex(const TopTools_ListOfShape& aLV,
TopoDS_Vertex& aVnew)
{
Standard_Integer aNb = aLV.Extent();
if (aNb == 1)
aVnew=*((TopoDS_Vertex*)(&aLV.First()));
else if (aNb > 1)
{
Standard_Real aNTol;
gp_Pnt aNC;
BRepLib::BoundingVertex(aLV, aNC, aNTol);
BRep_Builder aBB;
aBB.MakeVertex(aVnew, aNC, aNTol);
}
}
算法实现与文档描述一致。相交结果除了新产生的点,还有这些产生这些结果的数据都保存到BOPDS_InterfVV中,代码如下:
if (theAddInterfs) {
if (myDS->AddInterf(n1, n2))
{
BOPDS_InterfVV& aVV = aVVs.Appended();
aVV.SetIndices(n1, n2);
aVV.SetIndexNew(nV);
}
}
其中BOPDS_InterfVV中保存了哪两个点相交的索引n1, n2及产生新的点的索引nV。
3 Vertex/Edge interference
对于点Vi和边Ej相交的条件为点Vi到边的投影距离小于点Tol(Vi),边Tol(Ej)的容差之和。在DRAW中输入命令如下:
vertex v1 0 0 0
vertex v2 6 0 0
vertex v 3 0 0
edge e v1 v2
bop e v
其中点与边相交的代码如下:
//=======================================================================
//function : ComputeVE
//purpose :
//=======================================================================
Standard_Integer IntTools_Context::ComputeVE
(const TopoDS_Vertex& theV,
const TopoDS_Edge& theE,
Standard_Real& theT,
Standard_Real& theTol,
const Standard_Real theFuzz)
{
if (BRep_Tool::Degenerated(theE)) {
return -1;
}
if (!BRep_Tool::IsGeometric(theE)) {
return -2;
}
Standard_Real aDist, aTolV, aTolE, aTolSum;
Standard_Integer aNbProj;
gp_Pnt aP;
//
aP=BRep_Tool::Pnt(theV);
//
GeomAPI_ProjectPointOnCurve& aProjector=ProjPC(theE);
aProjector.Perform(aP);
aNbProj=aProjector.NbPoints();
if (!aNbProj) {
return -3;
}
//
aDist=aProjector.LowerDistance();
//
aTolV=BRep_Tool::Tolerance(theV);
aTolE=BRep_Tool::Tolerance(theE);
aTolSum = aTolV + aTolE + Max(theFuzz, Precision::Confusion());
//
theTol = aDist + aTolE;
theT = aProjector.LowerDistanceParameter();
if (aDist > aTolSum) {
return -4;
}
return 0;
}
使用类GeomAPI_ProjectPointOnCurve来计算点到线的投影距离,当距离小于点Tol(V)和Tol(E)及模糊容差Fuzzy之和的认为是相交的。相交结果保存在BOPDS_InterfVE中,记录了点和边的索引及点在边上的参数。
这里面会引入两个新的概念:BOPDS_Pave和BOPDS_PaveBlock。其中PaveBlock中记录了边中所有的点的Pave,及边的索引。Pave中记录点的索引,在边上的参数。一个PaveBlock对应边上一小部分。
因为容差的原因还引入收缩范围Shrunk Range的概念,先记住这些概念看看后面如何使用这些数据。
4 Vertex/Face interference
点与面的相交也是通过点到面的投影距离来判定的。当然也可以用Tcl脚本来调试,这里留给同学们自己动手尝试一下。计算点与面相交的代码如下:
//=======================================================================
//function : ComputeVF
//purpose :
//=======================================================================
Standard_Integer IntTools_Context::ComputeVF
(const TopoDS_Vertex& theVertex,
const TopoDS_Face& theFace,
Standard_Real& theU,
Standard_Real& theV,
Standard_Real& theTol,
const Standard_Real theFuzz)
{
Standard_Real aTolV, aTolF, aTolSum, aDist;
gp_Pnt aP;
aP = BRep_Tool::Pnt(theVertex);
//
// 1. Check if the point is projectable on the surface
GeomAPI_ProjectPointOnSurf& aProjector=ProjPS(theFace);
aProjector.Perform(aP);
//
if (!aProjector.IsDone()) { // the point is not projectable on the surface
return -1;
}
//
// 2. Check the distance between the projection point and
// the original point
aDist = aProjector.LowerDistance();
//
aTolV = BRep_Tool::Tolerance(theVertex);
aTolF = BRep_Tool::Tolerance(theFace);
//
aTolSum = aTolV + aTolF + Max(theFuzz, Precision::Confusion());
theTol = aDist + aTolF;
aProjector.LowerDistanceParameters(theU, theV);
//
if (aDist > aTolSum) {
// the distance is too large
return -2;
}
//
gp_Pnt2d aP2d(theU, theV);
Standard_Boolean pri = IsPointInFace (theFace, aP2d);
if (!pri) {// the point lays on the surface but out of the face
return -3;
}
return 0;
}
使用类GeomAPI_ProjectPointOnSurf来计算点到面的投影距离,并使用定位器IntTools_FClass2d来判断点是否在有界的Face面上。将计算结果保存到BOPDS_InterfVF中,保存数据有点与面的索引和点在面的参数空间上的参数。还更新面的信息,将这些点的索引保存到VerticesIn中。
5 Conclusion
综上所述,在DRAW中使用脚本可以方便对相关代码进行DEBUG。通过点与点、边和面的相交代码实现可以看出在BOPDS中对于相交结果保存了哪些数据。及模糊容差Fuzzy Tolerance的作用和精度。通过引入Pave, PaveBlock, Shrunk Range来保存求交结果及容差处理。