赞
踩
本文转载自:利用dxflib实现dxf文件的读写与可视化-CSDN博客,感谢原作者的分享,此处仅做学习交流使用
dxflib是开源的读写dxf文件的库,在QCAD上可以直接下载(QCAD - Downloads)。dxf作为一种通用的绘图文件格式,包含的信息量非常大,要去理解文件的内容也比较受苦,详细的解释在论坛里可以找到(dxf 格式详解_dxf是什么文件格式_runing9的博客-CSDN博客)。使用dxflib库的优势在于它很好地简化了各部分的读写,代码可读性很强,同时配库只需要将压缩包下的src文件包含在目录中即可。在给导师做一个简易的CAD软件时用到了包括dxf文件的读写,利用MFC做可视化,还做了一个尺寸修改的交互。
在压缩包内的examples/readwrite文件夹下,有写好的接口类test_creationclass,如下图所示(部分已经修改过),从传入的参数类型来理解各种图元信息的数据结构。目前只使用了包括点、线、圆弧、圆、多段线、文本标注和尺寸标注。
- Test_CreationClass();
- //图元读取
- virtual void addLayer(const DL_LayerData& data);
- virtual void addPoint(const DL_PointData& data);
- virtual void addLine(const DL_LineData& data);
- virtual void addArc(const DL_ArcData& data);
- virtual void addCircle(const DL_CircleData& data);
- virtual void addPolyline(const DL_PolylineData& data);
- virtual void addVertex(const DL_VertexData& data);
- virtual void add3dFace(const DL_3dFaceData& data);
- virtual void addText(const DL_TextData & data);
- struct DXFLIB_EXPORT DL_PointData {
- DL_PointData(double px=0.0, double py=0.0, double pz=0.0) {
- x = px;
- y = py;
- z = pz;
- }
- double x;//3个坐标值
- double y;
- double z;
- };
- struct DXFLIB_EXPORT DL_LineData {
- /**
- * Constructor.
- * Parameters: see member variables.
- */
- DL_LineData(double lx1, double ly1, double lz1,
- double lx2, double ly2, double lz2) {
- x1 = lx1;
- y1 = ly1;
- z1 = lz1;
-
- x2 = lx2;
- y2 = ly2;
- z2 = lz2;
- }
- //2个点坐标
- double x1; double y1;double z1;
-
- double x2; double y2; double z2;
- };
- struct DXFLIB_EXPORT DL_PolylineData {
- /**
- * Constructor.
- * Parameters: see member variables.
- */
- DL_PolylineData(int pNumber, int pMVerteces, int pNVerteces, int pFlags, double pElevation = 0.0) {
- number = pNumber;
- m = pMVerteces;
- n = pNVerteces;
- elevation = pElevation;
- flags = pFlags;
- }
- unsigned int number;//多段线包含的点数,与DL_VertexData配合使用
- unsigned int m;//如果多段线是多边形网格,则m方向上的顶点数
- unsigned int n;//如果多段线是多边形网格,则n方向上的顶点数
- double elevation;//高程
- int flags;
- };
顶点
- struct DXFLIB_EXPORT DL_VertexData {
- /**
- * Constructor.
- * Parameters: see member variables.
- */
- DL_VertexData(double px=0.0, double py=0.0, double pz=0.0,
- double pBulge=0.0) {
- x = px;
- y = py;
- z = pz;
- bulge = pBulge;
- }
-
- double x;
- double y;
- double z;
- double bulge;//多段线的顶点凸起部分的定义。使用顶点处的弧角的1/4弧度的切线值,直线为0
- };
- struct DXFLIB_EXPORT DL_ArcData {
- DL_ArcData(double acx, double acy, double acz,
- double aRadius,
- double aAngle1, double aAngle2) {
-
- cx = acx;
- cy = acy;
- cz = acz;
- radius = aRadius;
- angle1 = aAngle1;
- angle2 = aAngle2;
- }
- //圆弧圆心点坐标
- double cx;
- double cy;
- double cz;
- double radius;//圆弧半径
- double angle1;//起始角度(以x正半轴逆时针旋转计算角度)
- double angle2;//终止角度
- };
- struct DXFLIB_EXPORT DL_CircleData {
- DL_CircleData(double acx, double acy, double acz,
- double aRadius) {
-
- cx = acx;
- cy = acy;
- cz = acz;
- radius = aRadius;
- }
- //圆心坐标及半径
- double cx;
- double cy;
- double cz;
- double radius;
- };
- struct DXFLIB_EXPORT DL_TextData {
- DL_TextData(double ipx, double ipy, double ipz,
- double apx, double apy, double apz,
- double height, double xScaleFactor,
- int textGenerationFlags,
- int hJustification,
- int vJustification,
- const std::string& text,
- const std::string& style,
- double angle)
- : ipx(ipx), ipy(ipy), ipz(ipz),
- apx(apx), apy(apy), apz(apz),
- height(height), xScaleFactor(xScaleFactor),
- textGenerationFlags(textGenerationFlags),
- hJustification(hJustification),
- vJustification(vJustification),
- text(text),
- style(style),
- angle(angle) {
- }
- //定义点坐标
- double ipx;
- double ipy;
- double ipz;
- //对齐点坐标
- double apx;
- double apy;
- double apz;
-
- double height;//字高
- double xScaleFactor;//相对X比例因子
- int textGenerationFlags;//默认为0,向后为2,倒置为4
- int hJustification;//水平对齐
- /* 左侧=0,中心=1,右侧=2,对齐=3,中间=4,适应=5
- 对于3、4、5垂直对齐必须为0 */
- int vJustification;//垂直对齐,基线=0,底部=1,中间=2,顶部=3
- std::string text;//文本内容
- std::string style;//字体
- double angle;//旋转角度
- };
尺寸标注相对复杂一些,它不止简单的一个文本,还包括直线和箭头,称为标注块,也就是说它需要通过块来添加。具体的内容在文件中查阅,这里不在展示。
- virtual void addBlock(const DL_BlockData&data);//添加块
- virtual void endBlock();//结束块的添加
- virtual void addSolid(const DL_SolidData&data);//箭头
- virtual void addMText(const DL_MTextData & data);//标注文本
在官方下载下来的文件中,有一个Test_CreationClass头文件和源文件,dxf文件的数据结构直接用这个类就可以。这个就相当于接口类,在里面可以重写各类图元读取的函数,原本里面是打印相关信息,我改成了保存数据到成员中。需要注意的是多段线的读取结束时需要调用donpolyline,完成多段线的添加,而标注块也是类似的道理,需要读取完这个块。内容见下面头文件以及源文件。
- #ifndef TEST_CREATIONCLASS_H
- #define TEST_CREATIONCLASS_H
- #include<vector>
- #include "../src/dl_creationadapter.h"
-
- class Test_CreationClass : public DL_CreationAdapter {
- public:
- Test_CreationClass();
- //图元读取
- virtual void addLayer(const DL_LayerData& data);
- virtual void addPoint(const DL_PointData& data);
- virtual void addLine(const DL_LineData& data);
- virtual void addArc(const DL_ArcData& data);
- virtual void addCircle(const DL_CircleData& data);
- virtual void addPolyline(const DL_PolylineData& data);
- virtual void addVertex(const DL_VertexData& data);
- virtual void add3dFace(const DL_3dFaceData& data);
- virtual void addText(const DL_TextData & data);
- //标注块整体读取
- bool adddim = false;
- virtual void addBlock(const DL_BlockData&data);
- virtual void endBlock();
- virtual void addSolid(const DL_SolidData&data);
- virtual void addMText(const DL_MTextData & data);
-
- void printAttributes();
- void donepolyline()
- {
- for (int i = 0; i < m_polylines.size(); ++i)
- m_polylines[i].first.number = m_polylines[i].second.size();
- }
-
- class dimblock{
- public:
- dimblock(){
- dimlines.clear();
- dimtext.clear();
- dimarrow.clear();
- }
- std::vector<DL_LineData>dimlines;
- std::vector<DL_MTextData> dimtext;
- std::vector<DL_SolidData>dimarrow;
-
- };
- public://图元信息
- //DL_LayerData m_layerdata; //层
- std::vector<DL_PointData>m_points; //点
- std::vector<DL_LineData>m_lines; //直线
- std::vector<std::pair<DL_PolylineData, std::vector<DL_VertexData>>>m_polylines; //多段线
- std::vector<DL_ArcData> m_arcs; //圆弧
- std::vector<DL_CircleData >m_circles; //圆
- std::vector<DL_SolidData>m_solid; //实体
- std::vector<DL_TextData>m_text; //普通文本
- std::vector<DL_MTextData>m_mtext; //标注文本
- std::vector<dimblock>m_dimblock; //标注块
-
- };
-
- #endif
cpp
- #include "test_creationclass.h"
-
- #include <iostream>
- #include <stdio.h>
-
-
- /**
- * Default constructor.
- */
- Test_CreationClass::Test_CreationClass() {
- m_points.clear();
- m_lines.clear();
- m_polylines.clear();
- m_circles.clear();
- m_arcs.clear();
- m_text.clear();
- m_mtext.clear();
- m_dimblock.clear();
- }
-
-
- /**
- * Sample implementation of the method which handles layers.
- */
- void Test_CreationClass::addLayer(const DL_LayerData& data) {
- // printf("LAYER: %s flags: %d\n", data.name.c_str(), data.flags);
- // printAttributes();
- }
-
- /**
- * Sample implementation of the method which handles point entities.
- */
- void Test_CreationClass::addPoint(const DL_PointData& data) {
- m_points.push_back(data);
- // printf("POINT (%6.3f, %6.3f, %6.3f)\n",data.x, data.y, data.z);
- // printAttributes();
- }
-
- /**
- * Sample implementation of the method which handles line entities.
- */
- void Test_CreationClass::addLine(const DL_LineData& data) {
-
- if (adddim)
- m_dimblock[m_dimblock.size() - 1].dimlines.push_back(data);
- else
- m_lines.push_back(data);
- // printf("LINE (%6.3f, %6.3f, %6.3f) (%6.3f, %6.3f, %6.3f)\n",data.x1, data.y1, data.z1, data.x2, data.y2, data.z2);
- // printAttributes();
- }
-
- /**
- * Sample implementation of the method which handles arc entities.
- */
- void Test_CreationClass::addArc(const DL_ArcData& data) {
- m_arcs.push_back(data);
- // printf("ARC (%6.3f, %6.3f, %6.3f) %6.3f, %6.3f, %6.3f\n",data.cx, data.cy, data.cz, data.radius, data.angle1, data.angle2);
- // printAttributes();
- }
-
- /**
- * Sample implementation of the method which handles circle entities.
- */
- void Test_CreationClass::addCircle(const DL_CircleData& data) {
- m_circles.push_back(data);
- // printf("CIRCLE (%6.3f, %6.3f, %6.3f) %6.3f\n",data.cx, data.cy, data.cz, data.radius);
- // printAttributes();
- }
-
-
- /**
- * Sample implementation of the method which handles polyline entities.
- */
- void Test_CreationClass::addPolyline(const DL_PolylineData& data) {
- std::vector<DL_VertexData> temp; temp.clear();
- std::pair<DL_PolylineData, std::vector<DL_VertexData>> newone(data,temp);
- m_polylines.push_back(newone);
- // printf("POLYLINE \n");
- // printf("flags: %d\n", (int)data.flags);
- // printAttributes();
- }
-
-
- /**
- * Sample implementation of the method which handles vertices.
- */
- void Test_CreationClass::addVertex(const DL_VertexData& data) {
- m_polylines[m_polylines.size() - 1].second.push_back(data);
- // printf("VERTEX (%6.3f, %6.3f, %6.3f) %6.3f\n",data.x, data.y, data.z,data.bulge);
- // printAttributes();
- }
-
-
- void Test_CreationClass::add3dFace(const DL_3dFaceData& data) {
- printf("3DFACE\n");
- // for (int i=0; i<4; i++) {
- // printf(" corner %d: %6.3f %6.3f %6.3f\n", i, data.x[i], data.y[i], data.z[i]);
- // }
- // printAttributes();
- }
-
-
- void Test_CreationClass::addBlock(const DL_BlockData&data)
- {
- adddim = true;
- dimblock newone;
- m_dimblock.push_back(newone);
- }
-
-
- void Test_CreationClass::endBlock()
- {
- adddim = false;
- if (m_dimblock[m_dimblock.size() - 1].dimlines.size() < 1
- && m_dimblock[m_dimblock.size() - 1].dimtext.size() < 1
- && m_dimblock[m_dimblock.size() - 1].dimarrow.size()<1)
- m_dimblock.pop_back();
- }
-
-
- void Test_CreationClass::addSolid(const DL_SolidData&data)
- {
- if (adddim)
- m_dimblock[m_dimblock.size() - 1].dimarrow.push_back(data);
- else
- m_solid.push_back(data);
- }
-
- void Test_CreationClass::addText(const DL_TextData & data)
- {
- m_text.push_back(data);
- }
-
-
- void Test_CreationClass::addMText(const DL_MTextData & data)
- {
- if (adddim)
- m_dimblock[m_dimblock.size() - 1].dimtext.push_back(data);
- else
- m_mtext.push_back(data);
- }
-
- void Test_CreationClass::printAttributes() {
- // printf(" Attributes: Layer: %s, ", attributes.getLayer().c_str());
- // printf(" Color: ");
- // if (attributes.getColor()==256) {
- // printf("BYLAYER");
- // } else if (attributes.getColor()==0) {
- // printf("BYBLOCK");
- // } else {
- // printf("%d", attributes.getColor());
- // }
- // printf(" Width: ");
- // if (attributes.getWidth()==-1) {
- // printf("BYLAYER");
- // } else if (attributes.getWidth()==-2) {
- // printf("BYBLOCK");
- // } else if (attributes.getWidth()==-3) {
- // printf("DEFAULT");
- // } else {
- // printf("%d", attributes.getWidth());
- // }
- // printf(" Type: %s\n", attributes.getLinetype().c_str());
- }
-
-
-
- // EOF
在外部类中声明上述的类Test_CreationClass为成员变量,定义一个读文件的方法。例如我是外部又建立了一个MyDxf类用来衔接MFC的button事件或其他控件,注意包含相关的头文件。
- public:
- Test_CreationClass * m_data; //dxf数据输出接口
- void MyDxf::OpenDxf_Button(string filePath)
- {
- // Load DXF file into memory:
- Initialdxf();
- std::cout << "Reading file " << filePath << "...\n";
- if (!m_dxf->in(filePath, m_data)) { // if file open failed
- std::cerr << filePath << " could not be opened.\n";
- return;
- }
- m_data->donepolyline();
-
- }
说是写文件,其实是保存文件,写文件的过程就是对m_data修改的过程,例如后面添加交互功能,画线,画圆之类的,只需往相应的m_data中的容器添加即可。
- void MyDxf::SaveDxf_Button(string filePath)
- {
- if (m_data==NULL)return;
- FILE *pfd = fopen(filePath.c_str(), "w+");
- DL_Codes::version exportVersion = DL_Codes::AC1015;
- DL_WriterA* dw = m_dxf->out(filePath.c_str(), exportVersion);
- if (dw == NULL) { printf("Cannot open file 'myfile.m_dxf' \ for writing."); return; }
- /*--------------------------------------------------------*/
- //1 标题段
- m_dxf->writeHeader(*dw);
- dw->sectionEnd();
- /*--------------------------------------------------------*/
- //2 表段
- dw->sectionTables();
- m_dxf->writeVPort(*dw);
- //2.1 线型表(Linetype)
- dw->tableLinetypes(3);
- m_dxf->writeLinetype(*dw, DL_LinetypeData("BYBLOCK", "BYBLOCK", 0, 0, 0.0));
- m_dxf->writeLinetype(*dw, DL_LinetypeData("BYLAYER", "BYLAYER", 0, 0, 0.0));
- m_dxf->writeLinetype(*dw, DL_LinetypeData("CONTINUOUS", "Continuous", 0, 0, 0.0));
- dw->tableEnd();
- //2.2 图层表(Layer)
- int numberOfLayers = 3;//层数3
- dw->tableLayers(numberOfLayers);
- m_dxf->writeLayer(*dw, DL_LayerData("0", 0), DL_Attributes(std::string(""), DL_Codes::black, 100, "CONTINUOUS", 1.0));
- m_dxf->writeLayer(*dw, DL_LayerData("mainlayer", 0), DL_Attributes(std::string(""), DL_Codes::black, 100, "CONTINUOUS", 1.0));
- m_dxf->writeLayer(*dw, DL_LayerData("anotherlayer", 0), DL_Attributes(std::string(""), DL_Codes::blue, 100, "CONTINUOUS", 1.0));
- dw->tableEnd();
- //2.3 字样表(Style)
- dw->tableStyle(1);
- m_dxf->writeStyle(*dw, DL_StyleData("standard", 0, 2.5, 1.0, 0.0, 0, 2.5, "txt", ""));
- dw->tableEnd();
- //2.4 视图表(View)
- m_dxf->writeView(*dw);
- m_dxf->writeUcs(*dw);
- dw->tableAppid(1);
- m_dxf->writeAppid(*dw, "ACAD");
- dw->tableEnd();
- //2.5 DL_VERSION_R13中需要伪造dimstyle和blockrecord两部分,以使AutoCAD能够读取该文件。
- m_dxf->writeDimStyle(*dw, 1, 1, 1, 1, 1);
- m_dxf->writeBlockRecord(*dw);
- dw->tableEnd();
- dw->sectionEnd();
- /*--------------------------------------------------------*/
- //3 块段
- DL_Attributes typetemp1("mainlayer", 256, -1, "BYLAYER", 1.0);//属性
- DL_Attributes typetemp2("anotherlayer", 256, -1, "BYLAYER", 1.0);//属性
- dw->sectionBlocks();
- m_dxf->writeBlock(*dw, DL_BlockData("*Model_Space", 0, 0.0, 0.0, 0.0));
- m_dxf->writeEndBlock(*dw, "*Model_Space");
- m_dxf->writeBlock(*dw, DL_BlockData("*Paper_Space", 0, 0.0, 0.0, 0.0));
- m_dxf->writeEndBlock(*dw, "*Paper_Space");
- m_dxf->writeBlock(*dw, DL_BlockData("*Paper_Space0", 0, 0.0, 0.0, 0.0));
- m_dxf->writeEndBlock(*dw, "*Paper_Space0");
-
- // m_dxf->writeBlock(*dw, DL_BlockData("myblock1", 0, 0.0, 0.0, 0.0));
- // // ...
- // // write block entities e.g. with m_dxf->writeLine(), ..
- // // ...
- // m_dxf->writeEndBlock(*dw, "myblock1");
- dw->sectionEnd();
-
- /*--------------------------------------------------------*/
- //4 实体段
- dw->sectionEntities();
-
-
- for (int i = 0; i < m_data->m_points.size(); ++i)
- {
- m_dxf->writePoint(*dw, m_data->m_points[i], typetemp1);
- }
- for (int i = 0; i < m_data->m_lines.size(); ++i)
- {
- m_dxf->writeLine(*dw, m_data->m_lines[i], typetemp1);
- }
- for (int i = 0; i < m_data->m_polylines.size(); ++i)
- {
- m_dxf->writePolyline(*dw, m_data->m_polylines[i].first, typetemp1);
- for (int j = 0; j < m_data->m_polylines[i].second.size(); ++j)
- {
- m_dxf->writeVertex(*dw, m_data->m_polylines[i].second[j]);
- }
- m_dxf->writePolylineEnd(*dw);
- }
- for (int i = 0; i < m_data->m_arcs.size(); ++i)
- {
- m_dxf->writeArc(*dw, m_data->m_arcs[i], typetemp1);
- }
- for (int i = 0; i < m_data->m_circles.size(); ++i)
- {
- m_dxf->writeCircle(*dw, m_data->m_circles[i], typetemp1);
- }
- for (int i = 0; i < m_data->m_text.size();++i)
- {
- //m_dxf->writeText(*dw, m_data->m_text[i], typetemp2);//用text写有问题,使用MText代替
- DL_MTextData temp(m_data->m_text[i].ipx, m_data->m_text[i].ipy, m_data->m_text[i].ipz,
- 0, 0, 0, m_data->m_text[i].height, 0, 5, 1, 1, 1, m_data->m_text[i].text, m_data->m_text[i].style, m_data->m_text[i].angle);
- m_dxf->writeMText(*dw, temp, typetemp2);
-
- }
- for (int i = 0; i < m_data->m_mtext.size(); ++i)
- {
- //m_data->m_mtext[i].height = 30;
- DL_MTextData temp = m_data->m_mtext[i];
- temp.height = 50;
- m_dxf->writeMText(*dw, temp, typetemp2);
- }
-
-
-
- dw->sectionEnd();
- /*--------------------------------------------------------*/
- //5 文件结束段
- m_dxf->writeObjects(*dw);
- m_dxf->writeObjectsEnd(*dw);
-
- dw->dxfEOF();
- dw->close();
- delete dw;
- delete m_dxf;
- dw = nullptr;
- m_dxf = nullptr;
- }
版权声明:本文为CSDN博主「卡死脱离态」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Akiyama_sou/article/details/130870304
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。