OpenCASCADE Shape Location
eryar@163.com
Abstract. The TopLoc package of OpenCASCADE gives resources to handle 3D local coordinate systems called Locations. A Location is a composition of elementary coordinate systems, each one is called a Datum. The Location keeps track of this composition. The paper will use the Draw Test Harness to illustrate the Location concept.
Key Words. Transformation, Location, Local Coordinate Systems
1.Introduction
對(duì)于三維空間中的各種模型,總是想要擺放到合適的位置,最終形成一個(gè)工廠的模型,一艘船的模型,一個(gè)建筑物的模型,等等。目前來看,所有的幾何相關(guān)的庫對(duì)模型變換的實(shí)現(xiàn)一般都是使用了矩陣變換。有的可能只保留了最終變換的結(jié)果矩陣數(shù)據(jù),而OpenCASCADE的TopoDS_Shape中保留了Location信息。從其文檔可以看出,Location中保留了模型變換一系列的變換組合,并可以對(duì)這個(gè)變換進(jìn)行Track追蹤。如何來正確理解這個(gè)Location的意義呢?下面結(jié)合Draw Test Harness來進(jìn)行說明。
2.Draw Test
在Draw Test Harness中對(duì)模型進(jìn)行變換的命令有:ttranslate, trotate, tmove, reset, tmirror, tscale.其中ttranslate, trotate, tmove, reset命令只會(huì)對(duì)模型位置進(jìn)行調(diào)整,并不能讓模型發(fā)生變形,即是剛性變換。下面就通過對(duì)一個(gè)Box進(jìn)行移動(dòng)和旋轉(zhuǎn),來看看TopoDS_Shape中的Location是如何變化的。在Draw Test Harness中輸入以下命令:
pload ALL
box b 10 20 30
vdisplay b
vtrihedron vt
dump b
可以看到此時(shí)box的Location是沒有的:
Figure 2.1 Box Location in Original
當(dāng)將box沿X方向移動(dòng)一段距離后:
# translate by x direction
ttranslate b 10 0 0
vdisplay b
dump b
Figure 2.2 Location of the translation box
由上圖可知,當(dāng)對(duì)模型進(jìn)行變換后,TopoDS_Shape中即有了Location數(shù)據(jù),變換矩陣的平移部分(第4列數(shù)據(jù))發(fā)生了變化。下面繼續(xù)沿X軸方向移動(dòng)10:
# translate by x direction
ttranslate b 10 0 0
vdisplay b
dump b
Figure 2.3 Translate Box in X Direction
由圖2.3可知,模型現(xiàn)在的位置是通過兩個(gè)Elementary變換得來的。最后一個(gè)Complex變換是上述所有變換的復(fù)合。下面再對(duì)模型進(jìn)行繞Y軸旋轉(zhuǎn)45度:
# rotate by y axis
trotate b 0 0 0 0 1 0 45
vdisplay b
dump b
Figure 2.4 Rotate the Box
由上圖可知,經(jīng)過旋轉(zhuǎn)變換后的模型有了4個(gè)Location:三個(gè)基本變換和一個(gè)復(fù)合變換,復(fù)合變換是所有基本變換的組合。
通過上面的示例,已經(jīng)可以清晰理解OpenCASCADE中的Location的概念,雖然處理得有點(diǎn)復(fù)雜,通過Location可以對(duì)模型的變換軌跡有個(gè)詳細(xì)的跟蹤。這樣處理的好處就是對(duì)模型的變換過程進(jìn)行了記錄,可以方便地回到歷史上的任意一個(gè)時(shí)刻;不好的地方就是程序理解起來麻煩,而且還需要有額外的內(nèi)存來保存這些數(shù)據(jù)。
以下為上述所有Tcl腳本:
#
# test TopoDS_Shape location.
# Shing Liu(eryar@163.com)
# 2016-09-06 22:50
#
pload ALL
# initialize
box b 10 20 30
vdisplay b
vtrihedron vt
dump b
# translate by x direction
ttranslate b 10 0 0
vdisplay b
dump b
# translate by x direction
ttranslate b 10 0 0
vdisplay b
dump b
# rotate by y axis
trotate b 0 0 0 0 1 0 45
vdisplay b
dump b
3.Draw Code
每個(gè)Draw Test Harness命令都可以方便地找到其實(shí)現(xiàn)代碼,其中模型變換命令的實(shí)現(xiàn)代碼如下:
//=======================================================================
// transform
//=======================================================================
static Standard_Integer transform(Draw_Interpretor& ,Standard_Integer n,const char** a)
{
if (n <= 1) return 1;
gp_Trsf T;
Standard_Integer last = n;
const char* aName = a[0];
Standard_Boolean isBasic = Standard_False;
if (!strcmp(aName,"reset")) {
}
else {
isBasic = (aName[0] == 'b');
aName++;
if (!strcmp(aName,"move")) {
if (n < 3) return 1;
TopoDS_Shape SL = DBRep::Get(a[n-1]);
if (SL.IsNull()) return 0;
T = SL.Location().Transformation();
last = n-1;
}
else if (!strcmp(aName,"translate")) {
if (n < 5) return 1;
T.SetTranslation(gp_Vec(Draw::Atof(a[n-3]),Draw::Atof(a[n-2]),Draw::Atof(a[n-1])));
last = n-3;
}
else if (!strcmp(aName,"rotate")) {
if (n < 9) return 1;
T.SetRotation(gp_Ax1(gp_Pnt(Draw::Atof(a[n-7]),Draw::Atof(a[n-6]),Draw::Atof(a[n-5])),
gp_Vec(Draw::Atof(a[n-4]),Draw::Atof(a[n-3]),Draw::Atof(a[n-2]))),
Draw::Atof(a[n-1])* (M_PI / 180.0));
last = n-7;
}
else if (!strcmp(aName,"mirror")) {
if (n < 8) return 1;
T.SetMirror(gp_Ax2(gp_Pnt(Draw::Atof(a[n-6]),Draw::Atof(a[n-5]),Draw::Atof(a[n-4])),
gp_Vec(Draw::Atof(a[n-3]),Draw::Atof(a[n-2]),Draw::Atof(a[n-1]))));
last = n-6;
}
else if (!strcmp(aName,"scale")) {
if (n < 6) return 1;
T.SetScale(gp_Pnt(Draw::Atof(a[n-4]),Draw::Atof(a[n-3]),Draw::Atof(a[n-2])),Draw::Atof(a[n-1]));
last = n-4;
}
}
if (T.Form() == gp_Identity || isBasic) {
TopLoc_Location L(T);
for (Standard_Integer i = 1; i < last; i++) {
TopoDS_Shape S = DBRep::Get(a[i]);
if (S.IsNull())
{
std::cerr << "Error: " << a[i] << " is not a valid shape\n";
return 1;
}
else
DBRep::Set(a[i],S.Located(L));
}
}
else {
BRepBuilderAPI_Transform trf(T);
for (Standard_Integer i = 1; i < last; i++) {
TopoDS_Shape S = DBRep::Get(a[i]);
if (S.IsNull()) {
std::cerr << "Error: " << a[i] << " is not a valid shape\n";
return 1;
}
else {
trf.Perform(S);
if (!trf.IsDone())
return 1;
DBRep::Set(a[i],trf.Shape());
}
}
}
return 0;
}
對(duì)模型的變換主要使用類BRepBuilderAPI_Transform來完成。
4.Conclusion
通過上面的示例,已經(jīng)可以清晰理解OpenCASCADE中的Location的概念,雖然處理得有點(diǎn)復(fù)雜,通過Location可以對(duì)模型的變換軌跡有個(gè)詳細(xì)的跟蹤。這樣處理的好處就是對(duì)模型的變換過程進(jìn)行了記錄,可以方便地回到歷史上的任意一個(gè)時(shí)刻;不好的地方就是程序理解起來麻煩,而且還需要有額外的內(nèi)存來保存這些數(shù)據(jù)。
理解了Location的概念,也就理解了OpenCASCADE的Brep文件中的一項(xiàng)基本內(nèi)容,方便開發(fā)一些轉(zhuǎn)換接口。
關(guān)于矩陣變換在圖形學(xué)中的應(yīng)用可以參考《3D數(shù)學(xué)基礎(chǔ):圖形與游戲開發(fā)》。
5.References
1.Fletcher Dunn, Ian Parberry. 3D Math Primer for Graphics and Game Development. 清華大學(xué)出版社. 2005
2.OpenCASCADE Draw Test Harness User Guide.