讀取DXF格式檔案 (轉)

worldblog發表於2007-12-05
讀取DXF格式檔案 (轉)[@more@]

讀取DXF格式



OpenGL是美國SGI公司最新推出的一套開放式的三維圖形介面,適用於廣泛的環境,從個人計算機到工作站,OpenGL都能實現高的三維圖形功能。OpenGL本身不僅提供對簡單圖元的操作和控制,還提供了許多用於複雜物體的建模。但是,我們通常喜歡使用AutoCAD和3DS及3Dmax等工具來建立模型,並且我們已經有了很多這樣的模型,那麼我們如何才能資源共享,避免重複勞動呢?利用CAD圖形標準資料格式—DXF格式,我們就能很容易地實現資源共享,而不需要重複建模。

DXF檔案的結構很清楚,具體如下:
1. 標題段(HEADER )
有關圖形的一般資訊都可以DXF 檔案的這一節找到,每一個引數具有一個變數名和一個相關值。
2. 表段
這一段包含的指定項的定義,它包括:
a、
線形表(LTYPE)
b、
層表(LYER)
c、
字型表(STYLE)
d、
檢視表(VIEW)
e、
座標表(UCS)
f、
視窗表(VPORT)
g、
標註字型表(DIMSTYLE)
h、
申請符號表(APPID)
3. 塊段(BLOCKS)
這一段含有塊定義實體,這些實體描述了圖形種組成每個塊的實體。
4. 實體段(ENTITIES )
這一段含有實體,包括任何塊的。
5. END OF FILE(檔案結束)

下面是對DXF的基本結構舉一例項進行說明:
0 0 後接SECTION
SECTION 表明這是一個段的開始
2 2 後接的是段名
HEADER 說明該段是HEADER 段(標題段)
9
$ACADVER 檔案是由AUTOCAD 產生的
1
AC1008
9 9 後接 $UCSORG
$UCSORG 使用者座標系原點在世界座標系中的座標
10 10 對應 X
0.0 X 的值
20 20 對應 Y
0.0 Y 的值
30 30 對應 Z
0.0 Z 的值
9
$UCSXDIR 這是一段不太相關的部分,略去
10
1.0
... ....
9 9 後接 $EXTMIN
$EXTMIN 說明三維實體模型在世界座標系中的最小值
10 10 對應 X
-163.925293 X 的值
20 20 對應 Y
-18.5415860.0 Y 的值
30 30 對應 Z
78.350945 Z 的值
9 9 後接 $EXTMAN
$EXTMAX 說明三維實體模型在世界座標系中的最大值
10 10 對應 X
202.492279 X 的值
20 20 對應 Y
112.634300 Y 的值
30 30 對應 Z
169.945602 Z 的值
0 0 後接 ENDSEC
ENDSEC 說明這一段結束了
0 0 後接SECTION
SECTION 表明這是一個段的開始
2 2 後接的是段名
TABLES 說明該段是TABLES 段(表段)
... ... ... ... 該段對我們不太相關,此處略去不進行說明
0 0 後接 ENDSEC
ENDSEC 說明這一段結束了
0 0 後接SECTION
SECTION 表明這是一個段的開始
2 2 後接的是段名
ENTITIES 說明該段是ENTITIES 段(實體段)這是我
0 們要詳細說明的段,該段包含了所有實體的
POLYLINE 點的座標和組成面的點序。0後接POLYLINE
8 表明以下資料是對於一個新的實體;
01 8後接的字串是這個實體的名稱
66
1
70 從66 1 到70 64
64 說明該實體是由許多小平面組成的
71
38 71 38說明該實體共有38 個點
72
72 72 72 說明該實體由72 個三角形構成
0 0 VERTEX
VERTEX 表明後面緊跟著的是實體的資料
8
OBJECT01
10 對應X 座標
-163.925293 X 的值
20 對應Y 座標
-17.772665 Y 的值
30 對應Z 座標
128.929947 Z 的值
70 70 192
192 表明上面的資料資訊是點的座標
0 每一個從0 VERTEX 到70 192 之間
VERTEX 的一小段是點的座標
... ... ...
70
192
0
VERTEX
8
OBJECT01
10
0
20
0
30
0 當70 後跟128 時,表明該實體的每個點的座標資料已經記錄
70 完了,下面緊跟著的是記錄這些點是以什麼樣的方式組合成各
128 個三角形。
71 71、72、73 後面跟著的值表明某一個三角形是第二個、第
2 一個、第四個點構成的,點的順序是按照記入DXF 檔案的順
72 序。當某一值為負數時,則表明該點到下一點的線不要畫出,
1 如果要畫三維實體的線型圖,就必須使用這一特性,否則線條
73 將會出現紊亂。
-4
0
VERTEX
... ... ... ...
0 0 後接SEQEND 表明該實體的資料已經全部記錄完了
SEQEND
8
OBJECT01
0
POLYLINE 0 後接POLYLINE 表明以下又是一個新的實體
... ... ... ...
0
ENDSEC 0 後接ENDSEC 表明這是該段的結尾
0
EOF 0後接EOF 表明這個DXF 檔案結束了

