Open Cascade DataExchange DXF
eryar@163.com
摘要Abstract:對(duì)DXF文本格式進(jìn)行詳細(xì)介紹,并介紹了如何使用開源庫(kù)dxflib對(duì)DXF文件進(jìn)行讀寫操作,并將DXF文件中圖形導(dǎo)入到OpenCascade。
關(guān)鍵字Key Words:DXF、Open Cascade、Data Exchange, dxflib
一、引言 Introduction
目前市面上的CAD系統(tǒng)都有自己的數(shù)據(jù)文件,各個(gè)系統(tǒng)之間的數(shù)據(jù)結(jié)構(gòu)和格式各不相同,這樣極大影響了設(shè)計(jì)和制造部門之間或企業(yè)之間的數(shù)據(jù)傳輸和程序銜接的自動(dòng)化,同樣給CMM和CAD/CAM的數(shù)據(jù)通信帶來(lái)困難。因此,迫切需要數(shù)據(jù)交換文件格式的標(biāo)準(zhǔn)化。
產(chǎn)品數(shù)據(jù)的正確交換可以使雙方不必重建數(shù)據(jù),提高效率。產(chǎn)品數(shù)據(jù)交換的通常做法是使用數(shù)據(jù)交換接口,即需要交換的每一系統(tǒng)與標(biāo)準(zhǔn)數(shù)據(jù)格式(中性格式)之間開發(fā)雙向轉(zhuǎn)換接口,兩系統(tǒng)通過(guò)中性格式進(jìn)行交換。
DXF是Drawing eXchange File的縮寫,意思為圖形交換文件,在工程制圖中有廣泛的應(yīng)用,掌握了DXF文件的讀寫對(duì)編寫CAD軟件時(shí)的圖形信息的交換有重要意義。它有兩種格式:一種是ASCII DXF格式;一種是二進(jìn)制DXF格式。ASCII DXF文件格式是ASCII 文字格式的AutoCAD圖形的完整表示,這種文件格式易于被其它程序處理。二進(jìn)制格式的DXF文件與ASCII格式的DXF文件包含的信息相同,但格式上二進(jìn)制格式比ASCII格式更精簡(jiǎn),能夠節(jié)省百分之二十五的文件空間。AutoCAD能夠更快地對(duì)其執(zhí)行讀寫操作(通常能快五倍)。這可能是對(duì)ASCII格式的DXF文件操作時(shí)有ASCII與二進(jìn)制形式的轉(zhuǎn)換,因而花費(fèi)時(shí)間較多。ASCII格式的DXF文件可讀性強(qiáng)。
OpenCascade也有數(shù)據(jù)交換接口DataExchange,可對(duì)主流圖形交換格式進(jìn)行讀寫。
Figure 1.1 DataExchange Module of OpenCascade
其中對(duì)STEP、IGES、STL、VRML的程序是開源的,對(duì)ACIS的SAT、Parasolid的X_T和DXF數(shù)據(jù)交換的程序是收費(fèi)的,對(duì)DXF讀寫的是DXF-Import-Export,詳情可參考:
http://www.opencascade.org/support/products/dataex/,也可直接和OpenCascade進(jìn)行聯(lián)系。
二、DXF格式簡(jiǎn)介 DXF Introduction
一個(gè)完整的ASCII格式的DXF文件結(jié)構(gòu)如下:
l HEADER段。它包含圖形的基本信息。它由AutoCAD數(shù)據(jù)庫(kù)版本號(hào)和一些系統(tǒng)變量組成。每個(gè)參數(shù)都包含一個(gè)變量名稱及其關(guān)聯(lián)的值。
l CLASSES段。包含應(yīng)用程序定義的類的信息,這些類的實(shí)例出現(xiàn)在數(shù)據(jù)庫(kù)的BLOCKS、ENTITIES和OBJECTS段中。類定義在類的層次結(jié)構(gòu)中是固定不變的。
l TABLES段。包含以下符號(hào)表的定義:
APPID(應(yīng)用程序標(biāo)識(shí)表)
BLOCK_RECORD(塊參照表)
DIMSTYLE(標(biāo)注樣式表)
LAYER(圖層表)
LTYPE(線型表)
STYLE(文字樣式表)
UCS(用戶坐標(biāo)系表)
VIEW(視圖表)
VPORT(視口配置表)
l BLOCKS段。包含構(gòu)成圖形中每個(gè)塊參照的塊定義和圖形圖元。
l ENTITIES段。包含圖形中的圖形對(duì)象(圖元),其中包括塊參照(插入圖元)。這里的信息很重要。
l OBJECTS段。包含圖形中的非圖形對(duì)象。除圖元、符號(hào)表記錄以及符號(hào)表以外的所有對(duì)象都存儲(chǔ)在此段。OBJECTS段中的條目樣例是包含多線樣式和組的詞典。
l THUMBNAILIMAGE段。包含圖形的預(yù)覽圖像數(shù)據(jù)。此段為可選。
每個(gè)段都以一個(gè)后跟字符串SECTION的組碼0開始,其后是組碼2和表示該段名稱的字符串(例如,HEADER)。每個(gè)段都由定義其元素的組碼和值組成。每個(gè)段都以一個(gè)后跟字符串ENDSEC的組碼0結(jié)束。
關(guān)于DXF文件更詳細(xì)內(nèi)容可參考我08年寫的一篇文章《用C讀取DXF文件》,可以從網(wǎng)上下載,網(wǎng)址:http://blog.csdn.net/eryar/article/details/2371755。在11年又寫了一個(gè)《Read DXF File》,雖然使用了繼承,但是讀入時(shí)的很多判斷的處理感覺(jué)還不是很滿意,文章代碼網(wǎng)址:
http://www.shnenglu.com/eryar/archive/2013/03/26/162303.html
參考這些代碼,可以完全理解文本格式的DXF文件,并可自己動(dòng)手來(lái)處理DXF文件了。
三、使用dxflib與OpenCascade交換數(shù)據(jù) Wrap dxflib for OpenCascade DataExchange
如果程序中只用到DXF簡(jiǎn)單的圖形,如直線、圓弧、圓等,可以自己寫個(gè)處理的程序;如果要處理DWG格式的文件,有些庫(kù)可以使用,如openDWG Toolkit,雖然帶有Open字樣,但是這個(gè)工具并不是免費(fèi)的,免費(fèi)的有LibreDWG;如果只處理文本格式的DXF文件,可以使用庫(kù)dxflib。當(dāng)然dxflib也是有不足之處的,如只能處理文本格式的DXF,不能處理二進(jìn)制格式,不能處理包含的ACIS三維實(shí)體等。如果程序只處理簡(jiǎn)單的圖形、三維面片等,dxflib還是很好用的。
dxflib的使用方法很簡(jiǎn)單,通過(guò)調(diào)用 DL_Dxf 對(duì)象的 in 函數(shù)并將指針傳遞給一個(gè)繼承 DL_CreationAdapter 抽象類來(lái)打開此文件。in 函數(shù)運(yùn)行時(shí),會(huì)調(diào)用傳遞給它的類中的幾個(gè)函數(shù)。如今,有數(shù)十個(gè)這樣的函數(shù)(參閱DXFLib程序員手冊(cè)),但是在大多數(shù)情況下,受關(guān)注最多的有如下這幾個(gè)函數(shù):addPoint、addLine、 addCircle 和 addVertex。您只需實(shí)現(xiàn)您所關(guān)注的那些函數(shù);剩下的您可以忽略。
下面給出一個(gè)使用dxflib讀取形狀并轉(zhuǎn)換到OpenCascade中的具體例子。
四、程序示例 Example Code
這里給出具體的程序示例,當(dāng)然目前只實(shí)現(xiàn)部分形狀到OpenCascade的轉(zhuǎn)換,如果有興趣可以實(shí)現(xiàn)其他形狀的實(shí)現(xiàn)。程序代碼如下所示:
類聲明文件:DxfReader.h
/*
* Copyright (c) 2013 eryar All Rights Reserved.
*
* File : DxfReader.h
* Author : eryar@163.com
* Date : 2013-12-22 14:40
* Version : 1.0v
*
* Description : Use dxflib to import entities from DXF to OpenCascade.
*
* Key Words : OpenCascade, dxflib, DXF, DataExchange
*
*/
#pragma once
#define WNT
#include <TopoDS_Shape.hxx>
#include <BRep_Builder.hxx>
#include <memory>
#include "dl_dxf.h"
#include "dl_creationadapter.h"
/**
* @breif Facade dxflib for OpenCascade DataExchange with DXF.
*/
class DxfReader : public DL_CreationAdapter
{
public:
/**
* @brief constructor.
* @param fileName [in] dxf file name with path.
*/
DxfReader(const std::string& fileName);
~DxfReader(void);
/**
* @brief Get the shape of the dxf.
* @return OpenCascade topology shape.
*/
const TopoDS_Shape& GetShape(void) const;
public:
virtual void addPoint(const DL_PointData&);
virtual void addLine(const DL_LineData& line);
virtual void addArc(const DL_ArcData& arc);
virtual void addCircle(const DL_CircleData& circle);
virtual void addEllipse(const DL_EllipseData&);
virtual void addPolyline(const DL_PolylineData& polyline);
virtual void addVertex(const DL_VertexData&);
virtual void addSpline(const DL_SplineData&);
virtual void addKnot(const DL_KnotData&);
virtual void addControlPoint(const DL_ControlPointData&);
virtual void add3dFace(const DL_3dFaceData&);
virtual void addSolid(const DL_SolidData& solid);
private:
std::auto_ptr<DL_Dxf> mDxf;
TopoDS_Compound mShape;
BRep_Builder mBuilder;
};
類定義文件:DxfReader.cpp
/*
* Copyright (c) 2013 eryar All Rights Reserved.
*
* File : DxfReader.cpp
* Author : eryar@163.com
* Date : 2013-12-22 14:40
* Version : 1.0v
*
* Description : Use dxflib to import entities from DXF to OpenCascade.
*
* Key Words : OpenCascade, dxflib, DXF, DataExchange
*
*/
#include "DxfReader.h"
#include <Degrees.hxx>
#include <gp_Circ.hxx>
#include <gp_Elips.hxx>
#include <GC_MakeSegment.hxx>
#include <GC_MakeCircle.hxx>
#include <GC_MakeArcOfCircle.hxx>
#include <GC_MakeEllipse.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
DxfReader::DxfReader(const std::string& fileName)
: mDxf(new DL_Dxf())
{
mBuilder.MakeCompound(mShape);
mDxf->in(fileName, this);
}
DxfReader::~DxfReader(void)
{
}
const TopoDS_Shape& DxfReader::GetShape() const
{
return mShape;
}
void DxfReader::addPoint(const DL_PointData& point)
{
mBuilder.Add(mShape, BRepBuilderAPI_MakeVertex(gp_Pnt(point.x, point.y, point.z)));
}
void DxfReader::addLine(const DL_LineData& line)
{
Handle_Geom_Curve theSegment = GC_MakeSegment(gp_Pnt(line.x1, line.y1, line.z1), gp_Pnt(line.x2, line.y2, line.z2));
mBuilder.Add(mShape, BRepBuilderAPI_MakeEdge(theSegment));
}
void DxfReader::addArc(const DL_ArcData &arc)
{
gp_Circ theCircle;
theCircle.SetRadius(arc.radius);
theCircle.SetLocation(gp_Pnt(arc.cx, arc.cy, arc.cz));
Handle_Geom_Curve theArc = GC_MakeArcOfCircle(theCircle, DEG(arc.angle1), DEG(arc.angle2), false);
mBuilder.Add(mShape, BRepBuilderAPI_MakeEdge(theArc));
}
void DxfReader::addCircle(const DL_CircleData& circle)
{
gp_Circ aCircle;
aCircle.SetRadius(circle.radius);
aCircle.SetLocation(gp_Pnt(circle.cx, circle.cy, circle.cz));
Handle_Geom_Curve theCircle = GC_MakeCircle(aCircle);
mBuilder.Add(mShape, BRepBuilderAPI_MakeEdge(theCircle));
}
void DxfReader::addEllipse(const DL_EllipseData& ellipse)
{
}
void DxfReader::addPolyline(const DL_PolylineData& polyline)
{
}
void DxfReader::addVertex(const DL_VertexData& vertex)
{
}
void DxfReader::addSpline(const DL_SplineData& spline)
{
}
void DxfReader::addKnot(const DL_KnotData& knot)
{
}
void DxfReader::addControlPoint(const DL_ControlPointData& cp)
{
}
void DxfReader::add3dFace(const DL_3dFaceData& face)
{
BRepBuilderAPI_MakePolygon polygon(
gp_Pnt(face.x[0], face.y[0], face.z[0]),
gp_Pnt(face.x[1], face.y[1], face.z[1]),
gp_Pnt(face.x[2], face.y[2], face.z[2]),
gp_Pnt(face.x[3], face.y[3], face.z[3]), true);
BRepBuilderAPI_MakeFace makeFace(polygon.Wire());
if (makeFace.IsDone())
{
mBuilder.Add(mShape, makeFace.Face());
}
//mBuilder.Add(mShape, polygon.Wire());
}
void DxfReader::addSolid(const DL_SolidData &solid)
{
add3dFace(solid);
}
類DxfReader的使用也很簡(jiǎn)單,程序如下所示:
/*
* Copyright (c) 2013 eryar All Rights Reserved.
*
* File : Main.cpp
* Author : eryar@163.com
* Date : 2013-12-22 15:00
* Version : 1.0v
*
* Description : Use dxflib to import entities from DXF to OpenCascade.
*
* Key Words : OpenCascade, dxflib, DXF, DataExchange
*
*/
#include "DxfReader.h"
#include <BRepTools.hxx>
#pragma comment(lib, "TKernel.lib")
#pragma comment(lib, "TKMath.lib")
#pragma comment(lib, "TKBRep.lib")
#pragma comment(lib, "TKGeomBase.lib")
#pragma comment(lib, "TKTopAlgo.lib")
int main(int argc, char* argv[])
{
std::string strFile = ((argc > 1) ? argv[1] : "test.dxf");
DxfReader dxfReader(strFile);
ofstream brepFile("dxf.brep");
BRepTools::Write(dxfReader.GetShape(), brepFile);
return 0;
}
程序效果還不錯(cuò),給出幾個(gè)程序處理的例子如下圖所示:
Figure 4.1 Use DxfReader import DXF to OpenCascade
Figure 4.2 Use DxfReader import DXF to OpenCascade
五、結(jié)論 Conclusion
DXF格式是圖形數(shù)據(jù)交換的一種常見(jiàn)格式,DXF文件的讀寫對(duì)CAD/CAM程序很有意義。本文通過(guò)把dxflib簡(jiǎn)單封裝把DXF中圖形轉(zhuǎn)換為OpenCascade中的形狀,為免費(fèi)在OpenCascade中進(jìn)行DXF數(shù)據(jù)交換提供了一個(gè)思路。希望本文對(duì)你有所幫助。
六、參考資料 References
1. 使用開源庫(kù)讀取DWG和DXF文件,
http://www.ibm.com/developerworks/cn/opensource/os-autocad/
2. eryar, 用C讀取DXF文件, http://blog.csdn.net/eryar/article/details/2371755
3. eryar, Read DXF File, http://www.shnenglu.com/eryar/archive/2013/03/26/162303.html
4. openDWG, http://www.opendesign.com/
5. OpenCascade, DXF Import-Export, http://www.opencascade.org/support/products/dataex/dxf/