//////////////////////////////////////////////////////////////////
//                                                              //
//                   DXF Read/Write/Display                     //
//                      John Biddiscombe                       //
//               Rutherford Appleton Laboratory, UK             //
//                    j.biddiscombe@rl.ac.uk                    //
//                     DXF code release 2.1                     //
//                                                              //
//////////////////////////////////////////////////////////////////


This is a much improved set of AutoCAD DXF read/write/display
routines. The earlier version (1.0) (last year) didn't use objects
for the basic entity types. This was done for performance reasons,
but it was messy and difficult to follow. This version is much
better in all respects, and the performance has not been affected
much.

I have read the DXF files in an 'Ad Hoc' manner. 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. There is plenty of room for
expansion, and ideally, each DXF_Entity would have a read method
which would handle all of its own codes. However I simply didn't
need to bother. The entities we can handle with this code are

POINT
LINE
INSERT (with ATTRIB(s))
TEXT
CIRCLE
ARC
POLYLINE
3DFACE (renamed to FACE3D in the code)

You must install the Zoomer.pas unit to the component palette if
you wish to edit the demo form.

The right mouse button centres the window on the clicked point,
you can then zoom in/out on a specific object if desired.

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.

The code reads 3D data with no problems, but the display routines
only show a 2D representation in this release (I may add a 3D view
in a later version).

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 buildings and then
simulate placing transmitters and receivers in various places
in the database.

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.

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 recently found, I used a few of
his groupcode definitions to make my code more readable.

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.

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.

John B
April 1997

Notes
=====
The mouse tracking, does not follow the x,y coords of the mouse,
but instead looks for the nearest vertex in the display list(s).
It then shows this point. The extended info shows the full details
of the entity that the point belongs to. The code does this in two
passes, it asks each entity list for the nearest point (using
squared distance to save time), and then afterwards gets the info
it needs. (ARCs and CIRCLEs use the centre of the object
geometrically speaking). The mouse tracking can take a noticeable
amount of time with very large datasets, so I've used a timer
linked to the mousemove, which should allow regular updates,
without slowing everything down too much.
NB : Ver 2.1 : I've now added a point_in_object(2D) test for
polygons & circles. (I wanted the nearest point test because lots
of my data is lines and points).

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.

The polylines has a closed flag to indicate closed polygons, In my
code I create a PolyClosed_ object to distinguish between them. It
is not a true AutoCAD entity, so it is not included here.

If you add your own entities, care should be taken when naming
them - I've used a virtual method: proper_name - to return the DXF
entity name that should be used when writing data to DXF files. At
the moment it simply capitalizes the class name and strips off the
underscore. (e.g. Polyline_ becomes POLYLINE which is the correct
DXF name)

None of the code in these files does anything very complicated, so
I'm afraid there's very little in the way of comments or notes.
Sorry.

Bugs that I do know about
=========================
When tiny (or zoomed out) ARC's are plotted, The endpoints may be
too close together and not separated by more than one pixel. The
Windows ARC routine fails and draws an ARC that is nearly a
complete cirle, rather than a tiny segment. I don't care, because
there are no ARC's in my datasets.

If you copytoclipboard, the machine may GPF, this appears to be
related to the ARCs problem above, Windows NT is OK, but win95 is
duff. (The problem is also caused by integer overflow when
calculating coordinates)

If you have polylines with a lot (>1023) points you may get
troubles, again NT is fine, and I've set a variable
Maxpointsperpolyline or something like that, that you can adjust
if you do have problems.

Files with lots of ATTRIBs per insert may cause problems, because
I've statically allocated space for 4 (I think), so you might need
to increase this, or use dynamic allocation. (My data files only
ever contain one ATTRIB per insert, so I've never had problems)

If a file with no $EXTMAX, $EXTMIN data is read, the entities are
scanned to find the limits in (x,y & z), but the values may be
incorrect, I think this is due to my calculation of ARC extents
being dodgy. This is also true when writing DXF files. I use my
own format once I've modified the data, so I've not tested it
thoroughly.

The warning messages such as 'Invalid header or no Layer
information' etc. are set to stay on the screen for a second or
so, to give you time to read them, but you may find this annoying,
but I've put the delay in, to ensure you know about it. All the
DXF files I get are OK, but I tested this code on a number of
downloaded mesh files when I added the 3DFACE entity, and many of
them just have an ENTITES section and nothing else, so they often
give the error. (eg skull.dxf)

When loading multiple DXF's, the layers simply get added together,
so file 1 may be titled 'somecrap.dxf' and file 2 may be
'morecrap.dxf', these will both become 'somecrap.dxf', it wouldn't
be hard to separate these files, but I've not implemented it here.
Multiple DXF's with wildly different (x,y) extents, may not load
well together.

I've told the code to raise an exception if an entity with an
unnamed layer is read, however if a file with no layer tables is
loaded, an error is always raised. For this reason, I've added a
flag which allows one layer to be created (when the first entity
is loaded) for these files, this lets them work OK. I've never
encountered a file with dodgy layer info yet, but I thought I'd
mention it.

The DXF file contains a BLOCKS section, which I totally ignore, I
think it contains some stuff like hatching/filling styles, and the
ability to define 'macro like' objects which can be used within
entities. None of my data uses the BLOCKS section, so if anyone
can add this feature I'd like to know what it's all about.

In addition to this, I allow any codes which are not read to be
added to a list so that you can see what's been missed out. Mostly
you can simply ignore this, if you pass a nil pointer instead of a
valid stringlist, then it will not bother storing this extra
information.

Version History
===============

2.1 (Apr 1997)
--------------
Unix LF (as opposed to PC, CR/LF) on EOL supported on read.
Files with no header, no layers, no tables read OK (warning
 displayed).
3DFACE supported.
Multiple DXF files can be loaded, (they will be merged).
Point in polygon (or other closed object) mouse track test added.
Modified read routines to make some simpler.

2.0 (Mar 1997)
--------------
Completely Object Oriented. Much improved read structure. Write
 DXF added.
Better Zoombox and mouse tracking.
ATTRIB, TEXT, CIRCLE, ARC supported.
All source included.

1.0 (Sep 1996)
--------------
Working DXF code, very tatty, not all source included.
POINT, INSERT, POLYLINE, LINE supported


Future work
===========
I've been gradually making the DXF_read.pas code simpler and
simpler, with a bit of luck I can eventually make all the entities
readable with a single routine, at the moment Inserts and
Polylines are handled seperately, but a general purpose routine
would be more elegant and tidier.
(Note that I didn't use a DXF_Entity.Read_from_DXF method, but
I did use a DXF_Entity.Write_to_DXF, this is because originally
the DXF_read code was quite large and I wanted to use DXF_Structs
without using the DXF_Read, but also because it keeps the code
nicely separated. DXF_Entity.Write_to_DXF is fairly simple so it
is left in).

3D view. I've used a parameter which points to a mapping function
for coordinate calculation, so inserting a 3D view would be a
doddle. I have already written a 3D package for my datasets, but
it's in C++, so I am not going to add a 3D view to this code, just
yet.

There are more entites inside DXF files which could be added to
this project. I think I've now got all the main useful ones, and
so far I've not found any DXF files it can't read.

BLOCKS. As mentioned earlier, if anyone would care to let me know
what is in the BLOCKS section - or better still - write some code
to handle them, I'd be most grateful.

