DXF Import .NET: Read and View AutoCAD Format Files
Problem and solution
Software development in industry, building and many other fields requires working with CAD drawings. The most popular CAD formats are AutoCAD DWG and AutoCAD DXF, the latter being "simplified" dwg - a special format to be used by developers. The problem is that DXF and DWG formats are really complicated. They have dozens of objects with hundreds of interaction tricks and thousands of properties. Official DXF Reference from Autodesk has 256 pages though it fails to describe many important facts. Hence the development for CAD drawings is often required but is not easy to implement. This article is to tell you how to write the DXF reader in C#, what problems can arise and of course you can find example in C# source code, which is free for use under MPL license.
DXF Structure
DXF is an open ascii format from Autodesk and you can easily find documentation on it in the web. Here are some words about it. Below is a very simple example, to show the main parts:
0 SECTION 2 ENTITIES 0 LINE 10 39.19953392043317 20 36.4554281665769 30 0.0 11 39.19953392043322 21 736.4554281665768 31 0.0 0 ENDSEC 0 EOF
0 - introduction of extended symbol names, following the "0"
SECTION, ENDSEC - begin / end of section. Sections can include Header, Entities, Objects. In the above code you see only Entities section where the entities are.
LINE - begins LINE entity description. Lines:
10
39.19953392043317
mean X1 double value. The value after 20 is Y1, after 30 - Z1 (0 in 2D drawings). 11, 21 and 31 codes are consequently for X2, Y2, Z2. So here we see the line with coordinates (39.19.., 36, 45.. - 39,19.., 736,45..) - this is vertical line.
So our aim is to read this acsii format. We need to load the file to stream and to take lines - even lines (0, 2, 4..) are CODE, odd lines (1, 3, 5...) are VALUE and repeat this procedure step by step till the end of file "EOF".
// take a pair of lines in DXF file, repeate this till "EOF":
public void Next()
{
FCode = Convert.ToInt32(FStream.ReadLine()); //code
FValue = FStream.ReadLine(); // value
}
// for code=0 we create entities. Entitites here are not only thouse which visible in AutoCAD.
// Entities can be also names of Sections and many other internal DXF objects.
// This method is called for all FCode == 0
public DXFEntity CreateEntity()
{
DXFEntity E;
switch (FValue)
{
case "ENDSEC":
return null; // here we do not create entity
case "ENDBLK":
return null;
case "ENDTAB":
return null;
case "LINE": // for "LINE" value we create DXFLine object
E = new DXFLine();
break;
case "SECTION": // "SECTION" will be object to store other objects like Line
E = new DXFSection();
break;
case "BLOCK": // create block object
E = new DXFBlock();
break;
case "INSERT": // insert is reference to block.
E = new DXFInsert();
break;
case "TABLE":
E = new DXFTable();
break;
case "CIRCLE":
E = new DXFCircle();
break;
case "LAYER":
E = new DXFLayer();
break;
case "TEXT":
E = new DXFText();
break;
case "MTEXT":
E = new DXFMText();
break;
case "ARC":
E = new DXFArc();
break;
case "ELLIPSE":
E = new DXFEllipse();
break;
default: // there are many other objects are possible. For them we create empty Entity
E = new DXFEntity();
break;
}
// each Entity will need referense to the Base object Converter, which stores all Entities.
E.Converter = this;
return E; // return Entity and after it is added to the array of Entities
}
The method to read properties of entities is essentially similar to the one described above but it has one important point: different entities have both identic and different properties. For instance many Entities have "base point" - in DXF, which is described by codes: 10 (x), 20 (y), 30(z):
LINE 10 39.19953392043317 20 36.4554281665769 30 0.0
These codes are the same for LINE, CIRCLE, ELLIPSE, TEXT and for many others. So we can make Object-Oriented structure to read and to store the properties in order to avoid double-coding. We will store Layer and Base Point in entity "DXFVisibleEntity" which will be ancestor for all visible entities. Look at the code to read these properties:
//base class for all visible entities
public class DXFVisibleEntity : DXFEntity
{
//Base point (x, y, z) for all entities
public DXFImport.SFPoint Point1 = new SFPoint();
// virtual function ReadProperty() is overriden in all descendants of Entity to read
//specific properties
public override void ReadProperty()
{
// for the different codes we read values
switch (Converter.FCode)
{
//read Layer
case 8:
layer = Converter.LayerByName(Converter.FValue);
break;
//read Coordinates
case 10: //X
Point1.X = Convert.ToSingle(Converter.FValue, Converter.N);
break;
case 20: //Y
Point1.Y = Convert.ToSingle(Converter.FValue, Converter.N);
break;
//read Color
case 62:
FColor = CADImage.IntToColor(Convert.ToInt32(Converter.FValue, Converter.N));
break;
}
}
}
We use the same approach to read the second coordinate in LINE, radius in Circle and so on.
DXF File and DXF Import .NET Structure
This scheme shows main parts of DXF file and the way they are connected with the C# source code in the project. The dash lines stand for associations between DXF file objects and objects, programmed in C#
CADImage is a class for loading from DXF file and drawing to Graphics. It stores the DXF Entities in field:
public DXFSection FEntities;
In the scheme it is DXFSection.
DXFEntity is base class for all Entities classes. Classes DXFBlocks and DXFSection are not visible. Class DXFVisibleEntity is the ancestor for all visible Entities.
By the way, the scheme above is made in DXF format:) in ABViewer software.
CAD tricks
If you are not familiar with AutoCAD please pay attention to the structure of DXF entities . There is a special entity "Block" which may have many "inserts" in the CAD drawing. Block is just set of entities (including nested blocks) which can be inserted many times.
Note:
Block changes many properties of element when showing it. So if you want to know the color of entity, it is not enough to read "Entity.Color" - it is necessary to see all the Inserts and Blocks, in which this entity can be included. To get the correct color in DXF Import .NET project we made the following function: EntColor(DXFEntity E, DXFInsert Ins).
Please use EntColor() function get the correct Color type even if you do not have Blocks in the file. Pay attention that the most common color is "ByLayer" and in oder to read the correct color we need to read the color from Layer entity. This functionality is also provided in this function.
Below is EntColor function. It has many tricks, for instance checking the layer.name == "0" - in DXF layer "0" is special and elements with color "ByLayer" get the color from Block if they are on "0" layer.
<pre lang="cs">//Use this func to know the color of Entity, DXFInsert is Insert entity or null. public static Color EntColor(DXFEntity E, DXFInsert Ins) { DXFInsert vIns = Ins; DXFEntity Ent = E; Color Result = DXFConst.clNone; if(Ent is DXFVisibleEntity) Result = E.FColor; /*if(Ent is Polyline) Result = ((Polyline)Ent).Pen.Pen.Color;*/ if(E.layer == null) return Result; /* algorithm is rather difficult here. This is the way, how AutoCAD works with the colors, if you try to create entities in AutoCAD, you will see how they use Colors */ if((Result == clByLayer)||(Result == clByBlock)) { if((vIns == null)||((Result == clByLayer)&&(Ent.layer.name != "0"))) { if(Result == clByLayer) { if(Ent.layer.color != clNone) Result = Ent.layer.color; else Result = Color.Black; } } else { while(vIns != null) { Result = vIns.color; if((Result != clByBlock) && !((Result == clByLayer) && (vIns.layer.name == "0"))) { if(Result == clByLayer) Result = vIns.layer.color; break; } if((vIns.owner == null)&&(Result == clByLayer)) Result = vIns.layer.color; vIns = vIns.owner; } } } if((Result == clByLayer)||(Result == clByBlock)) Result = clNone; return Result; }
How to use the software
Main code is in DXFImport.cs. You can just use this file in your project or see to it as an example of reading and visualization of DXF files.
Sample code to use DXFImport.cs is Form1.cs.
How to view entities
In Form1.cs we use the Form1_Paint event:
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
//FCADImage - base class to reference to DXF
if (FCADImage == null)
return;
FCADImage.Draw(e.Graphics); // CADImage.Draw() accepts Graphics to draw to
}
We can use FCADImage.Draw() for drawing to any Graphics - for instance to printer. FCADImage.Draw() function should use a special algorithm, when each entity is drawn with the use of block/insert/layer parameters.
public void Draw(Graphics e)
{
if (FMain == null)
return;
FGraphics = e;
// Iterate begins to over the entities to draw all of them
FEntities.Iterate(new CADEntityProc(DrawEntity), FParams);
}
Pay attention to FEntities.Iterate() func, it allows accessing all entities including their being inside the blocks. This is how it works: There is a class DXFGroup which is an ancestor of Entity and which can store array of Entities. For instance, Block is ancestor of DXFGroup and can store many entities like LINE. For better unification we can use ONE BASE GROUP ENTITY object for all the drawing, this Entity will have array of all entities, each of them can also be the Group - the classic "Tree".
Iterate method finally should call Draw() for each Entity in oder to draw it to the Graphics:
<span style="white-space: pre; " class="Apple-tab-span"> </span>protected static void DrawEntity(DXFEntity Ent)
<span style="white-space: pre; " class="Apple-tab-span"> </span>{
<span style="white-space: pre; " class="Apple-tab-span"> </span>Ent.Draw(FGraphics);
<span style="white-space: pre; " class="Apple-tab-span"> </span>}
Draw() method is overridden in descendants of Entity to draw particular entities. Let us see in details how it is implemented in DXFLine:
// draw line
public override void Draw(System.Drawing.Graphics G)
{
// points P1 (x1, y1) and P2 (x2, y2) of Line
SFPoint P1, P2;
// read color via EntColor to get real color
Color RealColor = DXFConst.EntColor(this, Converter.FParams.Insert);
// Read point 1 -convert global coordinates to the screen coordinates:
P1 = Converter.GetPoint(Point1);
//read point 2
P2 = Converter.GetPoint(Point2);
if (FVisible)
G.DrawLine(new Pen(RealColor, 1), P1.X, P1.Y, P2.X, P2.Y);
}
1. We get the Real Color via DXFConst.EntColor(this, Converter.FParams.Insert); as I described before.
2. Points are converted from Global Coordinates to screen coordinates in function GetPoint(). GetPoint not only converts global-to-screen but also uses Block offsets and block scale inside. Thus it facilitates the development work, eliminating the need to "see" what block is being drawn at the moment - Block changes "FParams.matrix" to draw itself. And all entities coordinates use this "FParams
.matrix".
3. Entity is drawn to the given Graphics G:
So you can draw to printer, to raster image or to other Graphics.
DXF Import .NET Reference:
public class DXFConst
Stores constants and base functions.
public class DXFMatrix
Class to work with coordinates.
public struct FRect
Description of 3D space where the CAD drawing is situated in global coordinates.
public struct CADIterate
Stores all needed parameters for entities when processing "Iterate" function.
public class CADImage
Class to draw CAD drawing.
public class DXFEntity
Base class for all DXF Entities
public class DXFGroup : DXFEntity
Base class for all group entities.
public class DXFTable : DXFGroup
Class to read from DXF "Table" section - here it reads only Layers.
public class DXFVisibleEntity : DXFEntity
Base class for all visible entities (unvisible - are "DXFTable", "DXFLayer", etc.)
public class DXFCustomVertex: DXFVisibleEntity
Special class for 3D point in DXF.
public class DXFText: DXFCustomVertex
Stores and Draws "Text" DXF entity.
the following classes are for particular DXF entities:
public class DXFLine : DXFVisibleEntity public class DXFArc: DXFCircle public class DXFEllipse: DXFArc public class DXFLayer: DXFEntity
public class DXFBlock : DXFGroup
Class to work with DXF Block.
public class DXFInsert : DXFVisibleEntity
Class to work with "Insert" in DXF, for AutoCAD users this is "Block reference". Blocks are not visible, Inserts are visible.
Conclusion
The purpose of the article is to give some advice how to write DXF readers. DXF file structure is not so difficult as its logical presentation. The article looks through the base DXF format problems and shows how to find solution for them. The example source is written in C# and may be helpful for all who need to have access to DXF files.
Other projects on the Code Project
On The Code Project you can already find another DXF reader:
http://www.codeproject.com/KB/cs/dxfreader.aspx
Main advantages of our project as compared to the project above are:
1. Block / Inserts
2. Layers
3. Text
which are not presented in that DXF reader.
History
This is the first open source version of DXF Import .NET.
发表评论
This is a topic which is near to my heart Many thanks! Where are your contact details though?
Im grateful for the article.Really thank you! Fantastic.
This was to protect them from ghosts and demons. Peace,
Whoa! This blog looks exactly like my old one! It as on a entirely different topic but it has pretty much the same layout and design. Excellent choice of colors!
Wow, marvelous blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your web site is fantastic, as well as the content!
I think this is a real great blog article.Really thank you! Fantastic.
You ave made some decent points there. I looked on the internet for more information about the issue and found most people will go along with your views on this website.
I truly appreciate this post. I?аАТаЂаve been looking everywhere for this! Thank goodness I found it on Bing. You ave made my day! Thx again
There as definately a lot to find out about this subject. I like all of the points you made.
Normally I do not read post on blogs, however I would like to say that this write-up very pressured me to check out and do so! Your writing taste has been surprised me. Thank you, quite nice post.
Thank you for your article post. Much obliged.
I'аve learn some just right stuff here. Definitely price bookmarking for revisiting. I wonder how much effort you set to make the sort of great informative website.
Wow! Thank you! I constantly wanted to write on my site something like that. Can I implement a portion of your post to my site?
I really loved what you had to say, and more than that,
Very good article.Thanks Again. Awesome.
That is a good tip especially to those new to the blogosphere. Brief but very precise info Thank you for sharing this one. A must read post!
Your style is so unique compared to other folks I have read stuff from. Thank you for posting when you have the opportunity, Guess I all just bookmark this site.
This is one awesome article post.Really thank you! Really Cool.
Very neat blog post.Really looking forward to read more. Awesome.
Thanks-a-mundo for the blog.Really looking forward to read more. Great.
The leading source for trustworthy and timely health and medical news and information.
Perfectly written subject material, Really enjoyed examining.
Very nice article and right to the point. I am not sure if this is actually the best place to ask but do you people have any ideea where to get some professional writers? Thanks
I value the post.Much thanks again. Great.
You got a very good website, Glad I observed it through yahoo.
Utterly composed articles, Really enjoyed reading through.
Thanks so much for the article.Really looking forward to read more. Much obliged.
Nidenin Sesi Yemek Tarifleri Soan orbas
There is noticeably a bundle to find out about this. I assume you made sure good factors in features also.
produce a good article but what can I say I procrastinate a whole
Very nice post. I just stumbled upon your blog and wished to say that I ave truly enjoyed browsing your blog posts. In any case I will be subscribing to your feed and I hope you write again soon!
You made some good points there. I did a search on the issue and found most individuals will approve with your blog.
very good put up, i actually love this web site, carry on it
you could have an awesome weblog here! would you wish to make some invite posts on my blog?
Well I definitely liked studying it. This tip offered by you is very useful for proper planning.
I really liked your blog post.Really looking forward to read more. Fantastic.
Thanks for sharing, this is a fantastic post.Really thank you! Cool.
Say, you got a nice blog post.Thanks Again. Fantastic.
Thanks for the sen Powered by Discuz
You made some clear points there. I looked on the internet for the issue and found most guys will approve with your website.
I truly appreciate this post. I have been looking everywhere for this! Thank goodness I found it on Google. You have made my day! Thanks again
Thanks again for the blog article.Really looking forward to read more. Really Cool.
No matter if some one searches for his vital thing, thus he/she wishes to be available that in detail, therefore that thing is maintained over here.
Thanks-a-mundo for the blog.Really looking forward to read more. Want more.
to check it out. I am definitely loving the
Im no pro, but I imagine you just crafted the best point. You undoubtedly know what youre talking about, and I can really get behind that. Thanks for being so upfront and so truthful.
Really informative blog article. Fantastic.
Well I definitely liked studying it. This subject provided by you is very constructive for accurate planning.
I truly appreciate this post. I ave been looking all over for this! Thank goodness I found it on Google. You have made my day! Thx again.
Thanks a lot for the post.Really looking forward to read more. Cool.