在DXF檔案中,我們最關心的是如何得到模型上各個點的座標,並且用這些點連成許多個三用形,構成面,進而繪製出整個模型。在DXF檔案的結構中,我們已經看到,DXF檔案先敘述實體上各個點的座標,然後敘述實體上有多少個面,每個面由哪些點構成。這樣,我們至少需要2個陣列來一個實體的資訊,一個用於儲存點的座標,一個用於儲存點序,我們可以把這2個陣列放到一個結構中,如果模型中實體的數目不止一個是,我們就用這個結構來定義一個陣列。在本文中,我們使用 Visual C++ 6.0 來寫一個讀取DXF檔案的小。
在實際應用中,模型中實體的數目以及實體中點和麵的數目都是不定的,為了有效地利用,我們選擇MFC類庫中的聚合類CobArray類所建立的vertex, sequence來儲存和管理實體的點座標和點序。
CObArray類是一個用來存放陣列類的聚合類,它能根據要存進來的陣列(或結構)多少自動進行自身大小的高速,而且這個類本身具有的成員函式使得我們對它的物件的操作更加方便、快捷,用它編的程式也易於讀懂。
三維實體模型的模型資訊中的一部分資訊可以在標題段中讀出,透過讀取變數名為$UCSORG的三個變數,可以得到三維實體在世界座標系中自身所定義的使用者座標系原點的三維座標。透過讀取$EXTMAX,$EXTMIN可以獲知三維實體在世界座標系中的範圍,而其它部分的資訊只有讀完了全部DXF檔案後才可以透過計算確定。對於三維實體模型的全部點座標、點序,可以在實體段中按照前面介紹的DXF檔案基本結構讀出。現在我們開始寫這個程式。
先建立一個標頭檔案HEAD.H定義如下的結構:VERTEX, SEQUENCE和類CVertex, Csequence。
typedef struct {
float x,y,z;
}VERTEX; 結構VERTEX用來儲存點的座標

typedef struct {
int a,b,c;
}SEQUENCE; 結構SEQUENCE用來儲存實體的面的組成

typedef struct {
char obName[20]; 定義結構myVertex來儲存實體的名字,點的座標以及面的組成,
CObArray Vertex; 其中,點的座標和麵的組成是由聚合類CObArray定義的物件來
CObArray Sequence; 在儲存的,我們可以把VERTEX結構和SEQUENCE結構加入到
}myVertex; 這兩個物件中儲存

class CVertex : public CObject
{ 因為CObArray類的物件中只能加入由CObject派生的物件,所以
protected: 我們還需要建立一個由CObject類派生的CVertex類。在CVertex類
CVertex(); 中有一個VERTEX結構的變數:m_vertex,資訊實際上是儲存在這
DECLARE_DYNCREATE(CVertex) 個變數中的。
virtual ~CVertex();

// Attributes
public: 我們還需要建立一個由CObject類派生的CVertex類。在CVertex類
CVertex(VERTEX& ver); 中有一個VERTEX結構的變數:m_vertex,資訊實際上是儲存在這個變數中的,函式CVertex(VERTEX& ver)把VERTEX結構的變數
VERTEX m_vertex; 存入CObArray物件中。

};

class CSequence : public CObject
{ 這也是一個由CObject類派生的類,作用和剛才CVertex類一樣,
protected: 只不過Csequence類是用來儲存實體中面的組成(點序)的。
CSequence();
DECLARE_DYNCREATE(CSequence)
virtual ~CSequence();

public:
CSequence(SEQUENCE& sequ);
SEQUENCE m_sequence;
};

宣告好結構與類後,我們還需要建立一個.CPP檔案,來定義幾個函式。
IMPLEMENT_DYNCREATE(CVertex,CObject)
CVertex::CVertex()
{
}

CVertex::~CVertex() 建構函式和銷燬函式都是空的
{
}

CVertex::CVertex(VERTEX& ver)
{ 這個函式的作用是:把一個VERTEX結構的資料存入變數m_vertex中
m_vertex = ver; 它是這個類中最重要的一環。
}

IMPLEMENT_DYNCREATE(CSequence,CObject)
CSequence::CSequence()
{
} Csequence類的定義與CVertex類的定義差不多,只是其中的引數
m_sequence的型別和CVertex類中的引數my_vertex的型別不一樣
CSequence::~CSequence()
{
}

