📄 readme.txt
字号:
//////////////////////////////////////////////////////////////////
// //
// DXF Read/Write/Display //
// ㎎ohn Biddiscombe //
// Rutherford Appleton Laboratory, UK //
// j.biddiscombe@rl.ac.uk //
// DXF code release 3.0 - July 1997 //
// //
//////////////////////////////////////////////////////////////////
Please read all of this if you intend to use the code.
Intro
=====
Release version 3.0 of DXF code. See version history at end of
this document for synopsis of features.
This is not a 'complete' DXF reader package, but it handles most
entities that are commonly found. With this release I've added
the Polygon mesh and Polyface mesh varieties of POLYLINE, so a
great many of the 3D model DXF files found on the internet can now
be loaded and at least viewed in 2D. In addition, I've implemented
the Arbitrary Axis Algorithm and associated 3D transformations
which allows general purpose 3D datasets to be loaded and viewed
in 2D. In addition to both the above points, BLOCKs are now
supported, but the fact that they (and other objects) can be
inserted in arbitrary positions and with 3D rotations added, has
complicated the drawing routines somewhat.
In previous versions I wrote "There is a lot of structure inside
the DXF file that doesn't interest me, so I've simply read the
codes that I need". - This is still true, but the number of codes
that I've not read is considerably smaller, and it's mainly the
STYLE,VIEW and other more bizarre table and header $VALUE entries
that I've left out.
To emphasize this point, here's a quote from the AutoCad specs...
"Writing a program that communicates with AutoCAD by means of the
DXF mechanism appears more difficult than it actually is. The DXF
format makes it easy to ignore information you don't need, while
reading the information you do need."
There is still plenty of room for expansion !
Supported Entities
==================
The entities we can handle with this code are
POINT
LINE
INSERT (with ATTRIB(s) + BLOCK)
ATTDEF (in BLOCKS section)
TEXT
CIRCLE
ARC
POLYLINE (normal 2D & 3D variety)
POLYLINE (Polygon mesh variety)
POLYLINE (Polyface mesh variety)
3DFACE (renamed to FACE3D in the code)
SOLID
+ support for Arbitrary axis alignment of 2D objects in 3-space
Compiling and Running
=====================
You must install the Zoomer.pas unit to the component palette if
you wish to edit the demo form.
Double click to centre the window on the clicked point,
you can then zoom in/out on a specific object if desired.
Drag a rectangle to zoom in on a custom region (the aspect ratio
of 1:1 will be preserved, so the rescaling will use the largest
side of the box).
The buttons at the base of the viewing region are
Zoom out, Zoom in, return to last view, return to original view.
I've included some DXF files downloaded from various sources,
these should give you an idea of the sort of things this code can
read ok.
Why write this code
===================
This code is a subset of a much larger set of routines that I have
written...the reason being...
I work in research, doing Radio Propagation modelling. I'm given
DXF files of terrain, trees, building outlines and heights, which
I need to convert into 3D scenes to test my Raytracing code, which
predicts field strengths and area coverage. I needed to be able to
read DXF files, and manipulate the entities. I convert polylines
and lines representing wall and roof features into a 3D facet
model of buildings etc. and then simulate placing transmitters and
receivers in various places in the database.
The data I'm given isn't supplied as facets because it's cheaper
for the digitizers (who use stereo photos from aircraft flyovers)
to simply draw the building outlines and put a z-coord in. For
this reason, my data is essentially a flat map view, and so I have
not bothered with a 3D view. Once I've processed the data, I have
a 3D viewer I've written in C++ (using OpenGL) that I use to fly
around the model and place transmitters and receivers. I wrote the
renderer as a completely seperate package to the DXF reader, and
so I wanted to keep the DXF stuff simple.
I've added BLOCKs primarily because the newest data I've been
supplied with, uses BLOCKs to represent Trees and some other
simple features. Creating the datasets is much easier when
BLOCKs are used rather than drawing every object again and again.
Disclaimer
==========
I accept no responsibility for anything to do with this code. It
may have bugs and errors, and it's up to you to find them. If you
need to know about DXF files, try a Web/Archie search for
r13dxf.zip, which contains the specs for the latest(?) DXF format.
I've tried to add exception handling wherever it seems appropriate
without making the code too unreadable, but there are a few places
that an error could cause problems, however I think it's pretty
stable and shouldn't be a cause for concern. I've read loads of
DXF files with this code, and it handles most fairly well, but
please keep sending me examples and comments if you find a bug.
Thanks
======
Thanks to John F. Herbster for the original basic DXF reader class
that got me started, and thanks also to Ian L. Kaplan who has
written some C++ DXF code that I found, I used a few of his
groupcode definitions to make my code more readable.
Thanks to Dani Andres Izquierdo, for improving my Zoom_box and
adding the drag rectangle and previous view. Also for improving
the scrollbar action, though I must confess it behaves a little
strangely sometimes (I'll look into it when I get time).
Plea
====
Please don't ask me for help. I do not have a copy of AutoCad, and
I've only ever played with it to see how things look. All the
knowledge I've gained about DXF files has been from the Internet.
Also, I've added lots of functions and entities to the code which
I don't actually need or use, simply for fun and for the sake
of delving into the DXF format, so there may be many nuances of
DXF files which I simply haven't encountered or had trouble with.
It's not my problem, is all I can really say!
I hope this code helps someone. I'd appreciate an email if you
find this code useful. If you can add extra functionality,
please let me have a copy of anything nice, especially if I can
include it in a further release.
Some notes for people who modify the code
=========================================
Layers
======
I don't know how AutoCAD handles layers, but for my purposes I
need to distinguish between points, lines, polylines etc. So I
have opted for a series of entity lists, where all the entities in
a list are all of the same type. This may not be the most
efficient method of storing data but it simplifies my object
filtering and building reconstruction from corner vertices
greatly.
When the user selects a bunch of entity lists, I use an object
I've loosely called a selection object. It's really just a list
with a few functions to make my life easier. Most of the functions
I need to do the 3D database creation are not included in this
code, so it may give the impression of being a little over
engineered, you may want to strip out some of the extra
complication I've put in.
BLOCKs (+ Arbitrary Axis Transformations + plotting issues)
======
Adding BLOCKs has changed a lot of things. Previously the code
was intended for 2D datasets like my digital map data, but whilst
testing the BLOCK features I found some 3D DXF files that used
BLOCKs, and in the interest of 'doing the job right', I felt I had
to make the code handle the Arbitrary axis stuff, and in turn all
the associated tranformations of planar 2D objects in 3D datasets.
Here's a brief explanation of how I've implemeted it.
A 2D object such as a flat polygon (POLYLINE), would normally be
drawn using World Coordinates System (WCS), but sometimes you
might want to draw a planar object (ie 2D) in a plane that is
different from the x-y axis. Thus AutoCAD allows these objects
to be entered in Object Coordinate System (OCS) coords.
The OCS is defined by a vector (the Z axis) which is specified in
WCS. For a given Z axis, there are an infinite number of possible
x,y axes, so AutoCAD has a simple rule for generating the x,y
axes. Once you've worked out the x,y, axes you can then convert
your entity's coordinates from OCS->WCS. This is fairly
straightforward, but the problem is exacerbated by a model like
the passjet.DXF file.
In passjet.dxf, the rotor blades are drawn as two symmetrical
blade meshes. These are then made into a BLOCK. And the whole
engine is made up from 8 copies of this BLOCK with a 360/8 deg
rotation increment applied to each unit, and a couple of meshes
for the engine body. This whole lump is then made into a bigger
BLOCK called 'engine'. When the plane is drawn, two inserts are
used, one for each engine, and each insert has a different
position, and the engines are rotated to point backwards and to
be symmetrical. What this means is that you can't simply read one
blade object, transform the coordinates once, and store it,
because each instance of the blades will have a completely
different transformation applied, depending upon it's position
and orientation in 3D in the final model.
This is all fair enough once you've got the hang of it, but
it's highly annoying to perform thousands of 3D transformations
on every object, when 90% of the time your data is 2D or 3D but
already in WCS.
What I've done is this...every entity has it's OCS z-axis stored
with it in the DXF file, when it's OCS is the same as the WCS it
can be omitted to save space. If an entity is read and it needs
no transformations, then it has it's transformation matrix set
to a nil pointer, only when it needs one will it be allocated
a matrix. When plotting an object, the global matrix is passed
to the entities draw routine (for 2D views it is always nil, but
to do a 3D view simply add an extra view transformation), the
draw routine makes a simple check to see if it's matrix is nil,
and in 90% of cases it is (for my data sets), so it simply passes
the whatever matrix it received onwards. If it does have a matrix
it checks the one passed to it, and if that is nil, it simply
passes it's own on. If both are non nil, then it multiplies the
two and passes a pointer to the result.
Going back to the engine..we have an insert, which is at position
{x,y,z} with rotation r, and a corresponding matrix. We say plot
insert and pass nil, the insert says, nil passed, so pass mine,
the blades say, matrix passed, but I've got a rotation, so
multiply, and then plot. If the whole engine is sub nested inside
a huge 'plane' BLOCK, then the whole thing works just the same
with an extra matrix passed at the top level, and one extra matrix
multiply applied by the engine insert.
Most objects will simply say, nil passed, pass nil...etc
Two points....All inserts have a matrix. Usually just a
transformation to the required insertion point. This is a little
inefficient, for just a transformation, but keeps the strategy
nice. Some BLOCKs have a matrix, usually the BLOCK has an origin
of {0,0,0}, but occasionally you find an example where (say) an
engine has been made into a BLOCK, but it wasn't drawn at the
origin, so the BLOCK has a needless offset. This simply means
an extra matrix translation per BLOCK, but 99% of BLOCKs do not
have this origin shift, so no problem. (The HEXHEAD BLOCK in
motorcycle.dxf is one that does).
The final plot routine in Zoomer.pas simply checks to see if the
overall matrix is nil, and if so applies a simple 2D
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -