DXF_3_0

所属分类:Pascal/Delphi编程
开发工具:Delphi
文件大小:421KB
下载次数:83
上传日期:2013-03-04 17:35:30
上 传 者cpxwin
说明:  DXF控件,delphi中实现DXF文件的读写!
(DXF Control , Read and Write DXF file in Delphi program.)

文件列表:
DXF_write.PAS (5912, 1997-07-11)
IMAGES.RES (1584, 1997-06-23)
MAIN_FORM.dfm (5008, 1997-07-11)
MAIN_FORM.PAS (15168, 1997-07-11)
MOTORCYC.DXF (346963, 1996-10-17)
PASSJET.DXF (180831, 1989-01-05)
Project1.res (876, 2007-07-28)
SKULL.DXF (207928, 1991-12-20)
THINKBOX.DFM (621, 1997-06-04)
THINKBOX.PAS (3864, 1997-01-09)
Tracking_Form.dfm (1618, 2009-02-18)
Tracking_Form.PAS (2178, 1997-07-11)
ZOOMER.PAS (27168, 1997-07-11)
3D-CRAFT.DXF (826139, 1992-01-11)
50STATES.DXF (180270, 1988-11-13)
DXF_DEMO3.RES (876, 1997-02-26)
DXF_DEMO.DPR (1062, 1997-07-11)
DXF_DEMO.EXE (539136, 2009-02-18)
DXF_DEMO.res (876, 2009-02-14)
DXF_READ.PAS (37068, 1997-07-12)
DXF_Structs.pas (75380, 1997-07-12)
DXF_Utils.PAS (13348, 1997-07-11)

////////////////////////////////////////////////////////////////// // // // 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 ... ...

近期下载者

相关文件


收藏者