COMPASSi/trunk/code/projects/OCC/OCCLib/ScBRepLib.cpp

783 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Stdafx.h"
#include <vector>
#include <algorithm>
#include <TopExp.hxx>
#include <Precision.hxx>
#include <ShapeAlgo.hxx>
#include <BRepTools.hxx>
//#include <Bnd_SeqOfBox.hxx>
#include <BRepBndLib.hxx>
#include <BRepExtrema_DistShapeShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <ShapeAlgo.hxx>
#include <TopTools_SequenceOfShape.hxx>
#include <TopTools_DataMapOfShapeListOfShape.hxx>
#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
#include <ShapeAlgo_AlgoContainer.hxx>
#include <BRepBuilderAPI_FindPlane.hxx>
#include <BRepTopAdaptor_FClass2d.hxx>
#include "ScBRepLib.h"
ScBRepLib::ScBRepLib(void)
{
}
ScBRepLib::~ScBRepLib(void)
{
}
//辅助函数
BOOL ScBRepLib::IsVertex(const TopoDS_Shape& aS)
{
return (!aS.IsNull() && (aS.ShapeType() == TopAbs_VERTEX));
}
BOOL ScBRepLib::IsEdge(const TopoDS_Shape& aS)
{
return (!aS.IsNull() && (aS.ShapeType() == TopAbs_EDGE));
}
BOOL ScBRepLib::IsWire(const TopoDS_Shape& aS)
{
return (!aS.IsNull() && (aS.ShapeType() == TopAbs_WIRE));
}
BOOL ScBRepLib::IsFace(const TopoDS_Shape& aS)
{
return (!aS.IsNull() && (aS.ShapeType() == TopAbs_FACE));
}
BOOL ScBRepLib::IsShell(const TopoDS_Shape& aS)
{
return (!aS.IsNull() && (aS.ShapeType() == TopAbs_SHELL));
}
BOOL ScBRepLib::IsSolid(const TopoDS_Shape& aS)
{
return (!aS.IsNull() && (aS.ShapeType() == TopAbs_SOLID));
}
BOOL ScBRepLib::IsCompound(const TopoDS_Shape& aS)
{
return (!aS.IsNull() && (aS.ShapeType() == TopAbs_COMPOUND));
}
BOOL ScBRepLib::IsCompSolid(const TopoDS_Shape& aS)
{
return (!aS.IsNull() && (aS.ShapeType() == TopAbs_COMPSOLID));
}
//将一条edge分割为两条
BOOL ScBRepLib::SplitEdge(const TopoDS_Edge& aEdge,double t,
TopoDS_Edge& aE1,TopoDS_Edge& aE2)
{
if(aEdge.IsNull())
return FALSE;
double df,dl;
Handle(Geom_Curve) aCur = BRep_Tool::Curve(aEdge,df,dl);
if(aCur.IsNull())
return FALSE;
if(df > dl)
{
double tmp = df;dl = df;df = tmp;
}
double dtol = 1e-6;
if(t - dtol < df || t + dtol > dl)
{
return FALSE;
}
//创建两个新的edge
try
{
aE1 = BRepBuilderAPI_MakeEdge(aCur,df,t);
aE2 = BRepBuilderAPI_MakeEdge(aCur,t,dl);
if(aE1.IsNull() || aE2.IsNull())
return FALSE;
}
catch (Standard_Failure)
{
return FALSE;
}
return TRUE;
}
//用一条edge分割另一条edge,新edge保存在list中返回新edge的个数
int ScBRepLib::SplitEdgeByEdge(const TopoDS_Edge& aE1,const TopoDS_Edge& aE2,
TopTools_ListOfShape& shapeList)
{
int nC = 0;
std::vector<double> arpars;//交点参数列表
//为每段生成一个新的edge。
double df,dl;
Handle(Geom_Curve) aCur = BRep_Tool::Curve(aE1,df,dl);
if(aCur.IsNull())
return FALSE;
if(df > dl)
{
double tmp = df;dl = df;df = tmp;
}
//求交
BRepExtrema_DistShapeShape dss(aE1,aE2);
try{
dss.Perform();
}catch(Standard_Failure){
return 0;
}
nC = dss.NbSolution();
if(nC == 0)
return 0;
arpars.push_back(df);
int iC = 0;
gp_Pnt p1,p2;
//依次获取参数
for(int ix = 1;ix <= nC;ix ++)
{
double t ;
if(dss.SupportTypeShape1(ix) == BRepExtrema_IsOnEdge)
{
//要判断一下距离
p1 = dss.PointOnShape1(ix);
p2 = dss.PointOnShape2(ix);
if(p1.Distance(p2) < Precision::Confusion())
{
dss.ParOnEdgeS1(ix,t);
arpars.push_back(t);
iC ++;
}
else
{
//DTRACE("\n extrema point,not interpnt");
}
}
}
arpars.push_back(dl);
if(iC == 0)
return 0;
//排序
std::sort(arpars.begin(),arpars.end());
//为没对参数间生成一个edge
double t1,t2;
TopoDS_Edge aNE;
nC = 0;
for(int ix = 0;ix < arpars.size() - 1;ix ++)
{
t1 = arpars.at(ix);
t2 = arpars.at(ix + 1);
if(fabs(t1 - t2) < 1e-6)
continue;
aNE = BRepBuilderAPI_MakeEdge(aCur,t1,t2);
if(!aNE.IsNull())
{
//注意方向保证新分割edge的顺序和edge的方向一致
if(aE1.Orientation() == TopAbs_FORWARD)
shapeList.Append(aNE);
else
shapeList.Prepend(aNE);
nC ++;
}
}
return nC;
}
//用一条edge分割一个wire。新shape保存在list中返回新shape的个数
int ScBRepLib::SplitWireByEdge(const TopoDS_Wire& aWire,const TopoDS_Edge& aEdge,
TopTools_ListOfShape& shapeList)
{
if(aWire.IsNull() || aEdge.IsNull())
return 0;
int nC = 0,iC = 0,nNewC = 0;
TopTools_ListOfShape tmplist,wlist;
TopoDS_Wire aW;
TopExp_Explorer ex;
//依次剖分wire中的edge并进行必要的连接。
for(ex.Init(aWire,TopAbs_EDGE);ex.More();ex.Next())
{
TopoDS_Edge aE = TopoDS::Edge(ex.Current());
tmplist.Clear();
nC = ScBRepLib::SplitEdgeByEdge(aE,aEdge,tmplist);
if(nC == 0)//没有新的edge
{
wlist.Append(aE);
}
else
{
TopTools_ListIteratorOfListOfShape ll(wlist);
BRepBuilderAPI_MakeWire mw;
for(;ll.More();ll.Next())
mw.Add(TopoDS::Edge(ll.Value()));
wlist.Clear();
//从新分割edge中找到和aW相邻的edge并记录另一端的edge该edge
//和后续的edge相邻。
iC = 0;
TopTools_ListIteratorOfListOfShape ite(tmplist);
for(;ite.More();ite.Next())
{
if(iC == 0)
{
mw.Add(TopoDS::Edge(ite.Value()));
aW = mw.Wire();
if(!aW.IsNull())
{
nNewC ++;
shapeList.Append(aW);
}
}
else if(iC == nC - 1)
{
wlist.Append(ite.Value());
}
else
{
nNewC ++;
shapeList.Append(ite.Value());//新的edge
}
iC ++;
}//end for
}//end else
}//end for
if(wlist.Extent() > 0)
{
TopTools_ListIteratorOfListOfShape ll(wlist);
BRepBuilderAPI_MakeWire mw;
for(;ll.More();ll.Next())
mw.Add(TopoDS::Edge(ll.Value()));
TopoDS_Wire aW = mw.Wire();
if(!aW.IsNull())
{
nNewC ++;
shapeList.Append(aW);
}
}
return nNewC;
}
//用一条wire分割一个edge。
int ScBRepLib::SplitEdgeByWire(const TopoDS_Edge& aEdge,const TopoDS_Wire& aWire,
TopTools_ListOfShape& shapeList)
{
int nC = 0,iC;
std::vector<double> arpars;//交点参数列表
//为每段生成一个新的edge。
double df,dl;
Handle(Geom_Curve) aCur = BRep_Tool::Curve(aEdge,df,dl);
if(aCur.IsNull())
return FALSE;
if(df > dl)
{
double tmp = df;dl = df;df = tmp;
}
arpars.push_back(df);
double t;
gp_Pnt p1,p2;
TopExp_Explorer ex;
iC = 0;
for(ex.Init(aWire,TopAbs_EDGE);ex.More();ex.Next())
{
TopoDS_Edge aE = TopoDS::Edge(ex.Current());
//求交
BRepExtrema_DistShapeShape dss(aEdge,aE);
try{
dss.Perform();
}catch(Standard_Failure){
continue;
}
//获取交点
for(int ix = 1;ix <= dss.NbSolution();ix ++)
{
if(dss.SupportTypeShape1(ix) == BRepExtrema_IsOnEdge)
{
//要判断一下距离
p1 = dss.PointOnShape1(ix);
p2 = dss.PointOnShape2(ix);
if(p1.Distance(p2) < Precision::Confusion())
{
dss.ParOnEdgeS1(ix,t);
arpars.push_back(t);
iC ++;
}
else
{
//DTRACE("\n extrema point,not interpnt");
}
}
}
}
if(iC == 0)
return 0;//无交点
arpars.push_back(dl);
std::sort(arpars.begin(),arpars.end());
//生成新的edge
double t1,t2;
TopoDS_Edge aNE;
nC = 0;
for(int ix = 0;ix < arpars.size() - 1;ix ++)
{
t1 = arpars.at(ix);
t2 = arpars.at(ix + 1);
if(fabs(t1 - t2) < 1e-6)
continue;
aNE = BRepBuilderAPI_MakeEdge(aCur,t1,t2);
if(!aNE.IsNull())
{
//注意方向保证新分割edge的顺序和edge的方向一致
if(aEdge.Orientation() == TopAbs_FORWARD)
shapeList.Append(aNE);
else
shapeList.Prepend(aNE);
nC ++;
}
}
return nC;
}
//用一个wire分割另一个wire
int ScBRepLib::SplitWireByWire(const TopoDS_Wire& aW1,const TopoDS_Wire& aW2,
TopTools_ListOfShape& shapeList)
{
if(aW1.IsNull() || aW2.IsNull())
return 0;
int nC = 0,iC = 0,nNewC = 0;
TopTools_ListOfShape tmplist,wlist;
TopoDS_Wire aW;
TopExp_Explorer ex;
//依次剖分wire中的edge并进行必要的连接。
for(ex.Init(aW1,TopAbs_EDGE);ex.More();ex.Next())
{
TopoDS_Edge aE = TopoDS::Edge(ex.Current());
tmplist.Clear();
nC = ScBRepLib::SplitEdgeByWire(aE,aW2,tmplist);
if(nC == 0)//没有新的edge
{
wlist.Append(aE);
}
else
{
TopTools_ListIteratorOfListOfShape ll(wlist);
BRepBuilderAPI_MakeWire mw;
for(;ll.More();ll.Next())
mw.Add(TopoDS::Edge(ll.Value()));
wlist.Clear();
//从新分割edge中找到和aW相邻的edge并记录另一端的edge该edge
//和后续的edge相邻。
iC = 0;
TopTools_ListIteratorOfListOfShape ite(tmplist);
for(;ite.More();ite.Next())
{
if(iC == 0)
{
mw.Add(TopoDS::Edge(ite.Value()));
aW = mw.Wire();
if(!aW.IsNull())
{
nNewC ++;
shapeList.Append(aW);
}
}
else if(iC == nC - 1)
{
wlist.Append(ite.Value());
}
else
{
nNewC ++;
shapeList.Append(ite.Value());//新的edge
}
iC ++;
}//end for
}//end else
}//end for
if(wlist.Extent() > 0)
{
TopTools_ListIteratorOfListOfShape ll(wlist);
BRepBuilderAPI_MakeWire mw;
for(;ll.More();ll.Next())
mw.Add(TopoDS::Edge(ll.Value()));
TopoDS_Wire aW = mw.Wire();
if(!aW.IsNull())
{
nNewC ++;
shapeList.Append(aW);
}
}
return nNewC;
}
//edge和wire是否相连
BOOL ScBRepLib::IsConnected(const TopoDS_Wire& aW,const TopoDS_Edge& aE)
{
if(aW.IsNull() || aE.IsNull())
return FALSE;
TopoDS_Vertex v1,v2,v3,v4;
TopExp::Vertices(aE,v1,v2);
TopExp::Vertices(aW,v3,v4);
gp_Pnt p1,p2,p3,p4;
p1 = BRep_Tool::Pnt(v1);
p2 = BRep_Tool::Pnt(v2);
p3 = BRep_Tool::Pnt(v3);
p4 = BRep_Tool::Pnt(v4);
double dTol = Precision::Confusion();
if(p1.Distance(p3) < dTol || p1.Distance(p4) < dTol ||
p2.Distance(p3) < dTol || p2.Distance(p4) < dTol)
return TRUE;
return FALSE;
}
//使用BRepTools::OuterWire的代码略作修改。
TopoDS_Wire ScBRepLib::OuterWire(const TopoDS_Face& aFace)
{
TopoDS_Wire Wres;
TopExp_Explorer expw (aFace,TopAbs_WIRE);
BOOL bOverlap = FALSE;//是否包围盒相互覆盖
if (expw.More())
{
Wres = TopoDS::Wire(expw.Current());
expw.Next();
if (expw.More())
{
Standard_Real UMin, UMax, VMin, VMax;
Standard_Real umin, umax, vmin, vmax;
BRepTools::UVBounds(aFace,Wres,UMin,UMax,VMin,VMax);
while (expw.More())
{
const TopoDS_Wire& W = TopoDS::Wire(expw.Current());
BRepTools::UVBounds(aFace,W,umin, umax, vmin, vmax);
//如下简单判断范围可能不行例如一个大的外wire和一个小的wire当小环很
//贴近大环时,由于包围盒算法,可能导致两种包围盒重叠,导致错误的选择。
//下面算法适用于好的情况。
if ((umin <= UMin) &&
(umax >= UMax) &&
(vmin <= VMin) &&
(vmax >= VMax))
{//w包围盒包围了记录的包围盒。
Wres = W;
UMin = umin;
UMax = umax;
VMin = vmin;
VMax = vmax;
}
else
{
//判断是否重叠
if(umin > UMax || umax < UMin || vmin > VMax || vmax < VMin)
{//不可能重叠
}
else
{
//如果一个区间在另一个区间内则d1,d2应当异号。
double Ud1 = UMax - umax,Ud2 = UMin - umin;
double Vd1 = VMax - vmax,Vd2 = VMin - vmin;
if((Ud1 * Ud2 >= 0.0) && (Vd1 * Vd2 > 0.0) ||
(Ud1 * Ud2 > 0.0) && (Vd1 * Vd2 >= 0.0))
{
// DTRACE("\n wire overlap [%f,%f]*[%f,%f] ps [%f,%f]*[%f,%f]",
// umin,umax,vmin,vmax,UMin,UMax,VMin,VMax);
bOverlap = TRUE;
break;
}
}
}
expw.Next();
}
}
}
if(!bOverlap)
{
return Wres;
}
//重叠使用另一个算法
TopoDS_Wire aOWire;
try
{
aOWire = ShapeAlgo::AlgoContainer()->OuterWire(aFace);//Note:aFace 出现异常???
}
catch(Standard_Failure)
{
aOWire = Wres;//返回先前的。
}
return aOWire;
}
//根据一系列wire,创建平面face.wire不相交,可能相互包含.主要用于从文字轮廓
//生成一系列平面.
int ScBRepLib::BuildPlnFace(TopTools_ListOfShape& aWList,TopTools_ListOfShape& aFList)
{
int nFs = 0;
//先根据包围盒,判断是否相互包含.
NCollection_Sequence<Bnd_Box> seqBox;
//Bnd_SeqOfBox seqBox;
Bnd_Box bb;
TopTools_SequenceOfShape seqW,seqAlone;
TopTools_ListIteratorOfListOfShape its(aWList);
for(;its.More();its.Next())
{
TopoDS_Wire aW = TopoDS::Wire(its.Value());
BRepBndLib::Add(aW,bb);
seqBox.Append(bb);
seqW.Append(aW);
}
TopTools_DataMapOfShapeListOfShape mSS;//记录了包含关系,key的shape包含了list中的shape.
for(int ix = 1;ix <= seqW.Length();ix ++)
{
TopoDS_Wire aW1 = TopoDS::Wire(seqW.Value(ix));
const Bnd_Box& bb1 = seqBox.Value(ix);
BOOL bInter = FALSE;
for(int jx = 1;jx <= seqW.Length();jx ++)
{
if(ix == jx)
continue;
TopoDS_Wire aW2 = TopoDS::Wire(seqW.Value(jx));
const Bnd_Box& bb2 = seqBox.Value(jx);
if(bb1.IsOut(bb2) && bb2.IsOut(bb1))
{
continue;
}
else
{
//相交,判断两者的关系.先1后2,和先2后1.注意:包围盒相交甚至包含,但wire本身可能不相交
if(ScBRepLib::IsWire2InWire1(aW1,aW2))
{
if(!mSS.IsBound(aW1))
{
TopTools_ListOfShape aList;
mSS.Bind(aW1,aList);
}
BOOL bF = FALSE;
TopTools_ListIteratorOfListOfShape lit;
for(lit.Initialize(mSS.Find(aW1));lit.More();lit.Next())
{
if(aW2.IsEqual(lit.Value()))
{
bF = TRUE;
break;
}
}
if(!bF)
mSS.ChangeFind(aW1).Append(aW2);
bInter = TRUE;
}
else if(ScBRepLib::IsWire2InWire1(aW2,aW1))
{
if(!mSS.IsBound(aW2))
{
TopTools_ListOfShape aList;
mSS.Bind(aW2,aList);
}
BOOL bF = FALSE;
TopTools_ListIteratorOfListOfShape lit;
for(lit.Initialize(mSS.Find(aW2));lit.More();lit.Next())
{
if(aW1.IsEqual(lit.Value()))
{
bF = TRUE;
break;
}
}
if(!bF)
mSS.ChangeFind(aW2).Append(aW1);
bInter = TRUE;
}
else
{
continue;//包围盒相交,实际不相交
}
}
}
if(!bInter)//什么都不相交,独立的wire
{
seqAlone.Append(aW1);
}
}
//对相互包含的wire,判断相应关系,创建平面
TopTools_DataMapIteratorOfDataMapOfShapeListOfShape mapit;
for(mapit.Initialize(mSS);mapit.More();mapit.Next())
{
TopoDS_Wire aOW = TopoDS::Wire(mapit.Key());
const TopTools_ListOfShape& aList = mapit.Value();
//创建face
TopoDS_Face aF = ScBRepLib::BuildPlaneFace(aOW,aList);
if(!aF.IsNull())
{
aFList.Append(aF);
nFs ++;
}
}
//对独立的wire创建平面.
for(int ix = 1;ix <= seqAlone.Length();ix ++)
{
TopoDS_Wire aW = TopoDS::Wire(seqAlone.Value(ix));
BRepBuilderAPI_MakeFace MF(aW,Standard_True);
if(MF.IsDone())
{
TopoDS_Face aNF = MF.Face();
if(!aNF.IsNull())
{
aFList.Append(aNF);
nFs ++;
}
}
}
return nFs;
}
//wire 1是否包含wire2.
BOOL ScBRepLib::IsWire2InWire1(const TopoDS_Wire& aW1,const TopoDS_Wire& aW2)
{
BRepBuilderAPI_FindPlane fpln(aW1);
if(!fpln.Found())
return FALSE;
gp_Pln aPln = fpln.Plane()->Pln();
//构造face
BRepBuilderAPI_MakeFace mf(aPln,aW1);
if(!mf.IsDone())
return FALSE;
TopoDS_Face aNF = mf.Face();
//判断w2的一个点是否在mf上.
BOOL bIN = FALSE;
int nC = 0;
BRepTopAdaptor_FClass2d fcls(aNF,Precision::PConfusion());
TopExp_Explorer ex;
for(ex.Init(aW2,TopAbs_VERTEX);ex.More();ex.Next())
{
TopoDS_Vertex aV = TopoDS::Vertex(ex.Current());
gp_Pnt pnt = BRep_Tool::Pnt(aV);
GeomAPI_ProjectPointOnSurf pp(pnt,fpln.Plane());
if(pp.IsDone() && pp.NbPoints() > 0)
{
gp_Pnt2d uv;
double u,v;
pp.LowerDistanceParameters(u,v);
uv.SetCoord(u,v);
//验证是否在aW1内部
TopAbs_State sta = fcls.Perform(uv);
if(sta == TopAbs_IN)
{
bIN = TRUE;
break;
}
}
else
{
nC ++;
if(nC > 3)
break;
}
}
return bIN;
}
//从一个外环和一组内环创建face
TopoDS_Face ScBRepLib::BuildPlaneFace(const TopoDS_Wire& aOW,const TopTools_ListOfShape& aIWList)
{
TopoDS_Face aNF;
try{
//先使用外环创建一个平面
BRepBuilderAPI_MakeFace MF(aOW,Standard_True);
if(MF.IsDone())
{
aNF = MF.Face();
if(aNF.IsNull())
return aNF;
}
//下面依次对内环进行判断,主要是要保证环闭合,并且环的方向正确
BRep_Builder B;
TopTools_ListIteratorOfListOfShape lit;
for(lit.Initialize(aIWList);lit.More();lit.Next())
{
TopoDS_Wire aW = TopoDS::Wire(lit.Value());
if(aW.IsNull() || !BRep_Tool::IsClosed(aW))
{
//DTRACE("\n inner wire make null or not closed.");
continue;
}
//判断内环的方向
TopoDS_Shape aTS = aNF.EmptyCopied();
TopoDS_Face aTF = TopoDS::Face(aTS);
aTF.Orientation(TopAbs_FORWARD);
B.Add(aTF,aW);
BRepTopAdaptor_FClass2d fcls(aTF,Precision::PConfusion());
TopAbs_State sta = fcls.PerformInfinitePoint();
if(sta == TopAbs_OUT)
aW.Reverse();
MF.Add(aW);
}
//获取最终的face
aNF = MF.Face();
}catch(Standard_Failure){
return aNF;
}
return aNF;
}