DXF 读取器解决方案和简单的 DXF 查看器






3.68/5 (37投票s)
该项目读取 DXF 文件,提取和解释数据并在屏幕上绘制。

引言
该项目主要涉及读取 DXF 文件,但为了演示读取器的工作情况,我还包含了一个查看器,该查看器可以解释数据并在屏幕上绘制。事实上,一开始我的唯一目的是从 DXF 文件中提取数据,但后来在屏幕上解释和绘制数据开始花费更多时间,并掩盖了数据提取的优先级。在这一切之后,这是结果。
背景
CodeProject 上有几个 DXF 写入项目(一个是 Omid Shahabi 的,另一个是 Claude Gagnon 的),但我找不到一个读取 DXF 文件的 DXF 读取器。在对网络进行各种扫描后,我偶然发现了 AutoCAD 的 DXF 规范,并决定自己制作一个读取器。但后来我发现,仅仅一个读取器是没有价值的,还需要一个查看器。于是这个项目部分成为了一个 DXF 读取器,主要是作为一个查看器程序,我还制作了一个绘图编辑器。然而,编辑器向用户提供的唯一交互是突出显示形状(按住 Shift 键同时移动鼠标光标即可突出显示)……所有绘图均由软件完成。(稍后我将尝试提供详细信息。)
总体结构
DXF 文件 | → | DXF 读取器 | + | 解释 | → | 查看器 | → | 屏幕 |
嗯,正如你所看到的,结构如上。数据从 DXF 文件中提取并解释,然后调用查看器所需的相应方法,结果显示在屏幕上。
虽然预期的结构如上,但代码本身并没有如此分离。
该应用程序是一个 MDI 应用程序。您可以打开多个 DXF 文件进行查看。
有一个用于绘图的 Canvas
类和一个用于定义对象的 Shape
类。目前可以识别 AutoCAD
的 Line
、Polyline
、Circle
和 Arc
形状。在不久的将来,我计划添加 B-Spline。
DXF 解释方法包含在 canvas
类中。将这些方法与绘图方法分离会更好,但目前这就是我能提供的。
方法
当您单击“文件/打开”时,将调用以下方法
private void menuItem2_Click(object sender, System.EventArgs e) //Opens openfile
//dialog to select a DXF file
{
inputFileTxt = "";
openFileDialog1.InitialDirectory = "c:\\ "; //sets the initial directory of the
//openfile dialog
openFileDialog1.Filter = "DXF files (*.dxf)|*.dxf|All files (*.*)|*.*" ; //filters the
//visible files...
openFileDialog1.FilterIndex = 1 ;
if (openFileDialog1.ShowDialog() ==
System.Windows.Forms.DialogResult.OK) //open file dialog is shown here...
//if "cancel" button is clicked then
//nothing will be done...
{
inputFileTxt = openFileDialog1.FileName; //filename is taken
//(file path is also included to this
//name example: c:\windows\system\blabla.dxf
int ino = inputFileTxt.LastIndexOf("\\ "); //index no. of the last "\"
//(that is before the filename)
//is found here
newCanvas = new Canvas(); //a new canvas is created...
newCanvas.MdiParent = this; //...its mdiparent is set...
newCanvas.Text = inputFileTxt.Substring
(ino+1, inputFileTxt.Length - ino - 1); //...filename is
//extracted from the text.(blabla.dxf).
newCanvas.MinimumSize = new Size (500, 400); //...canvas minimum size is set...
if(inputFileTxt.Length > 0)
{
newCanvas.ReadFromFile(inputFileTxt); //the filename is sent to the method
//for data extraction and interpretation...
}
newCanvas.Show(); //the canvas is displayed...
newCanvas.Activate();
newCanvas.Focus();
}
openFileDialog1.Dispose();
}
如上所述,DXF 解释是在 Canvas
类中完成的。Canvas
类是一个 Windows 窗体。除了标准命名空间外,还包括以下命名空间
using System.IO;
using System.Drawing.Drawing2D;
using System.Data;
Canvas
类的 ReadFromFile(string filename)
方法负责从 DXF 文件中提取数据并将其转发给相应的绘图方法
public void ReadFromFile (string textFile) //Reads a text file
//(in fact a DXF file) for importing an
//Autocad drawing.
{
string line1, line2; //these line1 and line2 is used for getting the a/m data groups...
line1 = "0"; //line1 and line2 are initialized here...
line2 = "0";
long position = 0;
theSourceFile = new FileInfo (textFile); //the source file is set.
StreamReader reader = null; //a reader is prepared...
try
{
reader = theSourceFile.OpenText(); //the reader is set ...
}
catch (FileNotFoundException e)
{
MessageBox.Show(e.FileName.ToString() + " cannot be found");
}
catch
{
MessageBox.Show("An error occurred while opening the DXF file");
return;
}
////////////////////////////////////////////////////////////////////
//This part interprets the drawing objects found in the DXF file...
////////////////////////////////////////////////////////////////////
do
{
if (line1 == "0" && line2 == "LINE")
LineModule(reader);
else if (line1 == "0" && line2 == "LWPOLYLINE")
PolylineModule(reader);
else if (line1 == "0" && line2 == "CIRCLE")
CircleModule(reader);
else if (line1 == "0" && line2 == "ARC")
ArcModule(reader);
GetLineCouple (reader, out line1, out line2); //the related method is called
//for iterating through the text file
//and assigning values to line1 and line2...
} while (line2 != "EOF");
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
reader.DiscardBufferedData(); //reader is cleared...
theSourceFile = null;
reader.Close(); //...and closed.
}
让我稍微解释一下 DXF 文件的结构。在 DXF 文件中(可以用记事本打开),数据存储在两行(双行,双重,耦合,无论你怎么称呼它)结构中。第一行包含一种标识符(或标签),第二行包含数据值。因此,为了解释 DXF 文件,我们必须成对地解释行。
根据这种双重结构,我们可以解释 DXF 文件中存在的所有实体。但目前只能识别 LINE
、LWPOLYLINE
、CIRCLE
和 ARC
实体。在不久的将来,我计划添加 BSPLINE
。
我在源代码中提供了大量注释,所以请查看源代码本身以了解模块的说明。
DXF 查看器
查看器部分比读取器包含更多的代码。如上所述,目前我只能绘制有限数量的形状。我希望在不久的将来扩展它。
在开发查看器时,我从 CodeProject 中获得了许多想法和知识。范围从双缓冲技术到制作 GradientBackground
。
一开始,我说查看器是一个 MDI 应用程序。这样,您就可以打开多个 DXF 文件进行查看。打开文件后,如果单击主菜单中的“窗口”按钮,您可以看到打开的窗口列表。
要实现这一点,请向主菜单添加一个菜单项,然后在其属性中找到 MdiList
并将其值更改为“true
”。
我通过重写 OnPaintBackground
事件来创建渐变背景
protected override void OnPaintBackground
(System.Windows.Forms.PaintEventArgs e) //all drawing is made here in OnPaintBackground...
{
base.OnPaintBackground(e); //you must pass "e" to the base method
...
Graphics g = e.Graphics;
Rectangle rect = new Rectangle(this.pictureBox1.Location, this.pictureBox1.Size);
//In fact the pictureBox1 is hidden, the sole purpose of it is
//to get its dimensions for defining the drawing area.
System.Drawing.Drawing2D.LinearGradientBrush brush =
new System.Drawing.Drawing2D.LinearGradientBrush(
rect,
Color.SteelBlue,
Color.Black,
System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal);
if (this.WindowState != FormWindowState.Minimized)
{
e.Graphics.FillRectangle(brush, rect); //gradient background
Draw(g); //All drawing is made here...
}
brush.Dispose();
}
结论
该项目的主要目的是演示如何使用上述技术读取 DXF 文件。事实上,查看器部分在开始时是次要的。后来,我对其给予了一些关注,但我不能声称查看器是由最佳实践组成的。
演示应用程序的压缩文件包含可执行文件和两个示例 DXF 文件。其中一个 DXF 文件是屏幕截图中的那个。绘图看起来是 3D 的,但实际上不是。它是 2D 绘制的...
请随时发送反馈。
历史
- 2005 年 9 月 8 日:添加了主版本
- 2005 年 9 月 8 日:更新了源代码和演示应用程序以解决小数点符号冲突