CSequence::CSequence(SEQUENCE& sequ)
{
m_sequence=sequ;
}

然後用結構myVertex(如前所定義)定義一個指標*myData,目的在於根據模型中實體的多少來給指標分配合適的記憶體,使之成為結構陣列。
定義一個函式,用於確定模型中有多少個實體,函式的返回值就是實體的個數。
int CJupiterView::getObjectNumber()
{
char str1[10],str2[10];
char name[]="theFirst";
int num;

num=0;

FILE* fp;
fp=fopen("data.dxf","r"); 開啟DXF檔案,data.dxf
while(! feof(fp) && ! ferror(fp)) 這個函式是根據實體的名字來判斷實體的個數的
{ 所以函式只讀取實體的名字,一旦出現新的實體名字,
fscanf(fp,"%sn",str1); 實體數就加一。
if(strcmp(str1,"VERTEX")==0)
{
fscanf(fp,"%sn",str2); 開啟DXF檔案,data.dxf
fscanf(fp,"%sn",str2) ;這個函式是根據實體的名字來判斷實體的個數的
if(strcmp(name,str2) != 0) 所以函式只讀取實體的名字,一旦出現新的實體名字,
{實體數就加一。
strcpy(name,str2);
num++;
}
}
}
fclose(fp);

return num;
}

以下是讀取實體點的座標以及點序的程式程式碼,在這個程式中,讀取了模型中點的座標的最大值與最小值、實體的名字、點的座標,以及點序。
void CJupiterView::OnFileInput()
{
// TODO: Add your command handler code here
FILE* fp,*fp2;
int i,k,j;
float tempX,tempY,tempZ;

float xMin,yMin,zMin,xMax,yMax,zMax,Max;
int lab;
char str1[20],str2[20],str[20],HT;
char myName[20];
int myNumber;
VERTEX tempVertex;
SEQUENCE tempSequence;

typedef struct {
float x,y,z,max;
}MAX;

MAX max;
HT=9;

objectNumber=getObjectNumber();
myData=new myVertex[objectNumber];

fp=fopen(FileName,"r");

i=0;
j=0;
k=0;

myNumber=-1;
strcpy(myName,"ObjectName");

while(! feof(fp) && ! ferror(fp))
{
fscanf(fp,"%sn",str);

if(strcmp(str,"$EXTMIN")==0)
{
fscanf(fp,"%sn",str1);
fscanf(fp,"%fn",&xMin);

fscanf(fp,"%sn",str1);
fscanf(fp,"%fn",&yMin);

fscanf(fp,"%sn",str1);
fscanf(fp,"%fn",&zMin);
}

if(strcmp(str,"$EXTMAX")==0)
{
fscanf(fp,"%sn",str1);
fscanf(fp,"%fn",&xMax);

fscanf(fp,"%sn",str1);
fscanf(fp,"%fn",&yMax);

fscanf(fp,"%sn",str1);
fscanf(fp,"%fn",&zMax);

max.x=max(abs(xMax),abs(xMin));
max.y=max(abs(yMax),abs(yMin));
max.z=max(abs(zMax),abs(zMin));
max.max=max(max.x,max.y);
max.max=max(max.max,max.z);


}

if(strcmp(str,"VERTEX") ==0)
{
fscanf(fp,"%sn",str1);
fscanf(fp,"%sn",str1);

if(strcmp(myName,str1) != 0)
{
myNumber++;
strcpy(myName,str1);
strcpy((myData+myNumber)->obName,myName);
}


fscanf(fp,"%sn",str2);
fscanf(fp,"%fn",&tempX);

fscanf(fp,"%sn",str2);
fscanf(fp,"%fn",&tempY);

fscanf(fp,"%sn",str2);
fscanf(fp,"%fn",&tempZ);

fscanf(fp,"%dn",&lab);
fscanf(fp,"%dn",&lab);

if(lab == 192)
{
tempVertex.x=tempX / max.max;
tempVertex.y=tempY / max.max;
tempVertex.z=tempZ / max.max;
(myData+myNumber)->Vertex.Add(new CVertex(tempVertex));


}

if(lab == 128)
{
fscanf(fp,"%sn",str1);
fscanf(fp,"%fn",&tempX);

fscanf(fp,"%sn",str1);
fscanf(fp,"%fn",&tempY);

fscanf(fp,"%sn",str1);
fscanf(fp,"%fn",&tempZ);

tempSequence.a=abs(tempX);
tempSequence.b=abs(tempY);
tempSequence.c=abs(tempZ);

(myData+myNumber)->Sequence.Add(new CSequence(tempSequence));

}

}
}
fclose(fp);
}

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988580/,如需轉載,請註明出處,否則將追究法律責任。

相關文章