dxf30
所属分类:Pascal/Delphi编程
开发工具:Delphi
文件大小:920KB
下载次数:27
上传日期:2012-10-15 15:02:21
上 传 者:
seyed mousavi
说明: a simple DXF viewer for delphi.
文件列表:
dxf30\11.dxf (9006, 2005-01-18)
dxf30\111.dxf (375, 2005-07-28)
dxf30\3D-CRAFT.DXF (826139, 1992-01-11)
dxf30\50STA.bak (13169, 2004-08-08)
dxf30\50STA.dxf (24316, 2004-08-08)
dxf30\50STATES.DXF (180270, 1988-11-13)
dxf30\DxfPkg.cfg (434, 2004-08-31)
dxf30\DxfPkg.dcu (3459, 2005-07-28)
dxf30\DxfPkg.dof (2533, 2004-08-31)
dxf30\DxfPkg.dpk (538, 2004-08-08)
dxf30\DxfPkg.res (1536, 2004-08-08)
dxf30\DXF_DEMO.cfg (430, 2004-02-14)
dxf30\DXF_DEMO.dof (2631, 2004-02-14)
dxf30\DXF_DEMO.dpr (1073, 2005-01-18)
dxf30\DXF_DEMO.EXE (539136, 2006-11-18)
dxf30\DXF_DEMO.RES (876, 2004-02-14)
dxf30\Dxf_demo3.res (876, 1997-02-26)
dxf30\DXF_read.dcu (29269, 2005-10-31)
dxf30\DXF_READ.pas (37079, 2005-01-18)
dxf30\DXF_Structs.dcu (74601, 2005-10-31)
dxf30\DXF_Structs.pas (75391, 2005-01-18)
dxf30\DXF_Utils.dcu (9221, 2006-01-30)
dxf30\DXF_Utils.pas (13348, 2006-01-30)
dxf30\DXF_write.dcu (7602, 2005-10-31)
dxf30\Dxf_write.pas (5923, 2005-01-18)
dxf30\IMAGES.RES (1584, 1997-06-23)
dxf30\Main_form.dcu (17799, 2005-10-31)
dxf30\Main_form.ddp (51, 2005-10-31)
dxf30\Main_form.dfm (5007, 2005-10-31)
dxf30\Main_form.pas (15164, 2005-10-31)
dxf30\MOTORCYC.DXF (346963, 1996-10-17)
dxf30\PASSJET.DXF (180831, 1989-01-05)
dxf30\project1.cfg (430, 2004-02-14)
dxf30\project1.dof (2533, 2004-02-14)
dxf30\project1.exe (408576, 2006-11-18)
dxf30\project1.res (876, 2004-02-14)
dxf30\SKULL.DXF (207928, 1991-12-20)
dxf30\ThinkBox.dcu (6999, 2005-10-31)
dxf30\THINKBOX.DFM (621, 1997-06-04)
... ...
//////////////////////////////////////////////////////////////////
// //
// DXF Read/Write/Display //
// John 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
transformation.
NB : All matrices are created when the entity is created, then
stored for use when necessary. Usually they're just nil.
NB : the function update_transformations(...) in DXF_Utils uses
a temporoary global matrix to store results, we need this to
save allocating space for new matrices every time we multiply two.
(Since I wanted to pass pointers for efficiency, I couldn't make
the update transformations routine return a record structure)
Now all entities overwrite this every time they need to, but
because INSERTs & BLOCKs can be nested many levels deep, we must
use a stack allocated matrix in those draw routines to prevent
us losing a previous one.
Phew! - I'm glad I've finished that explanation.
Another BLOCK comment
=====================
The drawing routines, simply draw all the selected entity lists.
The BLOCKS are just like any other entity, so they get drawn too.
I've added a checkbox to stop them being selected, because it's
annoying when they keep appearing randomly all over the place.
If you want to see them or save them with the file, you must
uncheck the checkbox and select the BLOCK list.
Saving DXF files
================
If you load a file, then save it, you won't get an exact copy.
Any information that isn't read by my code is lost, and in
addition, to make the BLOCK referencing easier, I put all BLOCKs
in layer '0'. (It says they should always be there in the docs,
but I have found a couple of files with BLOCKs in any layer).
Be warned that because all BLOCKs get placed in layer '0', when
you load multiple DXFs, the BLOCKs will be merged, so when you
save data, you may end up with more than you wanted.
YOU MUST SELECT THE BLOCKS LIST WHEN SAVING DATA.
The code treats them specially, but they must still be included
when saving.
Mouse
=====
The mouse tracking, does not exactly 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).
NB : Ver 3.0 : Now that 'true' 3D objects are implemented, the
coordinates of the mouse may not correspond to the coordinates
of the object. This means the mouse tracking fails. This doesn't
bother me, because my data is essentially 2D, if you must
interrogate objects then you'll need to get the tranformed vertex
coordinates and check these.
Also, since BLOCKs are inserted with a single point, one would
need to search the transformed BLOCK coordinates and I've not
implemented this.
Polyline attributes
===================
Inside the Polyline_ entity I have allocated space for some
attributes. These are different from the ATTRIB entity that can
be associated with INSERTs, I've allocated this space because I
need to tag my polylines with flags to indicate wall/roof/tree
types etc. and also material properties. You can safely remove
these extra attribute flags, but they may prove to be useful for
your own purposes.
Naming conventions
==================
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)
The reason that I called my entities line_, polyline_, point_ etc.
is to avoid name conflicts with reserved words and other component
method/member names etc. There is no reason why an alternative
naming convention couldn't be used.
NB : Ver 3.0 : some new variants of Polylines override the
proper_name function for obvious reasons.
Comments
========
I have put very few comments in the code, since most of it is
pretty straightforward, but the 3D BLOCK transformations and
Arbitrary axis algorithm are a little complicated so I've tried
to explain what's going on.
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)
ARCs and CIRCLEs get plotted incorrectly in 3D, this is simply
because the insertion point gets transformed, but I've not
bothered turning them into ellipses when viewed side on. This
is particularly noticable in the 3d-craft.dxf dataset.
If you have polylines with a lot (>1024) 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 16 (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, the major source of this problem is BLOCKs, which can
be inserted at one place, but extend for a distance in any
direction from the insertion point. To correct this, you'd need
to get the transformed coordinates of all visible objects, which
would be fairly simple to do.
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.
In addition to this, the BLOCK tables get merged, and since I've
not added a facility for editing/deleting individual BLOCKs you
should be aware of this. If you had two files with BLOCKs of
the same name, you'd have trouble. It might be worth adding some
checks when loading if you think you'll encounter this problem.
Previously I thought that all DXF files had laye ... ...
近期下载者:
相关文件:
收藏者: